-
Notifications
You must be signed in to change notification settings - Fork 0
262 lines (229 loc) · 11.5 KB
/
Copy pathrelease.yml
File metadata and controls
262 lines (229 loc) · 11.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
name: Python uv Release
on:
push:
tags:
- "v*.*.*"
permissions:
contents: write # required for GitHub Release
id-token: write # required for PyPI Trusted Publishing
actions: write # required for tag deletion
discussions: write # attach the release-linked repo Discussion (Announcements)
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Set up Python 3.10
uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Install uv
run: |
curl -LsSf https://astral.sh/uv/install.sh | sh
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
- name: Sync dependencies
run: uv sync --all-groups
- name: Install dependencies
run: uv pip install -e ".[neo4j]"
# Keep generated docs in lockstep with the code being released: regenerate the
# README `canpy --help` block and the Neo4j schema.json from source, and commit
# them back to main. Releases are cut from main HEAD, so this fast-forwards;
# best-effort if main moved.
- name: Sync generated docs (README --help + Neo4j schema)
if: startsWith(github.ref, 'refs/tags/')
run: |
uv run python scripts/update_readme.py
uv run canpy --emit schema > schema.neo4j.json
if git diff --quiet README.md schema.neo4j.json; then
echo "Generated docs already current."
else
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add README.md schema.neo4j.json
git commit -m "docs: sync README --help and Neo4j schema for ${GITHUB_REF#refs/tags/}"
git push origin HEAD:main || echo "::warning::could not push doc sync to main (diverged?)"
fi
- name: Run tests
id: test
continue-on-error: true
run: uv run pytest
- name: Delete tag on failure
if: steps.test.conclusion == 'failure'
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: Build package
run: uv build
# Platform-independent, version-locked release assets published alongside the
# wheels/sdist: the Neo4j schema contract (so a consumer can validate
# producer/consumer compatibility without installing the package) and the
# cargo-dist-style install script.
- name: Stage release assets (Neo4j schema + installer script)
run: |
mkdir -p release-assets
uv run canpy --emit schema > release-assets/schema.json
cp packaging/install/canpy-installer.sh release-assets/canpy-installer.sh
ls -lh release-assets
- name: Get version from tag
id: tag_name
run: |
echo "current_version=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
shell: bash
# cargo-dist-style notes: install one-liners + a download table. The categorized
# "What's Changed" (merged PRs/issues grouped under emoji headings via
# .github/release.yml) is appended by generate_release_notes below. Indented code
# blocks avoid backticks in the heredoc.
- name: Compose release notes header (install + download)
env:
VERSION: ${{ steps.tag_name.outputs.current_version }}
run: |
REPO="codellm-devkit/codeanalyzer-python"
BASE="https://github.com/$REPO/releases/download/v$VERSION"
cat > "$RUNNER_TEMP/RELEASE_BODY.md" <<EOF
## Install codeanalyzer-python v$VERSION
Shell script (installs the canpy CLI via uv / pipx / pip):
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/$REPO/releases/latest/download/canpy-installer.sh | sh
PyPI:
pip install codeanalyzer-python==$VERSION
For the optional live Neo4j push (--emit neo4j --neo4j-uri ...):
pip install 'codeanalyzer-python[neo4j]==$VERSION'
## Download
| File | Description |
| --- | --- |
| [codeanalyzer_python-$VERSION-py3-none-any.whl]($BASE/codeanalyzer_python-$VERSION-py3-none-any.whl) | Python wheel |
| [codeanalyzer_python-$VERSION.tar.gz]($BASE/codeanalyzer_python-$VERSION.tar.gz) | Source distribution |
| [canpy-installer.sh]($BASE/canpy-installer.sh) | Shell installer (uv / pipx / pip) |
| [schema.json]($BASE/schema.json) | Neo4j schema contract |
EOF
echo "----- composed header -----"; cat "$RUNNER_TEMP/RELEASE_BODY.md"
- name: Publish release on GitHub
uses: softprops/action-gh-release@v2
with:
files: |
dist/*
release-assets/*
body_path: ${{ runner.temp }}/RELEASE_BODY.md
generate_release_notes: true # appends categorized "What's Changed" (see .github/release.yml)
# Auto-open a repo-level Discussion linked to this release, seeded with
# the same notes. Requires Discussions enabled and this category to exist.
discussion_category_name: Announcements
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Mirror the release announcement into the ORG-level discussions, which are
# backed by codellm-devkit/.github. GITHUB_TOKEN can't write cross-repo, so
# this uses a PAT (ORG_DISCUSSIONS_TOKEN) with repo scope, and posts via the
# createDiscussion GraphQL mutation. Reuses the already-composed RELEASE_BODY.md
# so org and repo posts stay identical.
- name: Announce in org-level discussions (codellm-devkit/.github)
if: startsWith(github.ref, 'refs/tags/')
continue-on-error: true # a failed org post must not fail an otherwise-good release
env:
GH_TOKEN: ${{ secrets.ORG_DISCUSSIONS_TOKEN }}
VERSION: ${{ steps.tag_name.outputs.current_version }}
run: |
set -uo pipefail
OWNER="codellm-devkit"; REPO=".github"; CATEGORY="Announcements"
# The mutation needs GraphQL node IDs, not names — resolve them first.
RESP=$(gh api graphql \
-f query='query($o:String!,$r:String!){repository(owner:$o,name:$r){id discussionCategories(first:25){nodes{id name}}}}' \
-f o="$OWNER" -f r="$REPO") \
|| { echo "::warning::org discussion lookup failed — skipping org announcement."; exit 0; }
REPO_ID=$(echo "$RESP" | jq -r '.data.repository.id')
CAT_ID=$(echo "$RESP" | jq -r --arg c "$CATEGORY" '.data.repository.discussionCategories.nodes[]|select(.name==$c)|.id')
if [[ -z "$REPO_ID" || "$REPO_ID" == "null" || -z "$CAT_ID" ]]; then
echo "::warning::could not resolve $OWNER/$REPO discussion category '$CATEGORY' — skipping org announcement."
exit 0
fi
gh api graphql \
-f query='mutation($rid:ID!,$cid:ID!,$t:String!,$b:String!){createDiscussion(input:{repositoryId:$rid,categoryId:$cid,title:$t,body:$b}){discussion{url}}}' \
-f rid="$REPO_ID" -f cid="$CAT_ID" \
-f t="codeanalyzer-python v$VERSION" \
-f b="$(cat "$RUNNER_TEMP/RELEASE_BODY.md")"
- name: Publish to PyPI via Trusted Publishing
run: uv publish
# Regenerate the Homebrew formula 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.
# 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: Generate Homebrew formula
env:
REPO: ${{ github.repository }}
VERSION: ${{ steps.ver.outputs.version }}
run: |
chmod +x packaging/homebrew/generate_formula.sh
# The release job just published the sdist as a Release asset; hash the
# exact bytes users will download so the formula checksum always matches.
sdist="https://github.com/${REPO}/releases/download/v${VERSION}/codeanalyzer_python-${VERSION}.tar.gz"
SHA256="$(curl -fLsS "$sdist" | shasum -a 256 | cut -d' ' -f1)"
REPO="$REPO" VERSION="$VERSION" SHA256="$SHA256" \
./packaging/homebrew/generate_formula.sh > codeanalyzer-python.rb
cat codeanalyzer-python.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-python.rb tap/Formula/codeanalyzer-python.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-python.rb
git commit -m "codeanalyzer-python ${VERSION}" || { echo "no formula change"; exit 0; }
git push
# Open a tracking issue on the python-sdk (CLDK) consumer so its
# codeanalyzer-python pin and integration can be brought up to this release.
# The issue body is the CHANGELOG section for this version. Split into its own
# job (needs: release) so a failure here -- e.g. a missing SDK_ISSUE_TOKEN --
# is isolated from the PyPI and GitHub Release steps above. Issues are
# repository-scoped (not branch-scoped), so this opens one on python-sdk.
notify-python-sdk:
needs: release
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
# Pull the lines under "## [VERSION]" up to the next "## [" heading.
- name: Extract changelog section for this release
run: |
VERSION="${GITHUB_REF#refs/tags/v}"
{
echo "A new \`codeanalyzer-python\` release (\`v${VERSION}\`) is published."
echo "Update the \`codeanalyzer-python\` pin in this repo and adapt the"
echo "integration to the changes below (see \`PyCodeanalyzer._run_analyzer\`)."
echo
awk -v ver="$VERSION" '
$0 ~ ("^## \\[" ver "\\]") { f = 1; print; next }
f && /^## \[/ { exit }
f { print }
' CHANGELOG.md
} > "$RUNNER_TEMP/sdk_issue.md"
echo "----- issue body -----"; cat "$RUNNER_TEMP/sdk_issue.md"
- name: Create incorporation issue in python-sdk
env:
# CLDK_AUTH_TOKEN is a PAT with repo + discussions scope, reused here for the
# cross-repo issue write. The default GITHUB_TOKEN is scoped to this repo only
# and cannot open issues cross-repo, mirroring HOMEBREW_TAP_TOKEN above.
GH_TOKEN: ${{ secrets.CLDK_AUTH_TOKEN }}
run: |
VERSION="${GITHUB_REF#refs/tags/v}"
gh issue create \
--repo codellm-devkit/python-sdk \
--title "Incorporate codeanalyzer-python v${VERSION}" \
--body-file "$RUNNER_TEMP/sdk_issue.md"