From d4fc2aa497a03f765e1e2275103c3a2338f6b804 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sat, 4 Jul 2026 06:25:45 +0000 Subject: [PATCH 1/2] Chain promote_rc and release_publish workflows The tagging done by promote_rc doesn't trigger the on-tag trigger of the publish workflow. To fix this, promote_rc now outputs the promoted version, and release_promote_rc.yaml uses it to call release_publish.yaml explicitly. --- .github/workflows/release_promote_rc.yaml | 11 ++++++++ .../tools/private/release/promote_rc_test.py | 27 +++++++++++++++++++ tools/private/release/promote_rc.py | 4 +++ 3 files changed, 42 insertions(+) diff --git a/.github/workflows/release_promote_rc.yaml b/.github/workflows/release_promote_rc.yaml index 6dd02f1a25..399e7b1fa2 100644 --- a/.github/workflows/release_promote_rc.yaml +++ b/.github/workflows/release_promote_rc.yaml @@ -25,6 +25,8 @@ permissions: jobs: promote: runs-on: ubuntu-latest + outputs: + version: ${{ steps.promote.outputs.version }} steps: - name: Checkout repository uses: actions/checkout@v7 @@ -42,6 +44,7 @@ jobs: git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" - name: Run Promote RC + id: promote env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} VERSION: ${{ inputs.version }} @@ -58,3 +61,11 @@ jobs: ARGS+=("--no-dry-run") bazel run //tools/private/release -- promote-rc "${ARGS[@]}" + + publish: + needs: promote + uses: ./.github/workflows/release_publish.yaml + with: + tag_name: ${{ needs.promote.outputs.version }} + publish_to_pypi: true + secrets: inherit diff --git a/tests/tools/private/release/promote_rc_test.py b/tests/tools/private/release/promote_rc_test.py index 5bfd122c4c..126911ddce 100644 --- a/tests/tools/private/release/promote_rc_test.py +++ b/tests/tools/private/release/promote_rc_test.py @@ -1,5 +1,8 @@ import argparse +import os +import tempfile import unittest +from pathlib import Path from unittest.mock import call, patch from tests.tools.private.release.release_test_helper import _mock_git_and_gh @@ -10,6 +13,8 @@ class CmdPromoteRcTest(unittest.TestCase): def setUp(self): _mock_git_and_gh(self) + self.test_dir = tempfile.TemporaryDirectory() + self.addCleanup(self.test_dir.cleanup) def test_promote_rc_success(self): # Arrange @@ -59,6 +64,28 @@ def test_promote_rc_success(self): ) self.mock_gh.post_issue_comment.assert_called_once_with(123, expected_comment) + def test_promote_rc_writes_github_output(self): + # Arrange + github_output_path = os.path.join(self.test_dir.name, "github_output") + args = argparse.Namespace( + version="2.0.0", issue=123, dry_run=False, remote="my-remote" + ) + self.mock_git.get_remote_tags.return_value = ["2.0.0-rc0", "2.0.0-rc1"] + self.mock_git.get_commit_sha.return_value = "abcdef123456" + self.mock_git.tag_exists.return_value = False + initial_body = "- [ ] Tag Final" + self.mock_gh.get_issue_body.return_value = initial_body + + # Act + with patch.dict("os.environ", {"GITHUB_OUTPUT": github_output_path}): + result = PromoteRc(args, self.mock_git, self.mock_gh).run() + + # Assert + self.assertEqual(result, 0) + self.assertTrue(os.path.exists(github_output_path)) + content = Path(github_output_path).read_text() + self.assertEqual(content, "version=2.0.0\n") + def test_promote_rc_resolve_issue_success(self): # Arrange args = argparse.Namespace( diff --git a/tools/private/release/promote_rc.py b/tools/private/release/promote_rc.py index ed59f0b76e..761b7b81eb 100644 --- a/tools/private/release/promote_rc.py +++ b/tools/private/release/promote_rc.py @@ -157,6 +157,10 @@ def run(self) -> int: self.git.tag(version, commit_sha) self.git.push(args.remote, version) + if github_output := os.environ.get("GITHUB_OUTPUT"): + with open(github_output, "a") as f: + f.write(f"version={version}\n") + print(f"Updating tracking issue #{issue_num} checklist...") self.gh.update_issue_body(issue_num, updated_body) From 59feedf8c6a7af7a63ef1d507eaf5e32dcd88d2e Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sat, 4 Jul 2026 06:29:29 +0000 Subject: [PATCH 2/2] chore(release): specify utf-8 encoding for file operations --- tests/tools/private/release/promote_rc_test.py | 2 +- tools/private/release/promote_rc.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/tools/private/release/promote_rc_test.py b/tests/tools/private/release/promote_rc_test.py index 126911ddce..b5dff3e478 100644 --- a/tests/tools/private/release/promote_rc_test.py +++ b/tests/tools/private/release/promote_rc_test.py @@ -83,7 +83,7 @@ def test_promote_rc_writes_github_output(self): # Assert self.assertEqual(result, 0) self.assertTrue(os.path.exists(github_output_path)) - content = Path(github_output_path).read_text() + content = Path(github_output_path).read_text(encoding="utf-8") self.assertEqual(content, "version=2.0.0\n") def test_promote_rc_resolve_issue_success(self): diff --git a/tools/private/release/promote_rc.py b/tools/private/release/promote_rc.py index 761b7b81eb..34c8107af4 100644 --- a/tools/private/release/promote_rc.py +++ b/tools/private/release/promote_rc.py @@ -158,7 +158,7 @@ def run(self) -> int: self.git.push(args.remote, version) if github_output := os.environ.get("GITHUB_OUTPUT"): - with open(github_output, "a") as f: + with open(github_output, "a", encoding="utf-8") as f: f.write(f"version={version}\n") print(f"Updating tracking issue #{issue_num} checklist...")