Skip to content

Commit bd639e6

Browse files
committed
Make release_type package field instead of release field
1 parent 473b84c commit bd639e6

File tree

8 files changed

+104
-29
lines changed

8 files changed

+104
-29
lines changed

src/redis_release/bht/behaviours.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -731,8 +731,8 @@ def __init__(
731731
super().__init__(name=f"{name} - debian", log_prefix=log_prefix)
732732

733733
def update(self) -> Status:
734-
if self.release_meta.release_type is not None:
735-
self.workflow.inputs["release_type"] = self.release_meta.release_type.value
734+
if self.package_meta.release_type is not None:
735+
self.workflow.inputs["release_type"] = self.package_meta.release_type.value
736736
if self.release_meta.tag is not None:
737737
self.workflow.inputs["release_tag"] = self.release_meta.tag
738738
return Status.SUCCESS
@@ -765,6 +765,8 @@ def update(self) -> Status:
765765
return Status.FAILURE
766766

767767
msg = ""
768+
if self.release_version.is_internal:
769+
msg = "Hombebrew internal release detected"
768770
if self.release_version.is_rc:
769771
self.package_meta.homebrew_channel = HomebrewChannel.RC
770772
msg = "Homebrew channel detected: rc"
@@ -1061,7 +1063,7 @@ def __init__(
10611063
super().__init__(name=name, log_prefix=log_prefix)
10621064

10631065
def update(self) -> Status:
1064-
if self.release_meta.release_type == ReleaseType.INTERNAL:
1066+
if self.package_meta.release_type == ReleaseType.INTERNAL:
10651067
if self.package_meta.publish_internal_release:
10661068
self.logger.debug(
10671069
f"Internal release requires publishing: {self.release_meta.tag}"
@@ -1077,28 +1079,33 @@ def update(self) -> Status:
10771079

10781080
class DetectReleaseType(LoggingAction):
10791081
def __init__(
1080-
self, name: str, release_meta: ReleaseMeta, log_prefix: str = ""
1082+
self,
1083+
name: str,
1084+
package_meta: PackageMeta,
1085+
release_meta: ReleaseMeta,
1086+
log_prefix: str = "",
10811087
) -> None:
10821088
self.release_meta = release_meta
1089+
self.package_meta = package_meta
10831090
super().__init__(name=name, log_prefix=log_prefix)
10841091

10851092
def update(self) -> Status:
1086-
if self.release_meta.release_type is not None:
1093+
if self.package_meta.release_type is not None:
10871094
if self.log_once(
1088-
"release_type_detected", self.release_meta.ephemeral.log_once_flags
1095+
"release_type_detected", self.package_meta.ephemeral.log_once_flags
10891096
):
10901097
self.logger.info(
1091-
f"Detected release type: {self.release_meta.release_type}"
1098+
f"Detected release type: {self.package_meta.release_type}"
10921099
)
10931100
return Status.SUCCESS
10941101
if self.release_meta.tag and re.search(r"-int\d*$", self.release_meta.tag):
1095-
self.release_meta.release_type = ReleaseType.INTERNAL
1102+
self.package_meta.release_type = ReleaseType.INTERNAL
10961103
else:
1097-
self.release_meta.release_type = ReleaseType.PUBLIC
1104+
self.package_meta.release_type = ReleaseType.PUBLIC
10981105
self.log_once(
10991106
"release_type_detected", self.release_meta.ephemeral.log_once_flags
11001107
)
1101-
self.logger.info(f"Detected release type: {self.release_meta.release_type}")
1108+
self.logger.info(f"Detected release type: {self.package_meta.release_type}")
11021109
return Status.SUCCESS
11031110

11041111

src/redis_release/bht/ppas.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,12 +137,15 @@ def create_identify_target_ref_ppa(
137137

138138

139139
def create_detect_release_type_ppa(
140+
package_meta: PackageMeta,
140141
release_meta: ReleaseMeta,
141142
log_prefix: str,
142143
) -> Union[Selector, Sequence]:
143144
return create_PPA(
144145
"Detect Release Type",
145-
DetectReleaseType("Detect Release Type", release_meta, log_prefix=log_prefix),
146+
DetectReleaseType(
147+
"Detect Release Type", package_meta, release_meta, log_prefix=log_prefix
148+
),
146149
)
147150

148151

src/redis_release/bht/state.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ class PackageMeta(BaseModel):
143143

144144
serialization_hint: Literal["generic"] = "generic"
145145
package_type: Optional[PackageType] = None
146+
release_type: Optional[ReleaseType] = None
146147
repo: str = ""
147148
ref: Optional[str] = None
148149
publish_internal_release: bool = False
@@ -195,7 +196,6 @@ class ReleaseMeta(BaseModel):
195196
"""Metadata for the release."""
196197

197198
tag: Optional[str] = None
198-
release_type: Optional[ReleaseType] = None
199199
last_started_at: Optional[datetime] = None
200200
ephemeral: ReleaseMetaEphemeral = Field(default_factory=ReleaseMetaEphemeral)
201201

src/redis_release/bht/tree_factory.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ def create_workflow_complete_tree_branch(
133133
log_prefix,
134134
)
135135
detect_release_type = create_detect_release_type_ppa(
136+
package_meta,
136137
release_meta,
137138
log_prefix,
138139
)

src/redis_release/cli.py

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

33
import asyncio
44
import logging
5-
from typing import List, Optional
5+
from typing import Dict, List, Optional
66

77
import typer
88
from py_trees.display import render_dot_tree, unicode_tree
@@ -30,6 +30,47 @@
3030
logger = logging.getLogger(__name__)
3131

3232

33+
def parse_force_release_type(
34+
force_release_type_list: Optional[List[str]],
35+
) -> Dict[str, ReleaseType]:
36+
"""Parse force_release_type arguments from 'package_name:release_type' format.
37+
38+
Args:
39+
force_release_type_list: List of strings in format 'package_name:release_type'
40+
41+
Returns:
42+
Dictionary mapping package names to ReleaseType
43+
44+
Raises:
45+
typer.BadParameter: If format is invalid or release type is unknown
46+
"""
47+
if not force_release_type_list:
48+
return {}
49+
50+
result = {}
51+
for item in force_release_type_list:
52+
if ":" not in item:
53+
raise typer.BadParameter(
54+
f"Invalid format '{item}'. Expected 'package_name:release_type' (e.g., 'docker:internal')"
55+
)
56+
57+
package_name, release_type_str = item.split(":", 1)
58+
package_name = package_name.strip()
59+
release_type_str = release_type_str.strip().lower()
60+
61+
try:
62+
release_type = ReleaseType(release_type_str)
63+
except ValueError:
64+
valid_types = ", ".join([rt.value for rt in ReleaseType])
65+
raise typer.BadParameter(
66+
f"Invalid release type '{release_type_str}'. Valid types: {valid_types}"
67+
)
68+
69+
result[package_name] = release_type
70+
71+
return result
72+
73+
3374
@app.command()
3475
def release_print(
3576
release_tag: str = typer.Argument(..., help="Release tag (e.g., 8.4-m01-int1)"),
@@ -108,10 +149,10 @@ def release(
108149
tree_cutoff: int = typer.Option(
109150
2000, "--tree-cutoff", "-m", help="Max number of ticks to run the tree for"
110151
),
111-
force_release_type: Optional[ReleaseType] = typer.Option(
152+
force_release_type: Optional[List[str]] = typer.Option(
112153
None,
113154
"--force-release-type",
114-
help="Force release type (public or internal)",
155+
help="Force release type per package in format 'package_name:release_type' (e.g., 'docker:internal' or 'all:public'). Can be specified multiple times.",
115156
),
116157
override_state_name: Optional[str] = typer.Option(
117158
None,
@@ -139,7 +180,7 @@ def release(
139180
release_tag=release_tag,
140181
force_rebuild=force_rebuild or [],
141182
only_packages=only_packages or [],
142-
force_release_type=force_release_type,
183+
force_release_type=parse_force_release_type(force_release_type),
143184
override_state_name=override_state_name,
144185
slack_token=slack_token,
145186
slack_channel_id=slack_channel_id,

src/redis_release/models.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import functools
44
import re
55
from enum import Enum
6-
from typing import List, Optional
6+
from typing import Dict, List, Optional
77

88
from pydantic import BaseModel, Field
99

@@ -235,7 +235,7 @@ class ReleaseArgs(BaseModel):
235235
release_tag: str
236236
force_rebuild: List[str] = Field(default_factory=list)
237237
only_packages: List[str] = Field(default_factory=list)
238-
force_release_type: Optional[ReleaseType] = None
238+
force_release_type: Dict[str, ReleaseType] = Field(default_factory=dict)
239239
override_state_name: Optional[str] = None
240240
slack_token: Optional[str] = None
241241
slack_channel_id: Optional[str] = None

src/redis_release/state_manager.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,6 @@ def __init__(
5050
self.aws_secret_access_key = os.getenv("AWS_SECRET_ACCESS_KEY")
5151
self.aws_session_token = os.getenv("AWS_SESSION_TOKEN")
5252

53-
# local state cache for dry run mode
54-
self._local_state_cache = {}
55-
5653
@property
5754
def s3_client(self) -> Optional[boto3.client]:
5855
"""Lazy initialization of S3 client."""
@@ -245,7 +242,31 @@ def apply_args(self, state: ReleaseState) -> None:
245242

246243
if self.args.force_release_type:
247244
logger.info(f"Force release type: {self.args.force_release_type}")
248-
state.meta.release_type = self.args.force_release_type
245+
# Handle "all" keyword to apply to all packages
246+
if "all" in self.args.force_release_type:
247+
release_type = self.args.force_release_type["all"]
248+
for package_name in state.packages:
249+
state.packages[package_name].meta.release_type = release_type
250+
logger.info(
251+
f"Set release type for package '{package_name}': {release_type}"
252+
)
253+
else:
254+
# Set release type for specific packages
255+
for (
256+
package_name,
257+
release_type,
258+
) in self.args.force_release_type.items():
259+
if package_name in state.packages:
260+
state.packages[package_name].meta.release_type = (
261+
release_type
262+
)
263+
logger.info(
264+
f"Set release type for package '{package_name}': {release_type}"
265+
)
266+
else:
267+
logger.warning(
268+
f"Package '{package_name}' not found in state, skipping release type override"
269+
)
249270

250271
def load(self) -> Optional[ReleaseState]:
251272
"""Load state from storage backend."""

src/redis_release/state_slack.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,19 +83,19 @@ def __init__(
8383
reply_broadcast: If True and thread_ts is set, also show in main channel
8484
"""
8585
self.client = WebClient(token=slack_token)
86-
self.channel_id = slack_channel_id
86+
self.channel_id: str = slack_channel_id
8787
self.thread_ts = thread_ts
8888
self.reply_broadcast = reply_broadcast
8989
self.message_ts: Optional[str] = None
9090
self.last_blocks_json: Optional[str] = None
9191
self.started_at = datetime.now(timezone.utc)
9292

93-
def format_package_name(self, package_name: str, state: ReleaseState) -> str:
93+
def format_package_name(self, package_name: str, package: Package) -> str:
9494
"""Format package name with capital letter and release type.
9595
9696
Args:
9797
package_name: The raw package name
98-
state: The ReleaseState to get release type from
98+
package: The Package to get release type from
9999
100100
Returns:
101101
Formatted package name with capital letter and release type in parentheses
@@ -104,8 +104,8 @@ def format_package_name(self, package_name: str, state: ReleaseState) -> str:
104104
formatted = package_name.capitalize()
105105

106106
# Add release type if available
107-
if state.meta.release_type:
108-
release_type_str = state.meta.release_type.value
107+
if package.meta.release_type:
108+
release_type_str = package.meta.release_type.value
109109
formatted = f"{formatted} ({release_type_str})"
110110

111111
return formatted
@@ -149,7 +149,9 @@ def update_message(self, state: ReleaseState) -> bool:
149149
response = self.client.chat_postMessage(**kwargs)
150150
self.message_ts = response["ts"]
151151
# Update channel_id from response (authoritative)
152-
self.channel_id = response["channel"]
152+
channel = response.get("channel")
153+
if isinstance(channel, str):
154+
self.channel_id = channel
153155
logger.info(
154156
f"Posted Slack message ts={self.message_ts}"
155157
+ (f" in thread {self.thread_ts}" if self.thread_ts else "")
@@ -231,7 +233,7 @@ def _make_blocks(self, state: ReleaseState) -> List[Dict[str, Any]]:
231233
# Process each package
232234
for package_name, package in sorted(state.packages.items()):
233235
# Format package name with capital letter and release type
234-
formatted_name = self.format_package_name(package_name, state)
236+
formatted_name = self.format_package_name(package_name, package)
235237

236238
# Get workflow statuses
237239
build_status_emoji = self._get_status_emoji(package, package.build)

0 commit comments

Comments
 (0)