Skip to content

Commit cd519e9

Browse files
committed
New prints and demo behaviours
1 parent 404f4ce commit cd519e9

File tree

5 files changed

+147
-30
lines changed

5 files changed

+147
-30
lines changed

src/redis_release/bht/behaviours.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,15 @@ def update(self) -> Status:
374374
return Status.RUNNING
375375

376376
result = self.task.result()
377+
if self.workflow.status != result.status:
378+
self.logger.info(
379+
f"Workflow {self.workflow.workflow_file}({self.workflow.run_id}) status changed: {self.workflow.status} -> {result.status}"
380+
)
377381
self.workflow.status = result.status
382+
if self.workflow.conclusion != result.conclusion:
383+
self.logger.info(
384+
f"Workflow {self.workflow.workflow_file}({self.workflow.run_id}) conclusion changed: {self.workflow.conclusion} -> {result.conclusion}"
385+
)
378386
self.workflow.conclusion = result.conclusion
379387
self.feedback_message = (
380388
f" {self.workflow.status}, {self.workflow.conclusion}"

src/redis_release/bht/state.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import logging
33
import uuid
44
from datetime import datetime
5-
from importlib.metadata import packages_distributions
65
from pathlib import Path
76
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Protocol, Union
87

src/redis_release/bht/tree.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from py_trees.display import unicode_tree
1212
from py_trees.trees import BehaviourTree
1313
from py_trees.visitors import SnapshotVisitor
14+
from rich.pretty import pretty_repr
1415
from rich.text import Text
1516

1617
from ..config import Config
@@ -374,3 +375,35 @@ def create_extract_result_tree_branch(
374375
)
375376
latch_chains(extract_artifact_result, download_artifacts)
376377
return extract_artifact_result
378+
379+
380+
class DemoBehaviour(Behaviour):
381+
def __init__(self, name: str):
382+
super().__init__(name=name)
383+
384+
def update(self) -> Status:
385+
return Status.SUCCESS
386+
387+
388+
def create_sequence_branch() -> Sequence:
389+
s = Sequence(
390+
name="Sequence: A && B",
391+
memory=False,
392+
children=[
393+
DemoBehaviour("A"),
394+
DemoBehaviour("B"),
395+
],
396+
)
397+
return s
398+
399+
400+
def create_selector_branch() -> Selector:
401+
s = Selector(
402+
name="Selector: A || B",
403+
memory=False,
404+
children=[
405+
DemoBehaviour("A"),
406+
DemoBehaviour("B"),
407+
],
408+
)
409+
return s

src/redis_release/cli.py

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
create_build_workflow_tree_branch,
3737
create_extract_result_tree_branch,
3838
create_publish_workflow_tree_branch,
39+
create_selector_branch,
40+
create_sequence_branch,
3941
create_workflow_complete_tree_branch,
4042
create_workflow_with_result_tree_branch,
4143
initialize_tree_and_state,
@@ -231,7 +233,20 @@ def release_print_bht(
231233
None,
232234
"--name",
233235
"-n",
234-
help="Name of specific PPA or tree branch to print. PPAs: 'workflow_success', 'workflow_completion', 'find_workflow', 'trigger_workflow', 'identify_target_ref', 'download_artifacts', 'extract_artifact_result'. Tree branches: 'workflow_success_branch', 'workflow_result_branch'",
236+
help="""Name of specific PPA or tree branch to print.
237+
PPAs:
238+
'workflow_success',
239+
'workflow_completion',
240+
'find_workflow',
241+
'trigger_workflow',
242+
'identify_target_ref',
243+
'download_artifacts',
244+
'extract_artifact_result'.
245+
Tree branches:
246+
'workflow_complete_branch',
247+
'workflow_with_result_branch',
248+
'publish_workflow_branch',
249+
'build_workflow_branch'""",
235250
),
236251
) -> None:
237252
"""Print and render (using graphviz) the release behaviour tree or a specific PPA."""
@@ -292,12 +307,20 @@ def release_print_bht(
292307
"workflow_with_result_branch": lambda: create_workflow_with_result_tree_branch(
293308
"artifact", workflow, package_meta, release_meta, github_client, ""
294309
),
295-
"publish_worflow_branch": lambda: create_publish_workflow_tree_branch(
296-
workflow, workflow, package_meta, release_meta, github_client, ""
310+
"publish_workflow_branch": lambda: create_publish_workflow_tree_branch(
311+
workflow,
312+
workflow,
313+
package_meta,
314+
release_meta,
315+
workflow,
316+
github_client,
317+
"",
297318
),
298319
"build_workflow_branch": lambda: create_build_workflow_tree_branch(
299-
workflow, package_meta, release_meta, github_client, ""
320+
package, release_meta, package, github_client, ""
300321
),
322+
"demo_sequence": lambda: create_sequence_branch(),
323+
"demo_selector": lambda: create_selector_branch(),
301324
}
302325

303326
if name not in ppa_creators:
@@ -332,7 +355,7 @@ def release_bht(
332355
),
333356
) -> None:
334357
"""Run release using behaviour tree implementation."""
335-
setup_logging(logging.DEBUG)
358+
setup_logging()
336359
config_path = config_file or "config.yaml"
337360
config = load_config(config_path)
338361

src/redis_release/logging_config.py

Lines changed: 78 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,103 @@
11
"""Logging configuration with Rich handler for beautiful colored output."""
22

33
import logging
4+
import os
5+
from typing import Optional
46

57
from rich.logging import RichHandler
68

79

10+
def _get_log_level_from_env() -> Optional[int]:
11+
"""Get log level from environment variables.
12+
13+
Checks for LOG_LEVEL and LOGGING_LEVEL environment variables.
14+
Supports both numeric values (10, 20, 30, 40, 50) and string values
15+
(DEBUG, INFO, WARNING, ERROR, CRITICAL).
16+
17+
Returns:
18+
Log level as integer, or None if not found/invalid
19+
"""
20+
for env_var in ["LOG_LEVEL", "LOGGING_LEVEL"]:
21+
level_str = os.getenv(env_var)
22+
if level_str:
23+
# Try to parse as integer first
24+
try:
25+
return int(level_str)
26+
except ValueError:
27+
pass
28+
29+
# Try to parse as string level name
30+
level_str = level_str.upper()
31+
level_map = {
32+
"DEBUG": logging.DEBUG,
33+
"INFO": logging.INFO,
34+
"WARNING": logging.WARNING,
35+
"WARN": logging.WARNING,
36+
"ERROR": logging.ERROR,
37+
"CRITICAL": logging.CRITICAL,
38+
"FATAL": logging.CRITICAL,
39+
}
40+
if level_str in level_map:
41+
return level_map[level_str]
42+
43+
return None
44+
45+
846
def setup_logging(
9-
level: int = logging.INFO,
47+
level: Optional[int] = None,
1048
show_path: bool = True,
1149
third_party_level: int = logging.WARNING,
50+
log_file: Optional[str] = None,
1251
) -> None:
13-
"""Configure logging with Rich handler.
52+
"""Configure logging with Rich handler for beautiful colored output.
1453
1554
Args:
16-
level: Logging level (e.g., logging.INFO, logging.DEBUG)
55+
level: Logging level (e.g., logging.INFO, logging.DEBUG).
56+
If None, will check LOG_LEVEL or LOGGING_LEVEL environment variables.
57+
Defaults to logging.INFO if no environment variable is set.
1758
show_path: Whether to show file path and line numbers in logs
1859
third_party_level: Logging level for third-party libraries (botocore, boto3, etc.)
60+
log_file: Optional file path to also log to a file
61+
"""
62+
# Determine the actual log level to use
63+
if level is None:
64+
level = _get_log_level_from_env()
65+
if level is None:
66+
level = logging.INFO
1967

20-
Example:
21-
>>> from redis_release.logging_config import setup_logging
22-
>>> import logging
23-
>>> setup_logging(level=logging.DEBUG)
24-
>>> logger = logging.getLogger(__name__)
25-
>>> logger.info("[blue]Hello[/blue] [green]World[/green]")
68+
handler = RichHandler(
69+
rich_tracebacks=True,
70+
show_time=True,
71+
show_level=True,
72+
show_path=show_path,
73+
markup=True,
74+
tracebacks_show_locals=True,
75+
omit_repeated_times=False,
76+
)
77+
78+
handlers = [handler]
79+
80+
# Add file handler if log_file is specified
81+
if log_file:
82+
file_handler = logging.FileHandler(log_file)
83+
file_handler.setLevel(level)
84+
formatter = logging.Formatter(
85+
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
86+
)
87+
file_handler.setFormatter(formatter)
88+
handlers.append(file_handler)
2689

27-
# To see botocore debug logs:
28-
>>> setup_logging(level=logging.DEBUG, third_party_level=logging.DEBUG)
29-
"""
3090
logging.basicConfig(
3191
level=level,
32-
format="[cyan1]%(name)s:[/cyan1] %(message)s",
92+
format="%(name)s: %(message)s",
3393
datefmt="[%X]",
34-
handlers=[
35-
RichHandler(
36-
rich_tracebacks=True,
37-
show_time=True,
38-
show_level=True,
39-
show_path=show_path,
40-
markup=True, # Enable Rich markup in log messages
41-
tracebacks_show_locals=True, # Show local variables in tracebacks
42-
omit_repeated_times=False, # Force timestamp on every line
43-
)
44-
],
94+
handlers=handlers,
95+
force=True,
4596
)
4697

98+
# Set root logger to the desired level
99+
logging.getLogger().setLevel(level)
100+
47101
# Optionally reduce noise from some verbose libraries
48102
logging.getLogger("asyncio").setLevel(third_party_level)
49103
logging.getLogger("aiohttp").setLevel(third_party_level)

0 commit comments

Comments
 (0)