-
Notifications
You must be signed in to change notification settings - Fork 0
177 lines (165 loc) · 6.72 KB
/
Copy path_release.yml
File metadata and controls
177 lines (165 loc) · 6.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# Reusable release implementation. Not dispatchable on its own — called by
# release.yml (production repos) and test-release.yml (the shared test repo),
# which supply `dist_repo` and `record`.
#
# Always: bump each of the agent's plugin manifest versions
# (.<agent>-plugin/plugin.json), build, and `make publish` to <dist_repo>.
# When record=true (production): commit the bump to main when needed, tag
# v<version>-<plugin>, and create a GitHub Release on the monorepo. After the
# distribution is deployed, its repo gets an unsuffixed v<version> tag and
# matching GitHub Release. Test runs (record=false) skip both sets of release
# records so they leave no trace and can be re-run with the same version.
name: _release
on:
workflow_call:
inputs:
version:
required: true
type: string
plugin:
required: true
type: string
dist_repo:
required: true
type: string
record:
description: "Commit+tag+release on the monorepo (production) vs. deploy-only (test)."
required: true
type: boolean
secrets:
PUBLISH_TOKEN:
required: true
OPENAI_API_KEY:
description: "For the post-deploy codex smoke test; skipped if unset."
required: false
permissions:
contents: write
concurrency:
group: release-${{ inputs.plugin }}-${{ inputs.dist_repo }}
cancel-in-progress: false
jobs:
release:
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- name: Checkout monorepo
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
fetch-depth: 0
- name: Validate inputs
id: vars
run: |
set -euo pipefail
version="${{ inputs.version }}"; version="${version#v}"
if ! printf '%s' "$version" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "::error::version '${{ inputs.version }}' is not semver (MAJOR.MINOR.PATCH)."; exit 1
fi
tag="v$version-${{ inputs.plugin }}"
dist_tag="v$version"
# Production releases must come from main. Existing monorepo release
# state is checked against HEAD below so an interrupted release can
# safely resume without moving a tag.
if [ "${{ inputs.record }}" = "true" ]; then
if [ "${{ github.ref }}" != "refs/heads/main" ]; then
echo "::error::Production releases must run on main (got '${{ github.ref }}')."; exit 1
fi
git fetch --tags --quiet
fi
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "tag=$tag" >> "$GITHUB_OUTPUT"
echo "dist_tag=$dist_tag" >> "$GITHUB_OUTPUT"
echo "Releasing $tag -> ${{ inputs.dist_repo }}@$dist_tag (record=${{ inputs.record }})"
- name: Validate distribution release tag
if: ${{ inputs.record }}
env:
GH_TOKEN: ${{ secrets.PUBLISH_TOKEN }}
DIST_REPO: ${{ inputs.dist_repo }}
DIST_TAG: ${{ steps.vars.outputs.dist_tag }}
run: |
set -euo pipefail
if output="$(gh api "repos/$DIST_REPO/git/ref/tags/$DIST_TAG" 2>&1)"; then
echo "::error::tag $DIST_TAG already exists in $DIST_REPO."
exit 1
elif [[ "$output" != *"HTTP 404"* ]]; then
printf '%s\n' "$output" >&2
exit 1
fi
- name: Bump plugin manifest versions
run: python3 scripts/set-plugin-version.py "${{ inputs.plugin }}" "${{ steps.vars.outputs.version }}"
- name: Record monorepo release
if: ${{ inputs.record }}
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add -A
tag="${{ steps.vars.outputs.tag }}"
tag_exists=false
if git rev-parse -q --verify "refs/tags/$tag" >/dev/null; then
tag_exists=true
if ! git diff --cached --quiet; then
echo "::error::tag $tag already exists, but the requested version would change committed manifests."
exit 1
fi
fi
if ! git diff --cached --quiet; then
git commit -m "chore(${{ inputs.plugin }}): release v${{ steps.vars.outputs.version }}"
git push origin HEAD:main
else
echo "Plugin manifests already contain v${{ steps.vars.outputs.version }}; tagging the committed version."
fi
if [ "$tag_exists" = "true" ]; then
tag_sha="$(git rev-list -n 1 "$tag")"
head_sha="$(git rev-parse HEAD)"
if [ "$tag_sha" != "$head_sha" ]; then
plugin_dir="src/plugins/${{ inputs.plugin }}"
if ! git diff --quiet "$tag" HEAD -- "$plugin_dir"; then
echo "::error::tag $tag points to $tag_sha and $plugin_dir has changed at $head_sha."
exit 1
fi
echo "Monorepo tag $tag points to $tag_sha; $plugin_dir is unchanged at $head_sha, so the interrupted release can resume."
else
echo "Monorepo tag $tag already points to the selected release commit; resuming."
fi
else
git tag "$tag"
git push origin "$tag"
fi
if gh release view "$tag" >/dev/null 2>&1; then
echo "Monorepo release $tag already exists; resuming."
else
gh release create "$tag" \
--title "$tag" \
--generate-notes
fi
- name: Deploy to distribution repo
env:
PUBLISH_TARGETS: "${{ inputs.plugin }}:${{ inputs.dist_repo }}"
GH_TOKEN: ${{ secrets.PUBLISH_TOKEN }}
run: make publish
- name: Tag and release distribution repo
if: ${{ inputs.record }}
env:
GH_TOKEN: ${{ secrets.PUBLISH_TOKEN }}
DIST_REPO: ${{ inputs.dist_repo }}
DIST_TAG: ${{ steps.vars.outputs.dist_tag }}
run: |
set -euo pipefail
target_sha="$(gh api "repos/$DIST_REPO/git/ref/heads/main" --jq '.object.sha')"
gh release create "$DIST_TAG" \
--repo "$DIST_REPO" \
--target "$target_sha" \
--title "$DIST_TAG" \
--generate-notes
# Post-deploy end-to-end smoke test (codex only): install the just-deployed
# plugin from the marketplace on Linux + both macOS arches and assert a real
# session traces. It's a verification, not a gate — the deploy already happened.
smoke:
needs: release
if: ${{ inputs.plugin == 'codex' }}
uses: ./.github/workflows/smoke-codex.yml
with:
dist_repo: ${{ inputs.dist_repo }}
secrets: inherit