Skip to content

Commit 62d8739

Browse files
ci: add manual crates release workflow (vllm-project#97)
## Summary - add a manual `workflow_dispatch` workflow for crates.io releases - default the button to dry-run mode and require an explicit toggle for real publishing - gate the workflow to `main` and require the actor to have `admin` or `maintain` repo permission - publish in the proven order: `agentic-server-core` first, then `agentic-server` after the crates.io index sees core - follow the vLLM release-ref pattern by creating `releases/vX.Y.Z`, tagging `vX.Y.Z`, and generating GitHub Release notes from the published commit - scope `CARGO_REGISTRY_TOKEN` only to the actual publish steps ## Test Plan - `SKIP=no-commit-to-branch uvx pre-commit run --files .github/workflows/release-crates.yml` - `git diff --check -- .github/workflows/release-crates.yml` --------- Signed-off-by: Francisco Javier Arceo <farceo@redhat.com>
1 parent 543568c commit 62d8739

1 file changed

Lines changed: 196 additions & 0 deletions

File tree

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
name: Release crates
2+
3+
run-name: Release crates (${{ inputs.dry_run && 'dry run' || 'publish' }})
4+
5+
on:
6+
workflow_dispatch:
7+
inputs:
8+
dry_run:
9+
description: "Run packaging and publish checks without uploading crates"
10+
required: true
11+
type: boolean
12+
default: true
13+
14+
concurrency:
15+
group: release-crates
16+
cancel-in-progress: false
17+
18+
permissions:
19+
contents: write
20+
21+
jobs:
22+
release:
23+
name: Release crates.io packages
24+
runs-on: ubuntu-latest
25+
if: github.ref == 'refs/heads/main'
26+
steps:
27+
- name: Verify maintainer permission
28+
env:
29+
GH_TOKEN: ${{ github.token }}
30+
run: |
31+
set -euo pipefail
32+
permission="$(gh api \
33+
"repos/${{ github.repository }}/collaborators/${{ github.actor }}/permission" \
34+
--jq '.permission')"
35+
36+
case "$permission" in
37+
admin|maintain)
38+
echo "${{ github.actor }} has $permission permission"
39+
;;
40+
*)
41+
echo "::error::${{ github.actor }} has $permission permission; crates releases require admin or maintain permission"
42+
exit 1
43+
;;
44+
esac
45+
46+
- name: Checkout code
47+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
48+
49+
- name: Install Rust toolchain
50+
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
51+
with:
52+
toolchain: stable
53+
components: clippy, rustfmt
54+
55+
- name: Cache cargo registry and build
56+
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v4
57+
with:
58+
path: |
59+
~/.cargo/registry
60+
~/.cargo/git
61+
target
62+
key: cargo-release-${{ runner.os }}-${{ hashFiles('Cargo.lock') }}
63+
restore-keys: |
64+
cargo-release-${{ runner.os }}-
65+
cargo-${{ runner.os }}-
66+
67+
- name: Check formatting
68+
run: cargo fmt -- --check
69+
70+
- name: Run clippy
71+
run: cargo clippy --all-targets -- -D warnings
72+
73+
- name: Run tests
74+
run: cargo test
75+
76+
- name: Read release version
77+
id: version
78+
run: |
79+
set -euo pipefail
80+
core_version="$(cargo metadata --format-version 1 --no-deps \
81+
| jq -r '.packages[] | select(.name == "agentic-server-core") | .version')"
82+
server_version="$(cargo metadata --format-version 1 --no-deps \
83+
| jq -r '.packages[] | select(.name == "agentic-server") | .version')"
84+
85+
if [ -z "$core_version" ] || [ "$core_version" = "null" ]; then
86+
echo "::error::agentic-server-core package not found in workspace metadata"
87+
exit 1
88+
fi
89+
90+
if [ "$core_version" != "$server_version" ]; then
91+
echo "::error::agentic-server-core ($core_version) and agentic-server ($server_version) versions differ"
92+
exit 1
93+
fi
94+
95+
echo "version=$core_version" >> "$GITHUB_OUTPUT"
96+
echo "tag=v$core_version" >> "$GITHUB_OUTPUT"
97+
echo "release_branch=releases/v$core_version" >> "$GITHUB_OUTPUT"
98+
echo "Release version: $core_version"
99+
100+
- name: Check release refs
101+
run: |
102+
set -euo pipefail
103+
tag="${{ steps.version.outputs.tag }}"
104+
release_branch="${{ steps.version.outputs.release_branch }}"
105+
106+
if git ls-remote --exit-code --tags origin "refs/tags/$tag" >/dev/null 2>&1; then
107+
echo "::error::Tag $tag already exists"
108+
exit 1
109+
fi
110+
111+
if git ls-remote --exit-code --heads origin "$release_branch" >/dev/null 2>&1; then
112+
echo "::error::Release branch $release_branch already exists"
113+
exit 1
114+
fi
115+
116+
- name: Check published versions
117+
run: |
118+
set -euo pipefail
119+
version="${{ steps.version.outputs.version }}"
120+
121+
if cargo info "agentic-server-core@$version" >/dev/null 2>&1; then
122+
echo "::error::agentic-server-core $version is already published"
123+
exit 1
124+
fi
125+
126+
if cargo info "agentic-server@$version" >/dev/null 2>&1; then
127+
echo "::error::agentic-server $version is already published"
128+
exit 1
129+
fi
130+
131+
- name: Dry-run package publication
132+
if: inputs.dry_run
133+
run: |
134+
set -euo pipefail
135+
cargo publish --dry-run -p agentic-server-core
136+
cargo package -p agentic-server --no-verify
137+
echo "Would create tag ${{ steps.version.outputs.tag }}"
138+
echo "Would create branch ${{ steps.version.outputs.release_branch }}"
139+
echo "Would create GitHub release ${{ steps.version.outputs.tag }} with generated notes"
140+
141+
- name: Publish agentic-server-core
142+
if: ${{ !inputs.dry_run }}
143+
env:
144+
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
145+
run: cargo publish -p agentic-server-core
146+
147+
- name: Wait for agentic-server-core index
148+
if: ${{ !inputs.dry_run }}
149+
run: |
150+
set -euo pipefail
151+
version="${{ steps.version.outputs.version }}"
152+
153+
for attempt in {1..30}; do
154+
if cargo info "agentic-server-core@$version" >/dev/null 2>&1; then
155+
echo "agentic-server-core $version is available in crates.io index"
156+
exit 0
157+
fi
158+
159+
echo "Waiting for crates.io index to expose agentic-server-core $version (attempt $attempt/30)"
160+
sleep 10
161+
done
162+
163+
echo "::error::agentic-server-core $version was not visible in crates.io index in time"
164+
exit 1
165+
166+
- name: Publish agentic-server
167+
if: ${{ !inputs.dry_run }}
168+
env:
169+
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
170+
run: cargo publish -p agentic-server
171+
172+
- name: Create release refs
173+
if: ${{ !inputs.dry_run }}
174+
run: |
175+
set -euo pipefail
176+
tag="${{ steps.version.outputs.tag }}"
177+
release_branch="${{ steps.version.outputs.release_branch }}"
178+
179+
git config user.name "github-actions[bot]"
180+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
181+
182+
git tag -a "$tag" "$GITHUB_SHA" -m "$tag"
183+
git push origin "$tag"
184+
git push origin "$GITHUB_SHA:refs/heads/$release_branch"
185+
186+
- name: Create GitHub release
187+
if: ${{ !inputs.dry_run }}
188+
env:
189+
GH_TOKEN: ${{ github.token }}
190+
run: |
191+
set -euo pipefail
192+
tag="${{ steps.version.outputs.tag }}"
193+
gh release create "$tag" \
194+
--target "$GITHUB_SHA" \
195+
--title "$tag" \
196+
--generate-notes

0 commit comments

Comments
 (0)