Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 134 additions & 18 deletions .github/scripts/release_verify.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

import argparse
import ast
import dataclasses
import difflib
import pathlib
import re
import subprocess
Expand Down Expand Up @@ -165,6 +167,126 @@ def _link_sdk_core_prs(subject: str) -> str:
)


def _changelog_entries(text: str) -> dict[str, list[list[str]]]:
entries: dict[str, list[list[str]]] = {}
header: str | None = None
entry: list[str] | None = None

for line in text.splitlines():
if line.startswith("### "):
if entry is not None:
entries.setdefault(header or "Other", []).append(entry)
entry = None
header = line.removeprefix("### ").strip()
elif line.startswith(("* ", "- ")):
if entry is not None:
entries.setdefault(header or "Other", []).append(entry)
entry = [line]
elif entry is not None:
if line.strip():
entry.append(line)
else:
entries.setdefault(header or "Other", []).append(entry)
entry = None

if entry is not None:
entries.setdefault(header or "Other", []).append(entry)
return entries


@dataclasses.dataclass
class _ChangelogEntry:
lines: list[str]
introduced_header: str | None = None


def _updated_changelog_entries(
previous_entries: dict[str, list[_ChangelogEntry]],
current_entries: dict[str, list[list[str]]],
) -> dict[str, list[_ChangelogEntry]]:
current = [
(header, entry)
for header, header_entries in current_entries.items()
for entry in header_entries
]
previous = [
entry
for category_entries in previous_entries.values()
for entry in category_entries
]
exact_matches: dict[tuple[str, ...], list[_ChangelogEntry]] = {}
for entry in previous:
exact_matches.setdefault(tuple(entry.lines), []).append(entry)

matches: dict[int, _ChangelogEntry] = {}
matched_previous: set[int] = set()
for current_index, (_, entry) in enumerate(current):
exact = exact_matches.get(tuple(entry))
if exact:
previous_entry = exact.pop(0)
matches[current_index] = previous_entry
matched_previous.add(id(previous_entry))

candidates: list[tuple[float, int, _ChangelogEntry]] = []
for current_index, (_, current_entry) in enumerate(current):
if current_index in matches:
continue
for previous_entry in previous:
if id(previous_entry) in matched_previous:
continue
similarity = difflib.SequenceMatcher(
a="\n".join(previous_entry.lines),
b="\n".join(current_entry),
autojunk=False,
).ratio()
if similarity >= 0.6:
candidates.append((similarity, current_index, previous_entry))
for _, current_index, previous_entry in sorted(
candidates, key=lambda candidate: candidate[0], reverse=True
):
if current_index not in matches and id(previous_entry) not in matched_previous:
matches[current_index] = previous_entry
matched_previous.add(id(previous_entry))

updated: dict[str, list[_ChangelogEntry]] = {}
for current_index, (header, entry) in enumerate(current):
previous_entry = matches.get(current_index)
updated.setdefault(header, []).append(
_ChangelogEntry(
entry,
previous_entry.introduced_header if previous_entry else header,
)
)
return updated


def _sdk_core_changelog_entries(
previous_commit: str,
current_commit: str,
path: pathlib.Path,
) -> list[str]:
output = subprocess.check_output(
[
"cargo",
"run",
"--quiet",
"-p",
"temporalio-sdk-core",
"--bin",
"changelog-release-notes",
"--",
"--from",
previous_commit,
"--to",
current_commit,
],
cwd=path,
encoding="utf-8",
stderr=subprocess.STDOUT,
).strip()
return output.splitlines() if output else []


def _sdk_core_release_notes(version: str, path: str) -> list[str]:
previous_tag = _previous_release_tag(version)
previous_commit = _gitlink(previous_tag, path)
Expand All @@ -178,29 +300,23 @@ def _sdk_core_release_notes(version: str, path: str) -> list[str]:
f"Submodule {path!r} is not initialized; checkout with submodules"
)

log_args = [
"log",
"--format=%H%x00%h%x00%s",
"--reverse",
f"{previous_commit}..{current_commit}",
]
try:
log_output = _git(log_args, cwd=submodule_path)
notes = _sdk_core_changelog_entries(
previous_commit,
current_commit,
submodule_path,
)
except subprocess.CalledProcessError:
_git(["fetch", "--quiet", "origin", "main"], cwd=submodule_path)
log_output = _git(log_args, cwd=submodule_path)
if not log_output:
notes = _sdk_core_changelog_entries(
previous_commit,
current_commit,
submodule_path,
)
if not notes:
return []

lines = ["### SDK Core", ""]
for line in log_output.splitlines():
full_hash, short_hash, subject = line.split("\0", 2)
subject = _link_sdk_core_prs(_clean_commit_subject(subject))
lines.append(
f"- [`{short_hash}`](https://github.com/temporalio/sdk-rust/commit/"
f"{full_hash}) {subject}"
)
return lines
return ["### SDK Core", "", *notes]


def changelog_notes(args: argparse.Namespace) -> None:
Expand Down
444 changes: 222 additions & 222 deletions temporalio/api/workflowservice/v1/request_response_pb2.py

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions temporalio/api/workflowservice/v1/request_response_pb2.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -8965,6 +8965,7 @@ class ResetActivityExecutionRequest(google.protobuf.message.Message):
RESTORE_ORIGINAL_OPTIONS_FIELD_NUMBER: builtins.int
RESOURCE_ID_FIELD_NUMBER: builtins.int
REQUEST_ID_FIELD_NUMBER: builtins.int
RESET_HEARTBEAT_FIELD_NUMBER: builtins.int
namespace: builtins.str
"""Namespace of the workflow which scheduled this activity."""
workflow_id: builtins.str
Expand Down Expand Up @@ -8993,6 +8994,11 @@ class ResetActivityExecutionRequest(google.protobuf.message.Message):
"""Resource ID for routing. Contains "workflow:{workflow_id}" for workflow activities or "activity:{activity_id}" for standalone activities."""
request_id: builtins.str
"""Used to de-dupe reset requests."""
reset_heartbeat: builtins.bool
"""Reset persisted heartbeat details.
Reset always resets the attempt counter. Passing this flag causes reset to additionally
discard any persisted heartbeat details.
"""
def __init__(
self,
*,
Expand All @@ -9006,6 +9012,7 @@ class ResetActivityExecutionRequest(google.protobuf.message.Message):
restore_original_options: builtins.bool = ...,
resource_id: builtins.str = ...,
request_id: builtins.str = ...,
reset_heartbeat: builtins.bool = ...,
) -> None: ...
def HasField(
self, field_name: typing_extensions.Literal["jitter", b"jitter"]
Expand All @@ -9025,6 +9032,8 @@ class ResetActivityExecutionRequest(google.protobuf.message.Message):
b"namespace",
"request_id",
b"request_id",
"reset_heartbeat",
b"reset_heartbeat",
"resource_id",
b"resource_id",
"restore_original_options",
Expand Down
Loading
Loading