-
Notifications
You must be signed in to change notification settings - Fork 1
300 lines (285 loc) · 10.5 KB
/
Copy pathrelease.yml
File metadata and controls
300 lines (285 loc) · 10.5 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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
name: Release
# Tag-driven release. Push a tag `vX.Y.Z` (or a prerelease `vX.Y.Z-beta.N`) whose
# base version matches `[workspace.package] version` in Cargo.toml. One synced
# version drives crates.io (code2graph), PyPI (code2graph-rs) and npm (code2graph-rs).
on:
push:
tags: ["v*"]
concurrency:
group: release
cancel-in-progress: false
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
jobs:
validate-version:
name: Validate version tag
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
is_prerelease: ${{ steps.version.outputs.is_prerelease }}
steps:
- uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Validate tag against workspace version
id: version
run: |
TAG="${GITHUB_REF_NAME}"
TAG_VERSION="${TAG#v}"
CARGO_VERSION=$(cargo metadata --no-deps --format-version=1 \
| jq -r '.packages[] | select(.name == "code2graph") | .version')
if [[ ! "$TAG_VERSION" =~ ^([0-9]+\.[0-9]+\.[0-9]+)(-[a-zA-Z]+\.[0-9]+)?$ ]]; then
echo "::error::Invalid tag '$TAG'. Expected vX.Y.Z or vX.Y.Z-label.N"
exit 1
fi
TAG_BASE="${BASH_REMATCH[1]}"
CARGO_BASE=$(echo "$CARGO_VERSION" | grep -oP '^\d+\.\d+\.\d+')
if [[ "$TAG_BASE" != "$CARGO_BASE" ]]; then
echo "::error::Tag base '$TAG_BASE' != Cargo.toml version '$CARGO_BASE'"
exit 1
fi
if [[ "$TAG_VERSION" == *-* ]]; then
echo "is_prerelease=true" >> "$GITHUB_OUTPUT"
else
echo "is_prerelease=false" >> "$GITHUB_OUTPUT"
fi
echo "version=$TAG_VERSION" >> "$GITHUB_OUTPUT"
echo "Releasing $TAG_VERSION"
ci:
name: Test
needs: validate-version
uses: ./.github/workflows/test.yml
publish-crates:
name: Publish to crates.io
needs: [validate-version, ci]
runs-on: ubuntu-latest
environment: crates.io
steps:
- uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Stamp version
run: |
VERSION="${{ needs.validate-version.outputs.version }}"
sed -i "0,/^version = \".*\"/s//version = \"$VERSION\"/" Cargo.toml
- name: Publish code2graph
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: |
VERSION="${{ needs.validate-version.outputs.version }}"
if curl -sf -H "User-Agent: code2graph-ci (github.com/nodedb-lab/code2graph)" \
"https://crates.io/api/v1/crates/code2graph/$VERSION" > /dev/null 2>&1; then
echo "code2graph@$VERSION already published — skipping"
else
cargo publish -p code2graph --allow-dirty --no-verify
fi
build-sdist:
name: Build sdist
needs: validate-version
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Stamp version
run: |
VERSION="${{ needs.validate-version.outputs.version }}"
PYPI_VERSION=$(echo "$VERSION" | sed -E 's/-alpha\./a/; s/-beta\./b/; s/-rc\./rc/')
sed -i "0,/^version = \".*\"/s//version = \"$VERSION\"/" Cargo.toml
sed -i "s/^version = .*/version = \"$PYPI_VERSION\"/" bindings/python/pyproject.toml
- name: Build sdist
uses: PyO3/maturin-action@v1
with:
command: sdist
args: --out dist -m bindings/python/Cargo.toml
- uses: actions/upload-artifact@v7
with:
name: wheels-sdist
path: dist
build-wheels:
name: Build wheel (${{ matrix.target }})
needs: validate-version
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
manylinux: auto
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu
manylinux: auto
- os: ubuntu-latest
target: x86_64-unknown-linux-musl
manylinux: musllinux_1_2
# Intel macOS hosted runners (macos-13) are retired; cross-compile the
# x86_64 wheel on an Apple Silicon runner (the target is set above).
- os: macos-latest
target: x86_64-apple-darwin
- os: macos-latest
target: aarch64-apple-darwin
- os: windows-latest
target: x86_64-pc-windows-msvc
steps:
- uses: actions/checkout@v6
- name: Stamp version
shell: bash
run: |
VERSION="${{ needs.validate-version.outputs.version }}"
PYPI_VERSION=$(echo "$VERSION" | sed -E 's/-alpha\./a/; s/-beta\./b/; s/-rc\./rc/')
sed -i.bak "0,/^version = \".*\"/s//version = \"$VERSION\"/" Cargo.toml && rm -f Cargo.toml.bak
sed -i.bak "s/^version = .*/version = \"$PYPI_VERSION\"/" bindings/python/pyproject.toml && rm -f bindings/python/pyproject.toml.bak
- name: Build wheel
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
manylinux: ${{ matrix.manylinux || 'auto' }}
args: --release --out dist -m bindings/python/Cargo.toml
sccache: "true"
# tree-sitter grammars' generated parser.c uses C99 for-loop init and
# some scanners use C11 static_assert; the manylinux cross-GCC defaults
# to C89. Force C11 inside the build container (linux/docker only).
docker-options: ${{ contains(matrix.target, 'linux') && '-e CFLAGS=-std=gnu11' || '' }}
- uses: actions/upload-artifact@v7
with:
name: wheels-${{ matrix.target }}
path: dist
publish-pypi:
name: Publish to PyPI
needs: [validate-version, build-wheels, build-sdist]
runs-on: ubuntu-latest
environment: pypi
permissions:
id-token: write
steps:
- uses: actions/download-artifact@v8
with:
pattern: wheels-*
path: dist
merge-multiple: true
- name: Publish (Trusted Publishing / OIDC)
uses: pypa/gh-action-pypi-publish@release/v1
with:
skip-existing: true
build-node:
name: Build addon (${{ matrix.target }})
needs: validate-version
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-gnu
runner: ubuntu-latest
- target: aarch64-unknown-linux-gnu
runner: ubuntu-latest
napi_cross: true
- target: x86_64-unknown-linux-musl
runner: ubuntu-latest
zig: true
# Intel macOS runners are retired; cross-compile x86_64 on Apple Silicon.
- target: x86_64-apple-darwin
runner: macos-latest
- target: aarch64-apple-darwin
runner: macos-latest
- target: x86_64-pc-windows-msvc
runner: windows-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v5
with:
node-version: "22"
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- uses: Swatinem/rust-cache@v2
with:
prefix-key: node-${{ matrix.target }}
- name: Install zig (musl cross-compile)
if: matrix.zig
run: |
pip install ziglang
cargo install --locked cargo-zigbuild
- name: Install napi cross-toolchain (linux aarch64)
if: matrix.napi_cross
run: npm install -g @napi-rs/cross-toolchain
- name: Install deps
working-directory: bindings/node
run: npm ci
- name: Build addon
working-directory: bindings/node
# tree-sitter grammars need C11 (for-loop init / static_assert); the napi
# aarch64 cross-GCC defaults to C89. Harmless on the modern gnu/clang/zig
# targets; omitted on Windows, whose MSVC rejects -std=gnu11.
env:
CFLAGS: ${{ !contains(matrix.target, 'windows') && '-std=gnu11' || '' }}
run: npx napi build --platform --release --target ${{ matrix.target }} ${{ matrix.zig && '-x' || '' }} ${{ matrix.napi_cross && '--use-napi-cross' || '' }}
- uses: actions/upload-artifact@v7
with:
name: node-${{ matrix.target }}
path: bindings/node/*.node
publish-npm:
name: Publish to npm
needs: [validate-version, build-node, publish-crates]
runs-on: ubuntu-latest
environment: npm
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v5
with:
node-version: "22"
registry-url: "https://registry.npmjs.org"
- name: Install deps
working-directory: bindings/node
run: npm ci
- name: Download addon artifacts
uses: actions/download-artifact@v8
with:
path: bindings/node/artifacts
pattern: node-*
merge-multiple: true
- name: Stamp version
working-directory: bindings/node
run: |
VERSION="${{ needs.validate-version.outputs.version }}"
jq --arg v "$VERSION" '.version = $v' package.json > tmp.json && mv tmp.json package.json
- name: Assemble platform packages
working-directory: bindings/node
run: |
npx napi create-npm-dirs --npm-dir ./npm
npx napi artifacts --output-dir ./artifacts --npm-dir ./npm
npx napi prepublish -t npm --npm-dir ./npm --skip-optional-publish
- name: Publish (idempotent, with provenance)
working-directory: bindings/node
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_CONFIG_PROVENANCE: "true"
run: |
publish_pkg() {
local dir="$1" name ver
name=$(jq -r .name "$dir/package.json")
ver=$(jq -r .version "$dir/package.json")
if npm view "$name@$ver" version >/dev/null 2>&1; then
echo "$name@$ver already published — skipping"
else
npm publish "$dir" --access public
fi
}
for dir in npm/*/; do publish_pkg "$dir"; done
publish_pkg .
github-release:
name: GitHub release
needs: [validate-version, publish-crates, publish-pypi, publish-npm]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: softprops/action-gh-release@v2
with:
generate_release_notes: true
prerelease: ${{ needs.validate-version.outputs.is_prerelease == 'true' }}