Skip to content

Commit 42a1069

Browse files
authored
ci: add cargo-public-api check for breaking API changes (#924)
* chore: bump Rust toolchain to 1.96 * ci: add cargo-public-api breaking-change check Adds a release-type-aware `cargo-public-api` diff job that fails on changed/removed public items unless the PR's commits mark a breaking (major) release. This catches source-breaking API changes that cargo-semver-checks cannot yet detect (e.g. function return-type or field-type changes).
1 parent b79e0d9 commit 42a1069

2 files changed

Lines changed: 72 additions & 1 deletion

File tree

.github/workflows/ci.yml

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,77 @@ jobs:
112112
--only-explicit-features \
113113
--features "$FEATURES"
114114
115+
public-api:
116+
name: Public API Check
117+
runs-on: ubuntu-latest
118+
if: github.event_name == 'pull_request'
119+
steps:
120+
- uses: actions/checkout@v7
121+
with:
122+
fetch-depth: 0
123+
124+
# cargo-public-api builds rustdoc JSON, which requires a nightly toolchain
125+
# to be installed (it does not need to be the default; the tool invokes it
126+
# via `cargo +nightly`).
127+
- name: Install Rust
128+
uses: dtolnay/rust-toolchain@nightly
129+
130+
- uses: Swatinem/rust-cache@v2
131+
132+
- name: Install cargo-public-api
133+
uses: taiki-e/install-action@v2
134+
with:
135+
tool: cargo-public-api
136+
137+
# Mirror the SemVer Check job's release-type detection: a breaking-change
138+
# commit marker (`!:` or `BREAKING CHANGE:`) means a major release (any API
139+
# change is allowed); otherwise a minor release (additions allowed, but
140+
# changed/removed public items are denied). This catches breaking changes
141+
# that cargo-semver-checks cannot yet detect, such as a change to a
142+
# function's return type or a field's type.
143+
# See https://github.com/obi1kenobi/cargo-semver-checks/issues/5
144+
- name: Determine release type and deny flags
145+
run: |
146+
if git log --format=%B \
147+
${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }} \
148+
| grep -Eq '(^[A-Za-z0-9_-]+(\([^)]*\))?!:|^BREAKING[ -]CHANGE:)'; then
149+
SEMVER_RELEASE_TYPE=major
150+
else
151+
SEMVER_RELEASE_TYPE=minor
152+
fi
153+
case "$SEMVER_RELEASE_TYPE" in
154+
major) DENY="" ;;
155+
patch) DENY="--deny added --deny changed --deny removed" ;;
156+
*) DENY="--deny changed --deny removed" ;;
157+
esac
158+
echo "SEMVER_RELEASE_TYPE=$SEMVER_RELEASE_TYPE" >> "$GITHUB_ENV"
159+
echo "DENY=$DENY" >> "$GITHUB_ENV"
160+
161+
- name: Check rmcp (default features)
162+
run: |
163+
cargo public-api \
164+
--package rmcp \
165+
-ss \
166+
diff \
167+
$DENY \
168+
--force \
169+
${{ github.event.pull_request.base.sha }}..${{ github.sha }}
170+
171+
- name: Check rmcp (all features except local)
172+
run: |
173+
FEATURES=$(cargo metadata --no-deps --format-version 1 \
174+
| jq -r '[.packages[] | select(.name == "rmcp") | .features | keys[]
175+
| select(startswith("__") | not)
176+
| select(. != "local")] | join(",")')
177+
cargo public-api \
178+
--package rmcp \
179+
--features "$FEATURES" \
180+
-ss \
181+
diff \
182+
$DENY \
183+
--force \
184+
${{ github.event.pull_request.base.sha }}..${{ github.sha }}
185+
115186
spelling:
116187
name: spell check with typos
117188
runs-on: ubuntu-latest

rust-toolchain.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
[toolchain]
2-
channel = "1.92"
2+
channel = "1.96"
33
components = ["rustc", "rust-std", "cargo", "clippy", "rustfmt", "rust-docs"]

0 commit comments

Comments
 (0)