-
Notifications
You must be signed in to change notification settings - Fork 0
188 lines (165 loc) · 7.19 KB
/
Copy pathrelease.yml
File metadata and controls
188 lines (165 loc) · 7.19 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
name: Release (binaries + Python wheels)
# Builds the self-contained cants binary for every supported
# platform and publishes:
# 1. the raw binaries as GitHub Release assets (for analysis_backend_path /
# $CODEANALYZER_TS_BIN / download-on-first-use use cases), and
# 2. platform-tagged Python wheels to PyPI as `codeanalyzer-typescript`.
#
# Bun cross-compiles all targets from one host, so a single Linux job suffices.
on:
push:
tags:
- "v*.*.*"
workflow_dispatch: {}
permissions:
contents: write # create GitHub Release + delete tag on failure
id-token: write # PyPI Trusted Publishing (OIDC) -- no API token needed
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
# Derive the release version from the tag (vX.Y.Z -> X.Y.Z) and require it
# to match package.json. This keeps the PyPI wheel version, the GitHub
# Release tag, and the npm version in lockstep -- a mismatch fails fast
# rather than silently publishing the wrong version to PyPI.
- name: Determine and verify version
id: ver
run: |
pkgjson="$(node -p "require('./package.json').version")"
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
version="${GITHUB_REF#refs/tags/v}"
if [[ "$version" != "$pkgjson" ]]; then
echo "::error::Tag version ($version) != package.json version ($pkgjson). Bump package.json or fix the tag."
exit 1
fi
else
version="$pkgjson" # workflow_dispatch: no tag, fall back to package.json
fi
echo "version=$version" >> "$GITHUB_OUTPUT"
echo ">>> Releasing version $version"
- name: Set up Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Install analyzer dependencies
run: bun install
# ----- test gate: a broken build must not produce a release -----
- name: Typecheck and test
id: test
continue-on-error: true
run: |
bun run typecheck
bun test
- name: Delete tag on failure
if: steps.test.conclusion == 'failure' && startsWith(github.ref, 'refs/tags/')
run: |
echo "Tests failed. Deleting tag ${GITHUB_REF#refs/tags/}..."
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git push --delete origin "${GITHUB_REF#refs/tags/}"
exit 1
- name: Fail if tests failed (non-tag runs)
if: steps.test.conclusion == 'failure'
run: exit 1
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install Python build tooling
# hatchling is the build backend; build_wheels.sh runs `python -m build
# --no-isolation`, so it must be present in this env (no auto-install).
run: python -m pip install --upgrade build wheel hatchling
- name: Build platform wheels (cross-compiles every target via Bun)
working-directory: packaging/python
env:
PKG_VERSION: ${{ steps.ver.outputs.version }}
run: ./build_wheels.sh
- name: Extract raw binaries from wheels (for GitHub Release)
working-directory: packaging/python
run: |
mkdir -p ../../release-bins
for whl in dist/*.whl; do
plat="$(basename "$whl" .whl | sed 's/.*-py3-none-//')"
tmp="$(mktemp -d)"
python -m zipfile -e "$whl" "$tmp"
bin="$(find "$tmp/codeanalyzer_typescript/_bin" -type f ! -name '.gitignore')"
ext=""; [[ "$bin" == *.exe ]] && ext=".exe"
cp "$bin" "../../release-bins/cants-${plat}${ext}"
done
ls -lh ../../release-bins
- name: Build changelog (auto-generated from commits/PRs)
id: changelog
if: startsWith(github.ref, 'refs/tags/')
uses: mikepenz/release-changelog-builder-action@v5
with:
failOnError: "false"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Publish GitHub Release (raw binaries)
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
with:
files: release-bins/*
body: ${{ steps.changelog.outputs.changelog }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Publish wheels to PyPI (Trusted Publishing / OIDC)
if: startsWith(github.ref, 'refs/tags/')
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: packaging/python/dist
# Make re-runs idempotent: a version already on PyPI is skipped rather
# than failing the whole job with a 400 (PyPI rejects duplicate uploads).
skip-existing: true
# Hand the raw binaries to the separate `homebrew` job below. Passing them
# as an artifact (rather than re-downloading the GitHub Release) keeps the
# formula checksums byte-identical to what was just published.
- name: Upload release binaries for the homebrew job
if: startsWith(github.ref, 'refs/tags/')
uses: actions/upload-artifact@v4
with:
name: release-bins
path: release-bins/
# ----- Homebrew: regenerate the formula from the just-built binaries and push
# it to the shared tap. Split into its own job (needs: release) so a tap-push
# failure -- e.g. a missing HOMEBREW_TAP_TOKEN -- is isolated from the PyPI and
# GitHub Release steps above, and can be re-run on its own without re-uploading
# wheels. This is the non-Rust equivalent of what cargo-dist does for you.
homebrew:
needs: release
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Derive version from tag
id: ver
run: echo "version=${GITHUB_REF#refs/tags/v}" >> "$GITHUB_OUTPUT"
- name: Download release binaries
uses: actions/download-artifact@v4
with:
name: release-bins
path: release-bins
- name: Generate Homebrew formula
env:
REPO: ${{ github.repository }}
VERSION: ${{ steps.ver.outputs.version }}
run: |
./packaging/homebrew/generate_formula.sh release-bins > codeanalyzer-typescript.rb
cat codeanalyzer-typescript.rb
- name: Push formula to codellm-devkit/homebrew-tap
env:
TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} # PAT with write access to homebrew-tap
VERSION: ${{ steps.ver.outputs.version }}
run: |
git clone "https://x-access-token:${TAP_TOKEN}@github.com/codellm-devkit/homebrew-tap.git" tap
mkdir -p tap/Formula
cp codeanalyzer-typescript.rb tap/Formula/codeanalyzer-typescript.rb
cd tap
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add Formula/codeanalyzer-typescript.rb
git commit -m "codeanalyzer-typescript ${VERSION}" || { echo "no formula change"; exit 0; }
git push