Skip to content

Commit c89f38e

Browse files
feat(ci): add automatic crates.io publishing workflow (#276)
- Automatically publishes crates to crates.io after successful release - Triggered when Release workflow completes successfully - Can also be manually triggered with optional dry-run mode - Checks which crates need publishing to avoid duplicate publishes - Publishes crates in dependency order: redis-cloud → redis-enterprise → redisctl - Includes verification step to ensure all crates are available on crates.io - Uses CARGO_REGISTRY_TOKEN from repository secrets
1 parent 4711cbf commit c89f38e

File tree

1 file changed

+158
-0
lines changed

1 file changed

+158
-0
lines changed
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
name: Publish to crates.io
2+
3+
on:
4+
workflow_run:
5+
workflows: ["Release"]
6+
types:
7+
- completed
8+
workflow_dispatch:
9+
inputs:
10+
dry-run:
11+
description: 'Dry run (do not actually publish)'
12+
required: false
13+
default: false
14+
type: boolean
15+
16+
jobs:
17+
publish:
18+
name: Publish to crates.io
19+
runs-on: ubuntu-latest
20+
# Only run if the release workflow succeeded or this was manually triggered
21+
if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' }}
22+
23+
steps:
24+
- name: Checkout repository
25+
uses: actions/checkout@v4
26+
with:
27+
# Fetch the tag that triggered the release
28+
fetch-depth: 0
29+
30+
- name: Get version from tag
31+
id: get-version
32+
run: |
33+
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
34+
# For manual runs, use the latest tag
35+
VERSION=$(git describe --tags --abbrev=0 || echo "v0.0.0")
36+
else
37+
# For workflow_run, get the tag from the triggering workflow
38+
VERSION="${{ github.event.workflow_run.head_branch }}"
39+
fi
40+
echo "version=${VERSION#v}" >> $GITHUB_OUTPUT
41+
echo "Publishing version: ${VERSION#v}"
42+
43+
- name: Install Rust
44+
uses: dtolnay/rust-toolchain@stable
45+
46+
- name: Install cargo-workspaces
47+
run: cargo install cargo-workspaces
48+
49+
- name: Check which crates need publishing
50+
id: check-crates
51+
run: |
52+
echo "Checking which crates need to be published..."
53+
54+
# Check each crate to see if it's already published
55+
NEEDS_PUBLISH=""
56+
57+
for crate in redis-cloud redis-enterprise redisctl; do
58+
CRATE_VERSION=$(grep "^version" crates/$crate/Cargo.toml | sed 's/.*= *"\(.*\)"/\1/')
59+
echo "Checking $crate v$CRATE_VERSION..."
60+
61+
# Check if this version is already on crates.io
62+
if cargo search $crate --limit 1 | grep -q "^$crate = \"$CRATE_VERSION\""; then
63+
echo " ✓ $crate v$CRATE_VERSION is already published"
64+
else
65+
echo " → $crate v$CRATE_VERSION needs publishing"
66+
NEEDS_PUBLISH="$NEEDS_PUBLISH $crate"
67+
fi
68+
done
69+
70+
echo "needs_publish=$NEEDS_PUBLISH" >> $GITHUB_OUTPUT
71+
72+
if [ -z "$NEEDS_PUBLISH" ]; then
73+
echo "All crates are already published!"
74+
else
75+
echo "Crates to publish:$NEEDS_PUBLISH"
76+
fi
77+
78+
- name: Publish redis-cloud
79+
if: contains(steps.check-crates.outputs.needs_publish, 'redis-cloud')
80+
env:
81+
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
82+
run: |
83+
if [[ "${{ inputs.dry-run }}" == "true" ]]; then
84+
echo "DRY RUN: Would publish redis-cloud"
85+
cd crates/redis-cloud && cargo publish --dry-run
86+
else
87+
echo "Publishing redis-cloud..."
88+
cd crates/redis-cloud && cargo publish --no-verify
89+
fi
90+
91+
- name: Wait for redis-cloud to be available
92+
if: contains(steps.check-crates.outputs.needs_publish, 'redis-cloud')
93+
run: |
94+
if [[ "${{ inputs.dry-run }}" != "true" ]]; then
95+
echo "Waiting for redis-cloud to be available on crates.io..."
96+
sleep 30
97+
fi
98+
99+
- name: Publish redis-enterprise
100+
if: contains(steps.check-crates.outputs.needs_publish, 'redis-enterprise')
101+
env:
102+
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
103+
run: |
104+
if [[ "${{ inputs.dry-run }}" == "true" ]]; then
105+
echo "DRY RUN: Would publish redis-enterprise"
106+
cd crates/redis-enterprise && cargo publish --dry-run
107+
else
108+
echo "Publishing redis-enterprise..."
109+
cd crates/redis-enterprise && cargo publish --no-verify
110+
fi
111+
112+
- name: Wait for redis-enterprise to be available
113+
if: contains(steps.check-crates.outputs.needs_publish, 'redis-enterprise')
114+
run: |
115+
if [[ "${{ inputs.dry-run }}" != "true" ]]; then
116+
echo "Waiting for redis-enterprise to be available on crates.io..."
117+
sleep 30
118+
fi
119+
120+
- name: Publish redisctl
121+
if: contains(steps.check-crates.outputs.needs_publish, 'redisctl')
122+
env:
123+
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
124+
run: |
125+
if [[ "${{ inputs.dry-run }}" == "true" ]]; then
126+
echo "DRY RUN: Would publish redisctl"
127+
cd crates/redisctl && cargo publish --dry-run
128+
else
129+
echo "Publishing redisctl..."
130+
cd crates/redisctl && cargo publish --no-verify
131+
fi
132+
133+
- name: Verify publication
134+
if: ${{ inputs.dry-run != true && steps.check-crates.outputs.needs_publish != '' }}
135+
run: |
136+
echo "Waiting for crates to be fully available..."
137+
sleep 60
138+
139+
echo "Verifying all crates are published:"
140+
for crate in redis-cloud redis-enterprise redisctl; do
141+
CRATE_VERSION=$(grep "^version" crates/$crate/Cargo.toml | sed 's/.*= *"\(.*\)"/\1/')
142+
echo -n "Checking $crate v$CRATE_VERSION... "
143+
144+
if cargo search $crate --limit 1 | grep -q "^$crate = \"$CRATE_VERSION\""; then
145+
echo "✓ Published!"
146+
else
147+
echo "✗ Not found!"
148+
exit 1
149+
fi
150+
done
151+
152+
echo ""
153+
echo "All crates successfully published to crates.io!"
154+
echo ""
155+
echo "View them at:"
156+
echo " - https://crates.io/crates/redis-cloud"
157+
echo " - https://crates.io/crates/redis-enterprise"
158+
echo " - https://crates.io/crates/redisctl"

0 commit comments

Comments
 (0)