Skip to content

Commit cac1712

Browse files
authored
CI: Add publish workflow (#68)
* CI: Add publish workflow #### Problem The repo has no automated publishing workflow. #### Summary of changes Following how it's done at token-2022, add the workflow! This means adding a script, package.json entry, git-cliff configuration, and GH actions workflow file. Note that this requires #67 to land first. * Fix yaml * Proper default
1 parent 86a56dc commit cac1712

File tree

4 files changed

+279
-0
lines changed

4 files changed

+279
-0
lines changed

.github/workflows/publish-rust.yml

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

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"template:upgrade": "zx ./scripts/upgrade-template.mjs",
1313
"rust:spellcheck": "cargo spellcheck --code 1",
1414
"rust:audit": "zx ./scripts/rust/audit.mjs",
15+
"rust:publish": "zx ./scripts/rust/publish.mjs",
1516
"rust:semver": "cargo semver-checks"
1617
},
1718
"devDependencies": {

scripts/cliff.toml

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

scripts/rust/publish.mjs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env zx
2+
import 'zx/globals';
3+
import { cliArguments, getCargo, workingDirectory } from '../utils.mjs';
4+
5+
const dryRun = argv['dry-run'] ?? false;
6+
const [folder, level] = cliArguments();
7+
if (!folder) {
8+
throw new Error('A path to a directory with a Rust package — e.g. "clients/cli" — must be provided.');
9+
}
10+
if (!level) {
11+
throw new Error('A version level — e.g. "patch" — must be provided.');
12+
}
13+
14+
cd(path.join(workingDirectory, folder));
15+
16+
const packageToml = getCargo(folder).package;
17+
const oldVersion = packageToml.version;
18+
const packageName = packageToml.name;
19+
const tagName = path.basename(folder);
20+
21+
// Publish the new version, commit the repo change, tag it, and push it all.
22+
const releaseArgs = dryRun
23+
? []
24+
: ['--tag-name', `${tagName}@v{{version}}`, '--no-confirm', '--execute'];
25+
await $`cargo release ${level} ${releaseArgs}`;
26+
27+
// Stop here if this is a dry run.
28+
if (dryRun) {
29+
process.exit(0);
30+
}
31+
32+
// Get the new version.
33+
const newVersion = getCargo(folder).package.version;
34+
const newGitTag = `${tagName}@v${newVersion}`;
35+
const oldGitTag = `${tagName}@v${oldVersion}`;
36+
37+
// Expose the new version to CI if needed.
38+
if (process.env.CI) {
39+
await $`echo "new_git_tag=${newGitTag}" >> $GITHUB_OUTPUT`;
40+
await $`echo "old_git_tag=${oldGitTag}" >> $GITHUB_OUTPUT`;
41+
}

0 commit comments

Comments
 (0)