Skip to content

Commit 64ff0ee

Browse files
committed
Massive fixes, new display stage, fix edge case for version
1 parent bd639e6 commit 64ff0ee

File tree

9 files changed

+428
-102
lines changed

9 files changed

+428
-102
lines changed

src/redis_release/bht/behaviours.py

Lines changed: 104 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from datetime import datetime
2020
from typing import Any, Dict, List, Optional
2121

22+
from py import log
2223
from py_trees.behaviour import Behaviour
2324
from py_trees.common import Status
2425

@@ -738,22 +739,51 @@ def update(self) -> Status:
738739
return Status.SUCCESS
739740

740741

741-
class DetectHomebrewChannel(ReleaseAction):
742+
class HomewbrewWorkflowInputs(ReleaseAction):
742743
def __init__(
743744
self,
744745
name: str,
746+
workflow: Workflow,
745747
package_meta: HomebrewMeta,
746748
release_meta: ReleaseMeta,
747749
log_prefix: str = "",
748750
) -> None:
751+
self.workflow = workflow
749752
self.package_meta = package_meta
750753
self.release_meta = release_meta
754+
super().__init__(name=f"{name} - homebrew", log_prefix=log_prefix)
755+
756+
def update(self) -> Status:
757+
if self.package_meta.release_type is not None:
758+
self.workflow.inputs["release_type"] = self.package_meta.release_type.value
759+
if self.release_meta.tag is not None:
760+
self.workflow.inputs["release_tag"] = self.release_meta.tag
761+
if self.package_meta.homebrew_channel is not None:
762+
self.workflow.inputs["channel"] = self.package_meta.homebrew_channel.value
763+
return Status.SUCCESS
764+
765+
766+
class DetectHombrewReleaseAndChannel(ReleaseAction):
767+
def __init__(
768+
self,
769+
name: str,
770+
package_meta: HomebrewMeta,
771+
release_meta: ReleaseMeta,
772+
log_prefix: str = "",
773+
) -> None:
774+
self.package_meta = package_meta
775+
self.release_meta = release_meta
776+
self.release_version: Optional[RedisVersion] = None
751777
super().__init__(name=name, log_prefix=log_prefix)
752778

753779
def initialise(self) -> None:
754780
if self.release_meta.tag is None:
755781
self.logger.error("Release tag is not set")
756782
return
783+
if self.release_version is not None:
784+
return
785+
786+
self.feedback_message = ""
757787
try:
758788
self.release_version = RedisVersion.parse(self.release_meta.tag)
759789
except ValueError as e:
@@ -762,24 +792,37 @@ def initialise(self) -> None:
762792

763793
def update(self) -> Status:
764794
if self.release_meta.tag is None:
795+
logger.error("Release tag is not set")
765796
return Status.FAILURE
766797

767-
msg = ""
768-
if self.release_version.is_internal:
769-
msg = "Hombebrew internal release detected"
770-
if self.release_version.is_rc:
771-
self.package_meta.homebrew_channel = HomebrewChannel.RC
772-
msg = "Homebrew channel detected: rc"
773-
elif self.release_version.is_ga:
774-
msg = "Homebrew channel detected: stable"
775-
self.package_meta.homebrew_channel = HomebrewChannel.STABLE
798+
if (
799+
self.package_meta.homebrew_channel is not None
800+
and self.package_meta.release_type is not None
801+
):
802+
pass
776803
else:
777-
msg = "Homebrew channel not detected"
804+
assert self.release_version is not None
805+
if self.release_version.is_internal:
806+
self.package_meta.release_type = ReleaseType.INTERNAL
807+
self.package_meta.homebrew_channel = HomebrewChannel.RC
808+
else:
809+
if self.release_version.is_ga:
810+
self.package_meta.release_type = ReleaseType.PUBLIC
811+
self.package_meta.homebrew_channel = HomebrewChannel.STABLE
812+
elif self.release_version.is_rc:
813+
self.package_meta.release_type = ReleaseType.PUBLIC
814+
self.package_meta.homebrew_channel = HomebrewChannel.RC
815+
else:
816+
self.package_meta.release_type = ReleaseType.INTERNAL
817+
self.package_meta.homebrew_channel = HomebrewChannel.RC
818+
self.feedback_message = f"release_type: {self.package_meta.release_type.value}, homebrew_channel: {self.package_meta.homebrew_channel.value}"
778819

779820
if self.log_once(
780821
"homebrew_channel_detected", self.package_meta.ephemeral.log_once_flags
781822
):
782-
self.logger.info(msg)
823+
self.logger.info(
824+
f"Hombrew release_type: {self.package_meta.release_type}, homebrew_channel: {self.package_meta.homebrew_channel}"
825+
)
783826

784827
return Status.SUCCESS
785828

@@ -810,6 +853,10 @@ def __init__(
810853

811854
def initialise(self) -> None:
812855
"""Initialize by validating inputs and starting download task."""
856+
if self.package_meta.ephemeral.is_version_acceptable is not None:
857+
return
858+
859+
self.feedback_message = ""
813860
# Validate homebrew_channel is set
814861
if self.package_meta.homebrew_channel is None:
815862
self.logger.error("Homebrew channel is not set")
@@ -829,6 +876,10 @@ def initialise(self) -> None:
829876
self.logger.error("Release tag is not set")
830877
return
831878

879+
if self.package_meta.release_type is None:
880+
self.logger.error("Package release type is not set")
881+
return
882+
832883
try:
833884
self.release_version = RedisVersion.parse(self.release_meta.tag)
834885
self.logger.debug(f"Parsed release version: {self.release_version}")
@@ -838,9 +889,9 @@ def initialise(self) -> None:
838889

839890
# Determine which cask file to download based on channel
840891
if self.package_meta.homebrew_channel == HomebrewChannel.STABLE:
841-
cask_file = "Casks/redis.rb"
892+
cask_file = "zCasks/redis.rb"
842893
elif self.package_meta.homebrew_channel == HomebrewChannel.RC:
843-
cask_file = "Casks/redis-rc.rb"
894+
cask_file = "zCasks/redis-rc.rb"
844895
else:
845896
self.logger.error(
846897
f"Unknown homebrew channel: {self.package_meta.homebrew_channel}"
@@ -860,14 +911,10 @@ def initialise(self) -> None:
860911

861912
def update(self) -> Status:
862913
"""Process downloaded cask file and classify version."""
863-
try:
864-
# Validate prerequisites
865-
if self.package_meta.homebrew_channel is None:
866-
return Status.FAILURE
867-
868-
if self.release_version is None:
869-
return Status.FAILURE
914+
if self.package_meta.ephemeral.is_version_acceptable is not None:
915+
return Status.SUCCESS
870916

917+
try:
871918
assert self.task is not None
872919

873920
# Wait for download to complete
@@ -882,8 +929,6 @@ def update(self) -> Status:
882929

883930
# Parse version from cask file
884931
# Look for: version "X.Y.Z"
885-
import re
886-
887932
version_match = re.search(
888933
r'^\s*version\s+"([^"]+)"', cask_content, re.MULTILINE
889934
)
@@ -905,27 +950,35 @@ def update(self) -> Status:
905950
return Status.FAILURE
906951

907952
# Compare versions: cask version >= release version means acceptable
908-
if self.cask_version >= self.release_version: # type: ignore[operator]
953+
assert self.release_version is not None
954+
self.package_meta.remote_version = str(self.cask_version)
955+
log_prepend = ""
956+
prepend_color = "green"
957+
if self.release_version >= self.cask_version:
909958
self.package_meta.ephemeral.is_version_acceptable = True
910-
self.logger.info(
911-
f"[green]Version acceptable:[/green] cask {self.cask_version} >= release {self.release_version}"
959+
self.feedback_message = (
960+
f"release {self.release_version} >= cask {self.cask_version}"
912961
)
962+
log_prepend = "Version acceptable: "
913963
else:
914964
self.package_meta.ephemeral.is_version_acceptable = False
965+
log_prepend = "Version NOT acceptable: "
966+
prepend_color = "yellow"
967+
self.feedback_message = (
968+
f"release {self.release_version} < cask {self.cask_version}"
969+
)
970+
if self.log_once(
971+
"homebrew_version_classified",
972+
self.package_meta.ephemeral.log_once_flags,
973+
):
915974
self.logger.info(
916-
f"[yellow]Version not acceptable:[/yellow] cask {self.cask_version} < release {self.release_version}"
975+
f"[{prepend_color}]{log_prepend}{self.feedback_message}[/]"
917976
)
918-
919977
return Status.SUCCESS
920978

921979
except Exception as e:
922980
return self.log_exception_and_return_failure(e)
923981

924-
def terminate(self, new_status: Status) -> None:
925-
"""Terminate the behavior."""
926-
# TODO: Cancel task if needed
927-
pass
928-
929982

930983
### Conditions ###
931984

@@ -1120,3 +1173,21 @@ def update(self) -> Status:
11201173
if self.package_meta.ephemeral.force_rebuild:
11211174
return Status.SUCCESS
11221175
return Status.FAILURE
1176+
1177+
1178+
class NeedToReleaseHomebrew(LoggingAction):
1179+
def __init__(
1180+
self,
1181+
name: str,
1182+
package_meta: HomebrewMeta,
1183+
release_meta: ReleaseMeta,
1184+
log_prefix: str = "",
1185+
) -> None:
1186+
self.package_meta = package_meta
1187+
self.release_meta = release_meta
1188+
super().__init__(name=name, log_prefix=log_prefix)
1189+
1190+
def update(self) -> Status:
1191+
if self.package_meta.ephemeral.is_version_acceptable is True:
1192+
return Status.SUCCESS
1193+
return Status.FAILURE

src/redis_release/bht/composites.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
from ..github_client_async import GitHubClientAsync
2323
from .behaviours import (
24+
ClassifyHomebrewVersion,
2425
ExtractArtifactResult,
2526
GetWorkflowArtifactsList,
2627
IdentifyTargetRef,
@@ -32,7 +33,7 @@
3233
from .behaviours import TriggerWorkflow as TriggerWorkflow
3334
from .behaviours import UpdateWorkflowStatusUntilCompletion
3435
from .decorators import ConditionGuard, FlagGuard, StatusFlagGuard
35-
from .state import Package, PackageMeta, ReleaseMeta, Workflow
36+
from .state import HomebrewMeta, Package, PackageMeta, ReleaseMeta, Workflow
3637

3738

3839
class ParallelBarrier(Composite):
@@ -393,3 +394,27 @@ def __init__(
393394
guard_status=Status.FAILURE,
394395
log_prefix=log_prefix,
395396
)
397+
398+
399+
class ClassifyHomebrewVersionGuarded(StatusFlagGuard):
400+
def __init__(
401+
self,
402+
name: str,
403+
package_meta: HomebrewMeta,
404+
release_meta: ReleaseMeta,
405+
github_client: GitHubClientAsync,
406+
log_prefix: str = "",
407+
) -> None:
408+
super().__init__(
409+
None if name == "" else name,
410+
ClassifyHomebrewVersion(
411+
"Classify Homebrew Version",
412+
package_meta,
413+
release_meta,
414+
github_client,
415+
log_prefix=log_prefix,
416+
),
417+
package_meta.ephemeral,
418+
"classify_remote_versions",
419+
log_prefix=log_prefix,
420+
)

src/redis_release/bht/state.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
logger = logging.getLogger(__name__)
2424

25-
SUPPORTED_STATE_VERSION = 2
25+
SUPPORTED_STATE_VERSION = 3
2626

2727

2828
class WorkflowEphemeral(BaseModel):
@@ -155,6 +155,11 @@ class HomebrewMeta(PackageMeta):
155155

156156
serialization_hint: Literal["homebrew"] = "homebrew" # type: ignore[assignment]
157157
homebrew_channel: Optional[HomebrewChannel] = None
158+
# remote_version field is for status display only (e.g. to pair with
159+
# classify_remote_versions flag) actual decision is based on
160+
# ephemeral.is_version_acceptable which is reset on each run to always
161+
# reflect recent remote version
162+
remote_version: Optional[str] = None
158163
ephemeral: HomebrewMetaEphemeral = Field(default_factory=HomebrewMetaEphemeral) # type: ignore[assignment]
159164

160165

@@ -163,6 +168,11 @@ class SnapMeta(PackageMeta):
163168

164169
serialization_hint: Literal["snap"] = "snap" # type: ignore[assignment]
165170
snap_risk_level: Optional[SnapRiskLevel] = None
171+
# remote_version field is for status display only (e.g. to pair with
172+
# classify_remote_versions flag) actual decision is based on
173+
# ephemeral.is_version_acceptable which is reset on each run to always
174+
# reflect recent remote version
175+
remote_version: Optional[str] = None
166176
ephemeral: SnapMetaEphemeral = Field(default_factory=SnapMetaEphemeral) # type: ignore[assignment]
167177

168178

@@ -203,7 +213,7 @@ class ReleaseMeta(BaseModel):
203213
class ReleaseState(BaseModel):
204214
"""Release state adapted for behavior tree usage."""
205215

206-
version: int = 2
216+
version: int = SUPPORTED_STATE_VERSION
207217
meta: ReleaseMeta = Field(default_factory=ReleaseMeta)
208218
packages: Dict[str, Package] = Field(default_factory=dict)
209219

src/redis_release/bht/tree.py

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from py_trees.visitors import SnapshotVisitor
2020
from rich.text import Text
2121

22-
from ..config import Config
22+
from ..config import Config, PackageConfig
2323
from ..github_client_async import GitHubClientAsync
2424
from ..models import PackageType, ReleaseArgs
2525
from ..state_display import print_state_table
@@ -42,7 +42,14 @@
4242
create_workflow_completion_ppa,
4343
create_workflow_success_ppa,
4444
)
45-
from .state import Package, PackageMeta, ReleaseMeta, ReleaseState, Workflow
45+
from .state import (
46+
SUPPORTED_STATE_VERSION,
47+
Package,
48+
PackageMeta,
49+
ReleaseMeta,
50+
ReleaseState,
51+
Workflow,
52+
)
4653
from .tree_factory import get_factory
4754

4855
logger = logging.getLogger(__name__)
@@ -263,16 +270,24 @@ def create_by_name(self, name: str) -> Union[Selector, Sequence, Behaviour]:
263270
available = ", ".join(self.get_names())
264271
raise ValueError(f"Unknown name '{name}'. Available options: {available}")
265272

273+
config = Config(
274+
version=SUPPORTED_STATE_VERSION,
275+
packages={
276+
"inspected": PackageConfig(
277+
repo="test/repo",
278+
package_type=self.package_type,
279+
build_workflow="build.yml",
280+
publish_workflow="publish.yml",
281+
)
282+
},
283+
)
284+
state = ReleaseState.from_config(config)
266285
# Create mock objects for PPA/branch creation
267-
workflow = Workflow(workflow_file="test.yml", inputs={})
268-
package_meta = PackageMeta(repo="redis/redis", ref="main")
269-
release_meta = ReleaseMeta(tag=self.release_tag)
286+
workflow = state.packages["inspected"].build
287+
package_meta = state.packages["inspected"].meta
288+
release_meta = state.meta
270289
github_client = GitHubClientAsync(token="dummy")
271-
package = Package(
272-
meta=package_meta,
273-
build=workflow,
274-
publish=Workflow(workflow_file="publish.yml", inputs={}),
275-
)
290+
package = state.packages["inspected"]
276291
log_prefix = "test"
277292

278293
# Create and return the requested branch/PPA

0 commit comments

Comments
 (0)