Skip to content

Commit 27220c7

Browse files
authored
CI: Add manual workflow to publish crates (#6)
#### Problem The solana-sdk repo has no way of publishing crates. #### Summary of changes Following the model used by SPL at solana-labs/solana-program-library#7184, add a manual workflow to publish crates.
1 parent eef0b8e commit 27220c7

File tree

4 files changed

+284
-0
lines changed

4 files changed

+284
-0
lines changed

.github/workflows/publish-rust.yml

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
name: Publish Crate
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
package_path:
7+
description: Path to directory with package to release
8+
required: true
9+
type: string
10+
level:
11+
description: Level
12+
required: true
13+
default: patch
14+
type: choice
15+
options:
16+
- patch
17+
- minor
18+
- major
19+
- version
20+
version:
21+
description: Version (used with level "version")
22+
required: false
23+
type: string
24+
dry_run:
25+
description: Dry run
26+
required: true
27+
default: true
28+
type: boolean
29+
create_release:
30+
description: Create a GitHub release
31+
required: true
32+
type: boolean
33+
default: true
34+
35+
jobs:
36+
sanity:
37+
name: Sanity checks
38+
runs-on: ubuntu-latest
39+
steps:
40+
- name: Git Checkout
41+
uses: actions/checkout@v4
42+
with:
43+
fetch-depth: 0 # full history to check for whitespace / conflict markers
44+
45+
- name: Setup Environment
46+
uses: ./.github/actions/setup
47+
with:
48+
stable-toolchain: true
49+
cargo-cache-key: cargo-stable-sanity
50+
cargo-cache-fallback-key: cargo-stable
51+
52+
- name: Check repo is in porcelain state
53+
run: ./scripts/check-porcelain.sh
54+
55+
- name: Check code nits
56+
run: ./scripts/check-nits.sh
57+
58+
format:
59+
name: Format
60+
runs-on: ubuntu-latest
61+
needs: [sanity]
62+
steps:
63+
- name: Git Checkout
64+
uses: actions/checkout@v4
65+
66+
- name: Setup Environment
67+
uses: ./.github/actions/setup
68+
with:
69+
rustfmt: true
70+
cargo-cache-key: cargo-nightly-fmt
71+
cargo-cache-fallback-key: cargo-nightly
72+
73+
- name: Check formatting
74+
run: ./scripts/check-fmt.sh
75+
76+
clippy:
77+
name: Clippy
78+
needs: [sanity]
79+
runs-on: ubuntu-latest
80+
steps:
81+
- name: Git Checkout
82+
uses: actions/checkout@v4
83+
84+
- name: Setup Environment
85+
uses: ./.github/actions/setup
86+
with:
87+
clippy: true
88+
cargo-cache-key: cargo-nightly-clippy
89+
cargo-cache-fallback-key: cargo-nightly
90+
91+
- name: Run clippy
92+
run: ./scripts/check-clippy.sh
93+
94+
publish-crate:
95+
name: Publish crate
96+
runs-on: ubuntu-latest
97+
needs: [format, clippy]
98+
permissions:
99+
contents: write
100+
steps:
101+
- name: Git Checkout
102+
uses: actions/checkout@v4
103+
with:
104+
token: ${{ secrets.ANZA_TEAM_PAT }}
105+
fetch-depth: 0 # get the whole history for git-cliff
106+
107+
- name: Setup Environment
108+
uses: ./.github/actions/setup
109+
with:
110+
stable-toolchain: true
111+
cargo-cache-key: cargo-stable-publish
112+
cargo-cache-fallback-key: cargo-stable
113+
114+
- name: Install cargo-release
115+
uses: taiki-e/cache-cargo-install-action@v2
116+
with:
117+
tool: cargo-release
118+
119+
- name: Ensure CARGO_REGISTRY_TOKEN variable is set
120+
env:
121+
token: ${{ secrets.CARGO_REGISTRY_TOKEN }}
122+
if: ${{ env.token == '' }}
123+
run: |
124+
echo "The CARGO_REGISTRY_TOKEN secret variable is not set"
125+
echo "Go to \"Settings\" -> \"Secrets and variables\" -> \"Actions\" -> \"New repository secret\"."
126+
exit 1
127+
128+
- name: Set Git Author
129+
run: |
130+
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
131+
git config --global user.name "github-actions[bot]"
132+
133+
- name: Publish Crate
134+
id: publish
135+
env:
136+
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
137+
run: |
138+
if [ "${{ inputs.level }}" == "version" ]; then
139+
LEVEL=${{ inputs.version }}
140+
else
141+
LEVEL=${{ inputs.level }}
142+
fi
143+
144+
if [ "${{ inputs.dry_run }}" == "true" ]; then
145+
OPTIONS="--dry-run"
146+
else
147+
OPTIONS=""
148+
fi
149+
150+
./scripts/publish-rust.sh "${{ inputs.package_path }}" $LEVEL $OPTIONS
151+
152+
- name: Generate a changelog
153+
if: github.event.inputs.create_release == 'true'
154+
uses: orhun/git-cliff-action@v3
155+
with:
156+
config: "scripts/cliff.toml"
157+
args: |
158+
"${{ steps.publish.outputs.old_git_tag }}"..master
159+
--include-path "${{ inputs.package_path }}/**"
160+
--github-repo "${{ github.repository }}"
161+
env:
162+
OUTPUT: TEMP_CHANGELOG.md
163+
GITHUB_REPO: ${{ github.repository }}
164+
165+
- name: Create GitHub release
166+
if: github.event.inputs.create_release == 'true' && github.event.inputs.dry_run != 'true'
167+
uses: ncipollo/release-action@v1
168+
with:
169+
tag: ${{ steps.publish.outputs.new_git_tag }}
170+
bodyFile: TEMP_CHANGELOG.md

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,17 @@ To patch all of the crates in this repo for Agave, just run:
1515
```console
1616
./scripts/patch-crates-no-header.sh <AGAVE_PATH> <SOLANA_SDK_PATH>
1717
```
18+
19+
### Publishing a crate from this repository
20+
21+
Unlike Agave, the solana-sdk crates are versioned independently, and published
22+
as needed.
23+
24+
If you need to publish a crate, you can use the "Publish Crate" GitHub Action.
25+
Simply type in the path to the crate directory you want to release, ie.
26+
`program-entrypoint`, along with the kind of release, either `patch`, `minor`,
27+
`major`, or a specific version string.
28+
29+
The publish job will run checks, bump the crate version, commit and tag the
30+
bump, publish the crate to crates.io, and finally create GitHub Release with
31+
a simple changelog of all commits to the crate since the previous release.

scripts/cliff.toml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# git-cliff configuration file
2+
# https://git-cliff.org/docs/configuration
3+
[changelog]
4+
header = """
5+
## What's new
6+
"""
7+
body = """
8+
{% for group, commits in commits | group_by(attribute="group") %}\
9+
{% for commit in commits %}
10+
- {{ commit.message | upper_first | split(pat="\n") | first | trim }}\
11+
{% if commit.remote.username %} by @{{ commit.remote.username }}{%- endif %}\
12+
{% endfor %}\
13+
{% endfor %}
14+
"""
15+
# remove the leading and trailing whitespace from the template
16+
trim = true
17+
footer = """
18+
"""
19+
postprocessors = [ ]
20+
[git]
21+
# parse the commits based on https://www.conventionalcommits.org
22+
conventional_commits = true
23+
# filter out the commits that are not conventional
24+
filter_unconventional = false
25+
# process each line of a commit as an individual commit
26+
split_commits = false
27+
# regex for preprocessing the commit messages
28+
commit_preprocessors = []
29+
# regex for parsing and grouping commits
30+
commit_parsers = [
31+
{ message = "^build\\(deps\\)", skip = true },
32+
{ message = "^build\\(deps-dev\\)", skip = true },
33+
{ message = "^ci", skip = true },
34+
{ body = ".*", group = "Changes" },
35+
]
36+
# protect breaking changes from being skipped due to matching a skipping commit_parser
37+
protect_breaking_commits = false
38+
# filter out the commits that are not matched by commit parsers
39+
filter_commits = false
40+
# glob pattern for matching git tags
41+
tag_pattern = "v[0-9]*"
42+
# regex for skipping tags
43+
skip_tags = ""
44+
# regex for ignoring tags
45+
ignore_tags = ""
46+
# sort the tags topologically
47+
topo_order = false
48+
# sort the commits inside sections by oldest/newest order
49+
sort_commits = "newest"

scripts/publish-rust.sh

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#!/usr/bin/env bash
2+
3+
set -e
4+
base="$(dirname "${BASH_SOURCE[0]}")"
5+
# pacify shellcheck: cannot follow dynamic path
6+
# shellcheck disable=SC1090,SC1091
7+
source "$base/read-cargo-variable.sh"
8+
cd "$base/.."
9+
10+
if [[ -z $1 ]]; then
11+
echo 'A package manifest path — e.g. "program" — must be provided.'
12+
exit 1
13+
fi
14+
PACKAGE_PATH=$1
15+
if [[ -z $2 ]]; then
16+
echo 'A version level — e.g. "patch" — must be provided.'
17+
exit 1
18+
fi
19+
LEVEL=$2
20+
DRY_RUN=$3
21+
22+
# Go to the directory
23+
cd "${PACKAGE_PATH}"
24+
25+
# Get the old version, used with git-cliff
26+
old_version=$(readCargoVariable version "Cargo.toml")
27+
package_name=$(readCargoVariable name "Cargo.toml")
28+
tag_name="${package_name//solana-/}"
29+
30+
# Publish the new version, commit the repo change, tag it, and push it all.
31+
if [[ -n ${DRY_RUN} ]]; then
32+
cargo release "${LEVEL}"
33+
else
34+
cargo release "${LEVEL}" --tag-name "${tag_name}@v{{version}}" --no-confirm --execute
35+
fi
36+
37+
# Stop here if this is a dry run.
38+
if [[ -n $DRY_RUN ]]; then
39+
exit 0
40+
fi
41+
42+
# Get the new version.
43+
new_version=$(readCargoVariable version "Cargo.toml")
44+
new_git_tag="${tag_name}@v${new_version}"
45+
old_git_tag="${tag_name}@v${old_version}"
46+
47+
# Expose the new version to CI if needed.
48+
if [[ -n $CI ]]; then
49+
echo "new_git_tag=${new_git_tag}" >> "$GITHUB_OUTPUT"
50+
echo "old_git_tag=${old_git_tag}" >> "$GITHUB_OUTPUT"
51+
fi

0 commit comments

Comments
 (0)