Skip to content

Commit c069041

Browse files
feat: notify Homebrew and Nix from the sealed release manifest (#821)
Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com>
1 parent 0406fda commit c069041

7 files changed

Lines changed: 424 additions & 84 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ jobs:
149149
- name: The tools of the CI stages pass their fixtures
150150
run: |
151151
python3 tests/scripts/test_classify_changes.py
152+
python3 tests/scripts/test_notify_packages.py
152153
python3 tests/scripts/test_check_e2e_coverage.py
153154
python3 tests/scripts/test_check_default_toolchain_docs.py
154155
python3 tests/scripts/test_check_provider_boundary.py

‎.github/workflows/homebrew-publish.yml‎

Lines changed: 0 additions & 83 deletions
This file was deleted.
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
name: publish-packages
2+
3+
# Notify repositories that own their package definitions. PyPI and AUR retain
4+
# their own publishing workflows, credentials and verification contracts.
5+
# Each target accepts mcpp-release and has a scheduled catch-up as a fallback.
6+
# HOMEBREW_TAP_TOKEN and NIX_PUBLISH_TOKEN are optional fine-grained PATs with
7+
# Contents: write on homebrew-mcpp and nix-mcpp respectively. Missing tokens
8+
# are reported as skipped; accepted dispatches are not publication success.
9+
on:
10+
workflow_run:
11+
workflows: [release]
12+
types: [completed]
13+
workflow_dispatch:
14+
inputs:
15+
tag:
16+
description: 'Exact complete stable release tag, e.g. v2026.10.17.1'
17+
type: string
18+
required: true
19+
channel:
20+
description: 'Repository to notify'
21+
type: choice
22+
options: [all, homebrew, nix]
23+
default: all
24+
25+
permissions:
26+
contents: read
27+
28+
concurrency:
29+
group: publish-packages
30+
cancel-in-progress: false
31+
32+
jobs:
33+
resolve:
34+
name: resolve the sealed release
35+
if: >-
36+
github.event_name == 'workflow_dispatch' ||
37+
github.event.workflow_run.conclusion == 'success'
38+
runs-on: ubuntu-24.04
39+
timeout-minutes: 5
40+
permissions:
41+
contents: read
42+
actions: read
43+
outputs:
44+
tag: ${{ steps.identity.outputs.tag }}
45+
version: ${{ steps.identity.outputs.version }}
46+
commit: ${{ steps.identity.outputs.commit }}
47+
matrix: ${{ steps.identity.outputs.matrix }}
48+
steps:
49+
# Execute trusted notification code, never code from a downloaded artifact.
50+
- uses: actions/checkout@v4
51+
with:
52+
ref: ${{ github.event.repository.default_branch }}
53+
persist-credentials: false
54+
55+
- name: Read the manifest sealed by the completed release run
56+
if: github.event_name == 'workflow_run'
57+
uses: actions/download-artifact@v4
58+
with:
59+
name: mcpp-release-manifest
60+
path: release-identity
61+
run-id: ${{ github.event.workflow_run.id }}
62+
github-token: ${{ github.token }}
63+
64+
- name: Download the manually selected release manifest
65+
if: github.event_name == 'workflow_dispatch'
66+
env:
67+
GH_TOKEN: ${{ github.token }}
68+
TAG: ${{ inputs.tag }}
69+
run: |
70+
set -euo pipefail
71+
[[ "$TAG" =~ ^v[0-9]+(\.[0-9]+)+$ ]] || { echo 'Expected a stable release tag'; exit 1; }
72+
mkdir -p release-identity
73+
gh release download "$TAG" --repo "$GITHUB_REPOSITORY" \
74+
-p mcpp-release.json -O release-identity/mcpp-release.json
75+
76+
- name: Validate the manifest and select notification targets
77+
id: identity
78+
env:
79+
REQUESTED_TAG: ${{ inputs.tag }}
80+
CHANNEL: ${{ inputs.channel || 'all' }}
81+
run: |
82+
python3 tools/release/notify_packages.py resolve \
83+
--manifest release-identity/mcpp-release.json \
84+
--expected-tag "$REQUESTED_TAG" --channel "$CHANNEL"
85+
86+
- name: The public manifest matches the sealed release identity
87+
env:
88+
GH_TOKEN: ${{ github.token }}
89+
TAG: ${{ steps.identity.outputs.tag }}
90+
run: |
91+
set -euo pipefail
92+
gh release download "$TAG" --repo "$GITHUB_REPOSITORY" \
93+
-p mcpp-release.json -O public-mcpp-release.json
94+
cmp release-identity/mcpp-release.json public-mcpp-release.json
95+
96+
notify:
97+
name: notify ${{ matrix.channel }}
98+
needs: resolve
99+
runs-on: ubuntu-24.04
100+
timeout-minutes: 5
101+
strategy:
102+
fail-fast: false
103+
matrix: ${{ fromJSON(needs.resolve.outputs.matrix) }}
104+
steps:
105+
- uses: actions/checkout@v4
106+
with:
107+
ref: ${{ github.event.repository.default_branch }}
108+
persist-credentials: false
109+
110+
- name: Send the release notification and report acceptance
111+
env:
112+
GH_TOKEN: ${{ secrets[matrix.token] }}
113+
CHANNEL: ${{ matrix.channel }}
114+
TAG: ${{ needs.resolve.outputs.tag }}
115+
VERSION: ${{ needs.resolve.outputs.version }}
116+
COMMIT: ${{ needs.resolve.outputs.commit }}
117+
run: |
118+
python3 tools/release/notify_packages.py notify \
119+
--channel "$CHANNEL" --tag "$TAG" --version "$VERSION" --commit "$COMMIT"

‎.github/workflows/pypi-publish.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: pypi-publish
22

33
# Publish the `mcpp-bin` wheels to PyPI (`pip install mcpp-bin`).
44
#
5-
# Downstream of `release`, like aur-publish.yml and homebrew-publish.yml: the
5+
# Downstream of `release`, like aur-publish.yml and publish-packages.yml: the
66
# wheels are built from the release's own mcpp-release.json and payloads, so
77
# this runs only once the release workflow has completed.
88
#

‎.github/workflows/release.yml‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,18 @@ jobs:
879879
cmp "$AUDIT_ROOT/final-assets/mcpp-release.json" \
880880
"$AUDIT_ROOT/final-expected.json"
881881
cat "$AUDIT_ROOT/final-assets/mcpp-release.json"
882+
echo "SEALED_RELEASE_MANIFEST=$AUDIT_ROOT/final-assets/mcpp-release.json" >> "$GITHUB_ENV"
883+
884+
# Downstream notifications consume the identity sealed by THIS run,
885+
# including workflow_dispatch rebuilds of a tag other than main's version.
886+
- name: Save the sealed manifest for package notifications
887+
uses: actions/upload-artifact@v4
888+
with:
889+
name: mcpp-release-manifest
890+
path: ${{ env.SEALED_RELEASE_MANIFEST }}
891+
if-no-files-found: error
892+
overwrite: true # A rerun has already proved the public bytes identical.
893+
retention-days: 30
882894

883895
# Publish this release into the xlings ecosystem, after ALL platform builds
884896
# have uploaded their assets and the immutable manifest gate has passed:

0 commit comments

Comments
 (0)