1- name : Publish to PyPI
1+ name : Release Published Pipeline
22
33on :
4- push :
5- tags :
6- - ' v*'
4+ release :
5+ types : [published]
76
87permissions :
9- contents : read
8+ contents : write
109 id-token : write
1110
11+ concurrency :
12+ group : release-published
13+ cancel-in-progress : false
14+
1215jobs :
13- guard :
14- name : Guard (tag points to main?)
16+ prepare :
17+ name : Bump versions and align tag
1518 runs-on : ubuntu-latest
1619 outputs :
17- publish : ${{ steps.check.outputs.publish }}
20+ tag : ${{ steps.ctx.outputs.tag }}
21+ version : ${{ steps.ctx.outputs.version }}
22+ sha : ${{ steps.ctx.outputs.sha }}
1823 steps :
19- - name : Checkout (shallow)
24+ - name : Checkout
2025 uses : actions/checkout@v4
2126 with :
2227 fetch-depth : 0
23- - name : Check if tag commit is on main
24- id : check
25- env :
26- DEFAULT_BRANCH : ${{ github.event.repository.default_branch }}
28+
29+ - name : Read context
30+ id : ctx
31+ shell : bash
32+ run : |
33+ TAG="${{ github.event.release.tag_name }}"
34+ echo "tag=$TAG" >> "$GITHUB_OUTPUT"
35+ if [[ ! "$TAG" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
36+ echo "Tag $TAG is not semver (vX.Y.Z). Exiting." >&2
37+ exit 1
38+ fi
39+ VER="${TAG#v}"
40+ echo "version=$VER" >> "$GITHUB_OUTPUT"
41+ # Resolve current tag SHA (lightweight or annotated)
42+ if git rev-parse -q --verify "refs/tags/$TAG^{commit}" >/dev/null; then
43+ SHA=$(git rev-parse "refs/tags/$TAG^{commit}")
44+ else
45+ echo "Cannot resolve commit for tag $TAG" >&2
46+ exit 1
47+ fi
48+ echo "sha=$SHA" >> "$GITHUB_OUTPUT"
49+ echo "Tag=$TAG Version=$VER TagSHA=$SHA"
50+
51+ - name : Configure bot user
2752 run : |
28- git fetch origin $DEFAULT_BRANCH --depth=1
29- if git merge-base --is-ancestor "$GITHUB_SHA" "origin/$DEFAULT_BRANCH"; then
30- echo "publish=true" >> "$GITHUB_OUTPUT"
31- echo "Tag commit is on $DEFAULT_BRANCH; will publish."
53+ git config user.name "github-actions[bot]"
54+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
55+
56+ - name : Update versions in sources
57+ shell : bash
58+ run : |
59+ set -euo pipefail
60+ VER="${{ steps.ctx.outputs.version }}"
61+ # Update Cargo.toml version
62+ sed -i.bak -E "s/^version = \"[0-9]+\.[0-9]+\.[0-9]+\"/version = \"${VER}\"/" crates/codex_native/Cargo.toml
63+ rm -f crates/codex_native/Cargo.toml.bak
64+ # Update Python __version__
65+ perl -0777 -pe 's/(\n__version__\s*=\s*\")[^"]*(\")/\1'"${VER}"'\2/s' -i codex/__init__.py
66+ echo "Updated versions to ${VER}"
67+
68+ - name : Commit version bump
69+ shell : bash
70+ run : |
71+ VER="${{ steps.ctx.outputs.version }}"
72+ if git diff --quiet; then
73+ echo "No changes to commit (versions already ${VER})."
3274 else
33- echo "publish=false" >> "$GITHUB_OUTPUT"
34- echo "Tag commit is NOT on $DEFAULT_BRANCH; skipping publish."
75+ git add crates/codex_native/Cargo.toml codex/__init__.py
76+ git commit -m "chore(release): v${VER} [skip ci]"
77+ DEFAULT_BRANCH="${{ github.event.repository.default_branch }}"
78+ git push origin HEAD:"${DEFAULT_BRANCH}"
3579 fi
3680
81+ - name : Move tag to version bump commit
82+ shell : bash
83+ run : |
84+ TAG="${{ steps.ctx.outputs.tag }}"
85+ # Point the tag at the latest main commit (which includes the bump)
86+ DEFAULT_BRANCH="${{ github.event.repository.default_branch }}"
87+ git fetch origin "$DEFAULT_BRANCH" --depth=1
88+ NEW_SHA=$(git rev-parse "origin/${DEFAULT_BRANCH}")
89+ git tag -fa "$TAG" "$NEW_SHA" -m "Align $TAG to version bump commit"
90+ git push origin "refs/tags/${TAG}" --force
91+ echo "Aligned tag $TAG -> $NEW_SHA"
92+
3793 build-wheels :
3894 name : Build native wheels
39- needs : guard
40- if : needs.guard.outputs.publish == 'true'
95+ needs : prepare
4196 strategy :
4297 fail-fast : false
4398 matrix :
65120 steps :
66121 - name : Checkout repository
67122 uses : actions/checkout@v4
123+ with :
124+ fetch-depth : 0
68125
69126 - name : Set up Rust
70127 uses : dtolnay/rust-toolchain@stable
@@ -89,16 +146,13 @@ jobs:
89146 if : ${{ matrix.platform == 'linux-x86_64' }}
90147 uses : PyO3/maturin-action@v1
91148 env :
92- # Ensure glibc exposes htobe*/be*toh macros in <endian.h>
93149 CFLAGS : -D_DEFAULT_SOURCE -D_BSD_SOURCE
94150 with :
95151 manylinux : ' 2014'
96152 command : build
97153 before-script-linux : |
98154 yum -y install curl perl-core >/dev/null 2>&1 || true
99155 (perl -MText::Template -e1 >/dev/null 2>&1 || (curl -sL https://cpanmin.us | perl - App::cpanminus Text::Template >/dev/null))
100- # Build via root pyproject so distribution name is 'codex-python'
101- # Use the default container python since we build abi3 once.
102156 args : --release -i python3.12 -o dist
103157
104158 - name : Build Linux aarch64 wheel (manylinux2014)
@@ -113,8 +167,6 @@ jobs:
113167 before-script-linux : |
114168 yum -y install curl perl-core >/dev/null 2>&1 || true
115169 (perl -MText::Template -e1 >/dev/null 2>&1 || (curl -sL https://cpanmin.us | perl - App::cpanminus Text::Template >/dev/null))
116- # Build via root pyproject so distribution name is 'codex-python'
117- # Use the default container python since we build abi3 once.
118170 args : --release -i python3.12 -o dist
119171
120172 - name : Build Linux x86_64 wheel (musllinux_1_2)
@@ -128,8 +180,6 @@ jobs:
128180 command : build
129181 before-script-linux : |
130182 apk add --no-cache curl perl perl-text-template >/dev/null 2>&1 || true
131- # Build via root pyproject so distribution name is 'codex-python'
132- # Use the default container python since we build abi3 once.
133183 args : --release -i python3.12 -o dist
134184
135185 - name : Build Linux aarch64 wheel (musllinux_1_2)
@@ -143,8 +193,6 @@ jobs:
143193 command : build
144194 before-script-linux : |
145195 apk add --no-cache curl perl perl-text-template >/dev/null 2>&1 || true
146- # Build via root pyproject so distribution name is 'codex-python'
147- # Use the default container python since we build abi3 once.
148196 args : --release -i python3.12 -o dist
149197
150198 - name : Build macOS universal2 wheel
@@ -153,16 +201,13 @@ jobs:
153201 python -m pip install --upgrade pip
154202 pip install maturin
155203 rustup target add x86_64-apple-darwin aarch64-apple-darwin
156- # maturin >=1.0 removed --universal2; use --target universal2-apple-darwin
157- # Build via root pyproject so distribution name is 'codex-python'
158204 maturin build --release -i python -o dist --target universal2-apple-darwin
159205
160206 - name : Build Windows wheel
161207 if : ${{ matrix.platform == 'windows-amd64' }}
162208 run : |
163209 python -m pip install --upgrade pip
164210 pip install maturin
165- # Build via root pyproject so distribution name is 'codex-python'
166211 maturin build --release -i python -o dist
167212
168213 - name : Upload wheels
@@ -173,8 +218,7 @@ jobs:
173218
174219 build-sdist :
175220 name : Build sdist
176- needs : guard
177- if : needs.guard.outputs.publish == 'true'
221+ needs : prepare
178222 runs-on : ubuntu-latest
179223 steps :
180224 - name : Checkout repository
@@ -205,15 +249,13 @@ jobs:
205249
206250 publish :
207251 name : Publish to PyPI (Trusted Publishing)
208- needs : [guard, build-wheels, build-sdist]
209- if : needs.guard.outputs.publish == 'true'
252+ needs : [prepare, build-wheels, build-sdist]
210253 runs-on : ubuntu-latest
211254 steps :
212255 - name : Download all artifacts
213256 uses : actions/download-artifact@v4
214257 with :
215258 path : dist
216- # Merge all artifacts directly into dist/ so Twine finds files
217259 merge-multiple : true
218260
219261 - name : Flatten artifacts into dist/
0 commit comments