Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
version: 2

updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
cooldown:
default-days: 7
40 changes: 29 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ jobs:
name: shellcheck + syntax
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
# shellcheck is preinstalled on ubuntu-latest runners.
- name: shellcheck
run: shellcheck -S warning zc tests/run.sh
Expand All @@ -25,17 +27,33 @@ jobs:
test:
name: integration tests
runs-on: ubuntu-latest
env:
ZC_TOOLCHAIN: nightly-2026-07-18
steps:
- uses: actions/checkout@v4
# cargo-public-api builds rustdoc JSON, which needs a nightly toolchain.
- name: Install Rust (stable + nightly)
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Create an action fixture
Comment thread
gustavovalverde marked this conversation as resolved.
id: fixture
run: |
rustup toolchain install stable --profile minimal --no-self-update
rustup toolchain install nightly --profile minimal --no-self-update
rustup default stable
- uses: Swatinem/rust-cache@v2
- name: Install cargo-public-api
run: cargo install cargo-public-api --locked
# jq is preinstalled on ubuntu-latest runners.
mkdir -p action-fixture/src
cd action-fixture
printf '[package]\nname = "zc_action_fixture"\nversion = "0.1.0"\nedition = "2021"\n' > Cargo.toml
printf 'version = 4\n\n[[package]]\nname = "zc_action_fixture"\nversion = "0.1.0"\n' > Cargo.lock
git init
git config user.name "zc CI"
git config user.email "zc-ci@users.noreply.github.com"
printf 'pub fn existing() {}\n' > src/lib.rs
git add .
git commit -m "fixture baseline"
echo "baseline=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
printf 'pub fn existing() {}\npub fn added() {}\n' > src/lib.rs
git add src/lib.rs
git commit -m "fixture head"
- name: Run the local action
uses: ./
with:
baseline: ${{ steps.fixture.outputs.baseline }}
working-directory: action-fixture
- name: Run integration tests
run: tests/run.sh
41 changes: 29 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,29 @@ under a per-run temp directory. Public API builds use target dirs in that temp
directory, so the invoking checkout's HEAD, branch, index, working tree, and
`Cargo.lock` are not checked out over or built in. The worktrees are removed on exit.

## GitHub Actions

Use the action in a pull request workflow after checking out the pull request head with complete history:

```yaml
permissions:
contents: read

steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
persist-credentials: false
- uses: ZcashFoundation/zc@v0.3.0
with:
baseline: origin/${{ github.base_ref }}
```

The action installs the `cargo-public-api` and Rust nightly versions tested with that `zc` release. It compares the pull request head with its branch point from the baseline, then fails with the same exit-code contract as the CLI. Set `head` when both refs must be compared literally, or enable `with-lock` and `with-values` for the optional analyses.

Pin the action to a full commit SHA when the workflow requires an immutable dependency.

## Cache

zc stores persistent cache files under `target/zc-cache/`, or under
Expand All @@ -54,27 +77,21 @@ state for a checkout.
First install the prerequisites (see [Requirements](#requirements)):

```sh
cargo install cargo-public-api # required; jq is also required
cargo install cargo-public-api --version 0.52.0 --locked
rustup toolchain install nightly-2026-07-18 --profile minimal
```

Then get `zc` itself — it's a single Bash script. Install it onto your `PATH`:

```sh
curl -fsSL https://raw.githubusercontent.com/ZcashFoundation/zc/main/zc -o ~/.local/bin/zc && chmod +x ~/.local/bin/zc
curl -fsSL https://raw.githubusercontent.com/ZcashFoundation/zc/v0.3.0/zc -o ~/.local/bin/zc
chmod +x ~/.local/bin/zc
```

…or run a one-off without installing:

```sh
curl -fsSL https://raw.githubusercontent.com/ZcashFoundation/zc/main/zc | bash -s -- main
```

In CI, the download-then-run form is the most robust:

```sh
curl -fsSL https://raw.githubusercontent.com/ZcashFoundation/zc/main/zc -o zc
chmod +x zc
./zc "$BASE".."$HEAD" --json
curl -fsSL https://raw.githubusercontent.com/ZcashFoundation/zc/v0.3.0/zc | bash -s -- main
```

> When run via `curl … | bash`, `--help` shows only a short usage (the script
Expand All @@ -91,7 +108,7 @@ zc --with-lock # include the transitive Cargo.lock diff
zc --with-values main # also flag const/static value + doc changes
zc --json main # machine-readable output for CI
zc --changelog main # draft a librustzcash-style changelog (markdown)
zc --version # version, current commit, and whether it's up to date with origin/main
zc --version # print the installed version
```

Run `zc --help` for the full option and output reference.
Expand Down
93 changes: 93 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
name: zc Rust API check
description: Check a Rust workspace for breaking public API and dependency changes
author: Zcash Foundation

branding:
icon: check-circle
color: blue

inputs:
baseline:
description: Git ref used as the comparison baseline
required: true
head:
description: Optional exact head ref; omit it to compare the baseline branch point with HEAD
required: false
default: ""
working-directory:
description: Directory containing the Rust workspace
required: false
default: .
with-lock:
description: Include transitive Cargo.lock changes
required: false
default: "false"
with-values:
description: Include public const, static value, and documentation changes
required: false
default: "false"

runs:
using: composite
steps:
- name: Check system dependencies
shell: bash
run: |
if ! command -v jq >/dev/null 2>&1; then
echo "::error title=Missing zc dependency::Install jq on the runner before using this action."
exit 64
fi

- name: Install the Rust nightly used by zc
shell: bash
env:
ZC_TOOLCHAIN: nightly-2026-07-18
run: rustup toolchain install "$ZC_TOOLCHAIN" --profile minimal --no-self-update

- name: Install cargo-public-api
uses: taiki-e/install-action@7572810d7dd469b651bb7793945692cf78da5dd7 # v2.85.0
with:
tool: cargo-public-api@0.52.0
checksum: true
env:
RUSTUP_TOOLCHAIN: nightly-2026-07-18

- name: Check the public API and dependencies
Comment thread
gustavovalverde marked this conversation as resolved.
shell: bash
working-directory: ${{ inputs.working-directory }}
env:
INPUT_BASELINE: ${{ inputs.baseline }}
INPUT_HEAD: ${{ inputs.head }}
INPUT_WITH_LOCK: ${{ inputs.with-lock }}
INPUT_WITH_VALUES: ${{ inputs.with-values }}
RUSTUP_TOOLCHAIN: nightly-2026-07-18
ZC_TOOLCHAIN: nightly-2026-07-18
run: |
set -euo pipefail

arguments=()

case "$INPUT_WITH_LOCK" in
true) arguments+=(--with-lock) ;;
false) ;;
*)
echo "::error title=Invalid with-lock input::Expected true or false."
exit 64
;;
esac

case "$INPUT_WITH_VALUES" in
true) arguments+=(--with-values) ;;
false) ;;
*)
echo "::error title=Invalid with-values input::Expected true or false."
exit 64
;;
esac

arguments+=("$INPUT_BASELINE")
if [[ -n "$INPUT_HEAD" ]]; then
arguments+=("$INPUT_HEAD")
fi

"$GITHUB_ACTION_PATH/zc" "${arguments[@]}"
18 changes: 7 additions & 11 deletions tests/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -693,19 +693,14 @@ else
fi
rm -rf "$repo"

# 11) --version prints the version and commit, and honors ZC_NO_UPDATE_CHECK.
# 11) --version prints the release version without requiring analysis tools.
ver=$(grep -m1 '^ZC_VERSION=' "$ZC" | cut -d= -f2)
out=$( ZC_NO_UPDATE_CHECK=1 "$ZC" --version 2>&1 ); rc=$?
out=$("$ZC" --version 2>&1); rc=$?
assert_eq "$rc" 0 "--version: exit 0"
assert_contains "$out" "zc $ver" "--version: prints 'zc <ZC_VERSION>'"
assert_contains "$out" "commit:" "--version: prints a commit line"
case "$out" in
*update:*) bad "--version: ZC_NO_UPDATE_CHECK should suppress the update line" ;;
*) ok "--version: ZC_NO_UPDATE_CHECK suppresses the update line" ;;
esac
out=$( ZC_NO_UPDATE_CHECK=1 "$ZC" -V 2>&1 ); rc=$?
assert_eq "$out" "zc $ver" "--version: prints 'zc <ZC_VERSION>'"
out=$("$ZC" -V 2>&1); rc=$?
assert_eq "$rc" 0 "-V alias: exit 0"
assert_contains "$out" "zc $ver" "-V alias: prints the version line"
assert_eq "$out" "zc $ver" "-V alias: prints the version line"

# 12) Public-dependency semver join: a foreign type re-exposed in a crate's
# public API whose crate takes a major bump is flagged, attributed to that
Expand Down Expand Up @@ -735,7 +730,8 @@ new_pubdep_repo() { # $1=foo dependency line $2=foo/src/lib.rs -> repo dir
}
bump_pubdep_head() { # $1=repo $2=new foo dependency line -> head sha
local d=$1 dep_line=$2
sed -i 's/^version = "0.1.0"/version = "0.2.0"/' "$d/bar/Cargo.toml"
sed -i.bak 's/^version = "0.1.0"/version = "0.2.0"/' "$d/bar/Cargo.toml"
rm "$d/bar/Cargo.toml.bak"
printf '[package]\nname = "foo"\nversion = "0.1.0"\nedition = "2021"\n\n[dependencies]\n%s\n' "$dep_line" >"$d/foo/Cargo.toml"
( cd "$d" && cargo generate-lockfile -q ) >/dev/null 2>&1
git -C "$d" add -A
Expand Down
Loading