Skip to content

Commit 6ddea2f

Browse files
committed
feat(publish): update publish workflow
This change updates the publish workflow to support tagging with the `${packageName}/v${version}` format so that we can publish packages independent of each other now that we are not bumping the version of all packages at the same time. This also adds a script to parse the output of `cargo metadata` to get the correct package name and version for all packages in the workspace. This is used to validate the tag before publishing to ensure that we are only publishing the package that we intend to publish. Also updated is the `attach-static-libs` workflow to only trigger on the `firewood-ffi` release tag since that is the only package that triggers an update to the Go wrapper module. Closes: #1560 Closes: #1561
1 parent b2a8248 commit 6ddea2f

File tree

3 files changed

+81
-58
lines changed

3 files changed

+81
-58
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/usr/bin/env bash
2+
3+
# This script emits all of the local cargo packages and their current versions
4+
# in topological order, so that they can be published to crates.io in the
5+
# correct order. The output is in the format "package-name/vVERSION", one per
6+
# line. When tagging cargo packages, the tag is expected to match the format
7+
# exactly.
8+
9+
set -euo pipefail
10+
11+
METADATA=$(cargo metadata --locked --format-version=1 --all-features --no-deps)
12+
13+
QUERY='
14+
# store the input for multiple passes
15+
. as $input |
16+
17+
# first pass: collect the name and version for each local package
18+
$input.packages[] | [{ key: .name, value: .version }] |
19+
from_entries as $versions |
20+
21+
# second pass: for each package, emit a single object for each (package,
22+
# dependency) pair where the dependency is also a local package
23+
$input.packages[] | {
24+
name,
25+
version,
26+
dependency: (.dependencies[] | {
27+
name,
28+
version: $versions[.name]
29+
} | select(.version != null))
30+
} |
31+
32+
# join the dependency and package with a tab, then sort topologically
33+
"\(.dependency.name)/v\(.dependency.version)\t\(.name)/v\(.version)"
34+
'
35+
36+
jq -r "${QUERY}" <<< "$METADATA" | tsort

.github/workflows/attach-static-libs.yaml

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ on:
88
required: true
99
push:
1010
tags:
11-
- "*"
11+
# Only tagging a release for the `firewood-ffi` crate can trigger a new
12+
# release for the Go wrapper module.
13+
- firewood-ffi/v*
1214
branches:
1315
- "main"
1416
pull_request:
@@ -164,17 +166,10 @@ jobs:
164166
git commit -m "firewood ci ${{ github.sha }}: attach firewood static libs"
165167
git push -u origin ${{ steps.determine_branch.outputs.target_branch }} --force
166168
167-
if [[ "${{ github.ref_type }}" == "tag" ]]; then
168-
# If the tag is a semantic version, prefix it with "ffi/" to ensure go get correctly
169-
# fetches the submodule. Otherwise, use the tag name as is.
170-
# Note: we explicitly ignore semantic versions with suffixes ie. v1.1.1-beta because
171-
# go get treats them as non-semantic version tags.
172-
# Ref: https://github.com/ava-labs/firewood/pull/991
173-
if [[ "${{ github.ref_name }}" =~ ^v?[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
174-
tag_name="ffi/${GITHUB_REF#refs/tags/}"
175-
else
176-
tag_name="${GITHUB_REF#refs/tags/}"
177-
fi
169+
ref_name="${GITHUB_REF#refs/tags/}"
170+
if [[ "${{ github.ref_type }}" == "tag" && ref_name == firewood-ffi/v* ]]; then
171+
# If the tag is for `firewood-ffi/*`, rename to `ffi/*` before tagging the other repo
172+
tag_name="${ref_name/firewood-ffi\//ffi/}"
178173
git tag -a "$tag_name" -m "firewood ci ${{ github.sha }}: attach firewood static libs"
179174
git push origin "refs/tags/$tag_name"
180175
fi

.github/workflows/publish.yaml

Lines changed: 38 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,53 +6,45 @@ on:
66
types: [published]
77

88
jobs:
9-
publish-firewood-crate:
10-
name: firewood-lib
9+
publish-single-firewood-crate:
10+
name: publish-crate
1111
runs-on: ubuntu-latest
12-
if: startsWith(github.event.release.tag_name, 'v')
12+
# e.g., firewood/v0.2.0 or fireweood-storage/v0.2.0
13+
if: startsWith(github.event.release.tag_name, 'firewood') && contains(github.event.release.tag_name, '/v')
1314
steps:
1415
- uses: actions/checkout@v1
15-
- uses: dtolnay/rust-toolchain@stable
16-
## NOTE: keep these packages sorted in reverse topological order!
17-
## cargo tree --workspace -e all | grep firewood
18-
- name: publish firewood-macros crate
19-
continue-on-error: false
20-
run: |
21-
cargo login ${{ secrets.CARGO_TOKEN }}
22-
cargo publish -p firewood-macros
23-
# TODO(demosdemon): detect when version is bumped and only publish then
24-
# - name: publish firewood-triehash crate
25-
# continue-on-error: false
26-
# run: |
27-
# cargo login ${{ secrets.CARGO_TOKEN }}
28-
# cargo publish -p firewood-triehash
29-
- name: publish firewood-storage crate
30-
continue-on-error: false
31-
run: |
32-
cargo login ${{ secrets.CARGO_TOKEN }}
33-
cargo publish -p firewood-storage
34-
- name: publish firewood crate
35-
continue-on-error: false
36-
run: |
37-
cargo login ${{ secrets.CARGO_TOKEN }}
38-
cargo publish -p firewood
39-
- name: publish firewood-replay crate
40-
continue-on-error: false
41-
run: |
42-
cargo login ${{ secrets.CARGO_TOKEN }}
43-
cargo publish -p firewood-replay
44-
- name: publish firewood-ffi crate
45-
continue-on-error: false
46-
run: |
47-
cargo login ${{ secrets.CARGO_TOKEN }}
48-
cargo publish -p firewood-ffi
49-
- name: publish firewood-fwdctl crate
50-
continue-on-error: false
16+
- name: parse and validate tag
17+
id: parse_tag
5118
run: |
52-
cargo login ${{ secrets.CARGO_TOKEN }}
53-
cargo publish -p firewood-fwdctl
54-
- name: publish firewood-benchmark crate
55-
continue-on-error: false
56-
run: |
57-
cargo login ${{ secrets.CARGO_TOKEN }}
58-
cargo publish -p firewood-benchmark
19+
set -exo pipefail
20+
21+
TAG_REF="${GITHUB_REF#refs/tags/}"
22+
23+
mapfile -t valid_tags < <(.github/scripts/cargo-release-tags.sh)
24+
25+
for tag in "${valid_tags[@]}"; do
26+
if [[ "$TAG_REF" == "$tag" ]]; then
27+
echo "Tag $TAG_REF is valid, proceeding with publish"
28+
echo "FOUND_TAG=$tag" >> "$GITHUB_OUTPUT"
29+
echo "PACKAGE=${tag%%/*}" >> "$GITHUB_OUTPUT"
30+
exit 0
31+
fi
32+
done
33+
34+
echo "FOUND_TAG=none" >> "$GITHUB_OUTPUT"
35+
- uses: dtolnay/rust-toolchain@stable
36+
if: steps.parse_tag.outputs.FOUND_TAG != 'none'
37+
- name: dry-run publish crate
38+
if: steps.parse_tag.outputs.FOUND_TAG != 'none'
39+
env:
40+
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_TOKEN }}
41+
# Will build the crate and verify its dependencies, but won't actually publish it. This is
42+
# a minor safety check to make sure the crate is publishable before we attempt to publish it
43+
# for real.
44+
run: cargo publish ${{ steps.parse_tag.outputs.PACKAGE }} --locked --dry-run
45+
- name: publish crate
46+
if: steps.parse_tag.outputs.FOUND_TAG != 'none'
47+
env:
48+
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_TOKEN }}
49+
# --no-verify since we just did a dry-run
50+
run: cargo publish ${{ steps.parse_tag.outputs.PACKAGE }} --locked --no-verify

0 commit comments

Comments
 (0)