Skip to content

Commit 42fd120

Browse files
authored
feat: Move to CI-based release process (#4265)
* feat(ci): automate release process Signed-off-by: Stepan Fedotov <trixter@osec.io> * refactor: bump only anchor's crates in lockfile * refactor(ci): reusable workflow for npmjs/crates/ci * refactor(ci): publish the entire workspace at once and handle environment correctly --------- Signed-off-by: Stepan Fedotov <trixter@osec.io>
1 parent 92716e4 commit 42fd120

File tree

42 files changed

+632
-95
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+632
-95
lines changed

.github/scripts/publish-npmjs.sh

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#!/usr/bin/env bash
2+
3+
set -xeuo pipefail
4+
5+
publish() {
6+
local dir="$1"
7+
pushd "$dir" >/dev/null
8+
9+
local name version
10+
name="$(node -p "require('./package.json').name")"
11+
version="$(node -p "require('./package.json').version")"
12+
13+
# We still build the package even if we don't publish it, as yarn workspace will
14+
# use the local version of each package, and if it's unbuilt then any subsequent
15+
# build will error out due to missing files.
16+
yarn --frozen-lockfile
17+
local dirname
18+
dirname="$(basename "$dir")"
19+
if [[ "$dirname" == spl-* ]]; then
20+
yarn build:npm
21+
else
22+
yarn build
23+
fi
24+
25+
if npm view "${name}@${version}" version >/dev/null 2>&1; then
26+
echo "The package $dir is already up to date, skipping"
27+
popd >/dev/null
28+
return 0
29+
fi
30+
31+
local publish_args=()
32+
# If version looks like X.Y.Z-<something> (e.g. 1.0.0-rc.2), publish under dist-tag "next"
33+
if [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+-.+ ]]; then
34+
publish_args+=(--tag next)
35+
fi
36+
37+
if [[ "${DRY_RUN:-false}" == "true" ]]; then
38+
echo "Publishing $dir (${name}@${version}) as a dry-run"
39+
npm publish "${publish_args[@]}" --dry-run
40+
else
41+
echo "Publishing $dir (${name}@${version})"
42+
npm publish "${publish_args[@]}" --provenance --access public
43+
fi
44+
45+
popd >/dev/null
46+
}
47+
48+
base="ts/packages"
49+
50+
publish "$base/borsh"
51+
publish "$base/anchor-errors"
52+
publish "$base/anchor"
53+
#publish "$base/spl-associated-token-account"
54+
#publish "$base/spl-binary-option"
55+
#publish "$base/spl-binary-oracle-pair"
56+
#publish "$base/spl-feature-proposal"
57+
#publish "$base/spl-governance"
58+
#publish "$base/spl-memo"
59+
#publish "$base/spl-name-service"
60+
#publish "$base/spl-record"
61+
#publish "$base/spl-stake-pool"
62+
#publish "$base/spl-stateless-asks"
63+
publish "$base/spl-token"
64+
#publish "$base/spl-token-lending"
65+
#publish "$base/spl-token-swap"

.github/workflows/build-cli.yaml

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
name: Build CLI
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
dry_run:
7+
description: "If true, use 'dry-run' as the version string instead of the tag"
8+
required: true
9+
type: boolean
10+
dist:
11+
description: "Directory name for distribution artifacts (e.g. dist-v1.2.3 or dist-dry-run)"
12+
required: true
13+
type: string
14+
15+
jobs:
16+
build-cli:
17+
name: Build binaries${{ inputs.dry_run && ' (dry-run)' || '' }}
18+
runs-on: ${{ matrix.os }}
19+
permissions:
20+
contents: read
21+
id-token: write
22+
attestations: write
23+
24+
strategy:
25+
matrix:
26+
target:
27+
- aarch64-apple-darwin
28+
- x86_64-unknown-linux-gnu
29+
- x86_64-apple-darwin
30+
- x86_64-pc-windows-msvc
31+
include:
32+
- target: aarch64-apple-darwin
33+
os: macos-latest
34+
35+
- target: x86_64-unknown-linux-gnu
36+
os: ubuntu-latest
37+
38+
- target: x86_64-apple-darwin
39+
os: macos-latest
40+
41+
- target: x86_64-pc-windows-msvc
42+
os: windows-latest
43+
44+
steps:
45+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
46+
47+
- uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
48+
with:
49+
toolchain: stable
50+
target: ${{ matrix.target }}
51+
52+
- name: Install dependencies (Linux)
53+
if: runner.os == 'Linux'
54+
run: sudo apt-get update && sudo apt-get install -y libudev-dev
55+
56+
- name: Build release binary
57+
run: cargo build --package trixter-osec-anchor-cli --release --locked --target ${{ matrix.target }}
58+
59+
- name: Prepare
60+
id: prepare
61+
shell: bash
62+
run: |
63+
if [[ "${{ inputs.dry_run }}" == "true" ]]; then
64+
version="dry-run"
65+
else
66+
version=$(echo $GITHUB_REF_NAME | cut -dv -f2)
67+
fi
68+
ext=""
69+
[[ "${{ matrix.os }}" == windows-latest ]] && ext=".exe"
70+
71+
mkdir ${{ inputs.dist }}
72+
mv "target/${{ matrix.target }}/release/anchor$ext" ${{ inputs.dist }}/anchor-$version-${{ matrix.target }}$ext
73+
74+
echo "version=$version" >> $GITHUB_OUTPUT
75+
76+
- name: Attest build provenance
77+
uses: actions/attest-build-provenance@96278af6caaf10aea03fd8d33a09a777ca52d62f # v3.2.0
78+
with:
79+
subject-path: ${{ inputs.dist }}/anchor-${{ steps.prepare.outputs.version }}-${{ matrix.target }}*
80+
81+
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
82+
with:
83+
name: anchor-${{ steps.prepare.outputs.version }}-${{ matrix.target }}
84+
path: ${{ inputs.dist }}
85+
overwrite: true
86+
retention-days: 1
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
name: Publish Crates
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
dry_run:
7+
description: "If true, build crates instead of publishing them (packaging validation only)"
8+
required: true
9+
type: boolean
10+
11+
jobs:
12+
publish-crates-dry-run:
13+
name: Publish crates (dry-run)
14+
if: ${{ inputs.dry_run }}
15+
runs-on: ubuntu-latest
16+
permissions:
17+
contents: read
18+
steps:
19+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
20+
21+
- uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
22+
with:
23+
toolchain: stable
24+
25+
- name: Publish crates
26+
run: |
27+
set -xeuo pipefail
28+
29+
echo "Publishing all workspace packages as a dry-run"
30+
cargo publish --workspace --locked --dry-run
31+
32+
publish-crates:
33+
name: Publish crates
34+
if: ${{ !inputs.dry_run }}
35+
runs-on: ubuntu-latest
36+
permissions:
37+
contents: read
38+
id-token: write
39+
attestations: write
40+
artifact-metadata: write
41+
environment:
42+
name: release
43+
steps:
44+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
45+
46+
- uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
47+
with:
48+
toolchain: stable
49+
50+
- name: Authenticate with crates.io
51+
id: auth
52+
uses: rust-lang/crates-io-auth-action@b7e9a28eded4986ec6b1fa40eeee8f8f165559ec # v1.0.3
53+
54+
- name: Publish crates
55+
env:
56+
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
57+
run: |
58+
set -xeuo pipefail
59+
60+
echo "Publishing all workspace packages"
61+
cargo publish --workspace --locked
62+
63+
- name: Check for crate artifacts
64+
id: crate-artifacts
65+
if: ${{ !inputs.dry_run }}
66+
run: |
67+
shopt -s nullglob
68+
files=(target/package/*.crate)
69+
if [ ${#files[@]} -gt 0 ]; then
70+
echo "found=true" >> "$GITHUB_OUTPUT"
71+
cd target/package
72+
sha256sum *.crate > SHA256SUMS
73+
echo "--- Crate checksums ---"
74+
cat SHA256SUMS
75+
else
76+
echo "found=false" >> "$GITHUB_OUTPUT"
77+
fi
78+
79+
- name: Attest crate checksum manifest
80+
uses: actions/attest-build-provenance@96278af6caaf10aea03fd8d33a09a777ca52d62f # v3.2.0
81+
if: ${{ !inputs.dry_run && steps.crate-artifacts.outputs.found == 'true' }}
82+
with:
83+
subject-path: target/package/SHA256SUMS
84+
85+
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
86+
if: ${{ !inputs.dry_run && steps.crate-artifacts.outputs.found == 'true' }}
87+
with:
88+
if-no-files-found: ignore
89+
name: published-crates
90+
path: |
91+
target/package/*.crate
92+
target/package/SHA256SUMS
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: Publish npmjs
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
dry_run:
7+
description: "If true, use --dry-run instead of actually publishing"
8+
required: true
9+
type: boolean
10+
11+
jobs:
12+
publish-npmjs-dry-run:
13+
name: Publish npmjs packages (dry-run)
14+
if: ${{ inputs.dry_run }}
15+
runs-on: ubuntu-latest
16+
permissions:
17+
contents: read
18+
steps:
19+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
20+
21+
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
22+
with:
23+
node-version: "24"
24+
registry-url: "https://registry.npmjs.org"
25+
package-manager-cache: false
26+
27+
- name: Enable corepack (yarn)
28+
run: corepack enable
29+
30+
- name: Publish npmjs packages
31+
env:
32+
DRY_RUN: "true"
33+
run: bash .github/scripts/publish-npmjs.sh
34+
35+
publish-npmjs:
36+
name: Publish npmjs packages
37+
if: ${{ !inputs.dry_run }}
38+
runs-on: ubuntu-latest
39+
permissions:
40+
id-token: write
41+
contents: read
42+
environment:
43+
name: release
44+
steps:
45+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
46+
47+
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
48+
with:
49+
node-version: "24"
50+
registry-url: "https://registry.npmjs.org"
51+
package-manager-cache: false
52+
53+
- name: Enable corepack (yarn)
54+
run: corepack enable
55+
56+
- name: Publish npmjs packages
57+
env:
58+
DRY_RUN: "false"
59+
run: bash .github/scripts/publish-npmjs.sh

.github/workflows/release-pr.yaml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: Release Dry-run
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- master
7+
8+
paths:
9+
- VERSION
10+
- github/workflows/release-pr.yaml
11+
- github/workflows/build-cli.yaml
12+
- github/workflows/publish-crates.yaml
13+
- github/workflows/publish-npmjs.yaml
14+
15+
workflow_dispatch:
16+
17+
env:
18+
DIST: dist-dry-run
19+
20+
jobs:
21+
publish-crates-dryrun:
22+
name: Publish crates (dry-run)
23+
uses: ./.github/workflows/publish-crates.yaml
24+
with:
25+
dry_run: true
26+
27+
publish-npmjs-dryrun:
28+
name: Publish npmjs packages (dry-run)
29+
uses: ./.github/workflows/publish-npmjs.yaml
30+
with:
31+
dry_run: true
32+
33+
# We skip checking if the Docker image builds for now as it depends on the version tag already existing,
34+
# though as we already have the `build-cli-dryrun` step below there should be rarely any reason for the
35+
# image build to ever fail anyway.
36+
37+
build-cli-dryrun:
38+
name: Build binaries (dry-run)
39+
uses: ./.github/workflows/build-cli.yaml
40+
with:
41+
dry_run: true
42+
dist: dist-dry-run

0 commit comments

Comments
 (0)