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
59 changes: 20 additions & 39 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@ jobs:
name: Public API Guard
runs-on: ubuntu-latest
timeout-minutes: 30
continue-on-error: true # cargo-public-api v0.38.0 can't parse rustdoc JSON v498
continue-on-error: true # Gracefully degrade when cargo-public-api can't parse rustdoc JSON
if: github.event_name == 'pull_request'
needs: path-filter
steps:
Expand All @@ -501,14 +501,17 @@ jobs:
with:
fetch-depth: 0

- name: Install Rust toolchain
- name: Install Rust nightly toolchain
id: rust-toolchain
uses: dtolnay/rust-toolchain@nightly

- name: Install Rust stable toolchain
uses: dtolnay/rust-toolchain@stable

- name: Get toolchain hash
id: toolchain-hash
shell: bash
run: echo "cachekey=$(rustc -Vv | sha256sum | cut -d' ' -f1)" >> $GITHUB_OUTPUT
run: echo "cachekey=$(rustc +nightly -Vv | sha256sum | cut -d' ' -f1)" >> $GITHUB_OUTPUT

- name: Cache cargo registry
uses: actions/cache@v4
Expand Down Expand Up @@ -539,58 +542,36 @@ jobs:
sudo apt-get update
sudo apt-get install -y libudev-dev

- name: Cache cargo-public-api binary
uses: actions/cache@v4
with:
path: ~/.cargo/bin/cargo-public-api
key: cargo-public-api-${{ runner.os }}-0.38.0

- name: Install cargo-public-api
- name: Install cargo-public-api (latest)
run: |
if ! command -v cargo-public-api &> /dev/null; then
cargo install --locked cargo-public-api@=0.38.0
else
echo "cargo-public-api already installed"
fi
cargo install --locked cargo-public-api || {
echo "::warning::Failed to install cargo-public-api — skipping public API checks"
exit 0
}
Comment on lines +545 to +550
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Installing the latest cargo-public-api on every CI run without a version pin reduces reproducibility and increases supply-chain exposure (the behavior of this job can change without any repo change). If possible, pin to a known-good version (and bump intentionally), or at least centralize the version in an env var so updates are explicit and reviewable.

Copilot uses AI. Check for mistakes.

- name: Check flight-core public API
if: needs.path-filter.outputs.core == 'true'
id: check-core-api
continue-on-error: true
run: cargo public-api -p flight-core diff origin/main..HEAD

- name: Retry flight-core API check with nightly (if needed)
if: needs.path-filter.outputs.core == 'true' && steps.check-core-api.outcome == 'failure'
run: |
echo "Retrying with nightly toolchain..."
rustup toolchain install nightly
cargo +nightly public-api -p flight-core diff origin/main..HEAD
cargo +nightly public-api -p flight-core diff origin/main..HEAD 2>&1 || {
echo "::warning::flight-core public API check failed (possible rustdoc JSON format mismatch)"
}
Comment on lines +545 to +558
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If cargo install fails, the job continues but the subsequent check steps still run and will likely fail with no such command: public-api (or similar). That failure then gets reported as a possible rustdoc JSON mismatch, which is misleading. Consider setting a step output (e.g., installed=true/false) or adding a command -v cargo-public-api guard and using it in if: to skip the check steps when the install did not succeed.

Copilot uses AI. Check for mistakes.

- name: Check flight-ipc public API
if: needs.path-filter.outputs.ipc == 'true'
id: check-ipc-api
continue-on-error: true
run: cargo public-api -p flight-ipc diff origin/main..HEAD

- name: Retry flight-ipc API check with nightly (if needed)
if: needs.path-filter.outputs.ipc == 'true' && steps.check-ipc-api.outcome == 'failure'
run: |
echo "Retrying with nightly toolchain..."
rustup toolchain install nightly
cargo +nightly public-api -p flight-ipc diff origin/main..HEAD
cargo +nightly public-api -p flight-ipc diff origin/main..HEAD 2>&1 || {
echo "::warning::flight-ipc public API check failed (possible rustdoc JSON format mismatch)"
}

Comment on lines +545 to 567
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Install failure not gated 🐞 Bug ⛯ Reliability

If cargo-public-api fails to install, the workflow exits 0 from the install step but still runs
the subsequent checks, which then fail for the wrong reason and emit misleading “format mismatch”
warnings. This can fully bypass the guard while producing confusing output.
Agent Prompt
### Issue description
When `cargo install cargo-public-api` fails, later public API steps still run and produce misleading warnings.

### Issue Context
The PR intends to “gracefully install failure — emit warning and skip”. Currently it only exits 0 from the install step, not from the rest of the job.

### Fix Focus Areas
- .github/workflows/ci.yml[545-550]
- .github/workflows/ci.yml[552-574]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

- name: Check flight-hid public API
if: needs.path-filter.outputs.hid == 'true'
id: check-hid-api
continue-on-error: true
run: cargo public-api -p flight-hid diff origin/main..HEAD

- name: Retry flight-hid API check with nightly (if needed)
if: needs.path-filter.outputs.hid == 'true' && steps.check-hid-api.outcome == 'failure'
run: |
echo "Retrying with nightly toolchain..."
rustup toolchain install nightly
cargo +nightly public-api -p flight-hid diff origin/main..HEAD
cargo +nightly public-api -p flight-hid diff origin/main..HEAD 2>&1 || {
echo "::warning::flight-hid public API check failed (possible rustdoc JSON format mismatch)"
}
Comment on lines 552 to +574
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Api guard errors swallowed 🐞 Bug ✓ Correctness

The CI public API steps unconditionally convert any cargo public-api ... diff failure into a
success, so real API drift (or other errors) won’t be reflected as a failing step/check. This
undermines the job’s stated purpose of detecting unintended public API changes.
Agent Prompt
### Issue description
CI’s `public-api-check` currently masks *all* failures from `cargo public-api ... diff` as a successful step by using `|| { echo "::warning::..." }`. This makes genuine API drift indistinguishable from rustdoc JSON format incompatibilities.

### Issue Context
The PR intent is to treat known rustdoc JSON format mismatches as warnings, not to suppress true API-diff failures.

### Fix Focus Areas
- .github/workflows/ci.yml[552-574]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


gated-ipc-smoke:
name: Gated IPC Smoke Tests
Expand Down
36 changes: 28 additions & 8 deletions xtask/src/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,14 +464,18 @@ fn validate_all_front_matter(
/// If not installed, it logs a warning and returns Ok(false) to indicate the check
/// was skipped (not a failure).
///
/// If cargo-public-api fails due to a rustdoc JSON format mismatch (e.g.,
/// "invalid type: integer" errors from nightly format changes), the error is
/// treated as a warning rather than a hard failure.
///
/// For workspaces, this runs cargo public-api on each core crate individually.
///
/// # Returns
///
/// Returns:
/// - `Ok(true)` if cargo-public-api is installed and verification passed
/// - `Ok(false)` if cargo-public-api is not installed (skipped)
/// - `Err` if cargo-public-api is installed but verification failed
/// - `Ok(false)` if cargo-public-api is not installed or JSON format is incompatible (skipped)
/// - `Err` if cargo-public-api is installed but verification failed for non-format reasons
fn verify_public_api() -> Result<bool> {
// Check if cargo-public-api is installed
let check_installed = Command::new("cargo")
Expand All @@ -484,23 +488,39 @@ fn verify_public_api() -> Result<bool> {

// Run public API verification on each core crate
let mut all_passed = true;
let mut format_error = false;
for crate_name in crate::config::CORE_CRATES {
println!(" Checking {}...", crate_name);
let status = Command::new("cargo")
let output = Command::new("cargo")
.args(["public-api", "-p", crate_name])
.status()
.output()
.context(format!(
"Failed to execute cargo public-api for {}",
crate_name
))?;
Comment on lines +494 to 500
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switching from .status() to .output() captures both stdout and stderr into memory. cargo public-api output can be large, so this can increase peak memory usage unnecessarily (especially in workspaces). Since you only need stderr for format detection, consider discarding stdout (e.g., configure stdout to null) and only piping/capturing stderr.

Copilot uses AI. Check for mistakes.

if !status.success() {
eprintln!(" ✗ Public API check failed for {}", crate_name);
all_passed = false;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
if stderr.contains("invalid type: integer")
|| stderr.contains("rustdoc JSON")
|| stderr.contains("format version")
{
Comment on lines +504 to +507
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The matching for format incompatibility is quite broad (\"rustdoc JSON\" / \"format version\") and may accidentally classify unrelated failures as a format mismatch, which would downgrade real failures into warnings. Consider tightening the match to more specific phrases produced by cargo-public-api/rustdoc JSON parsing errors (or using a small regex set that targets known error lines), to reduce the chance of false positives.

Suggested change
if stderr.contains("invalid type: integer")
|| stderr.contains("rustdoc JSON")
|| stderr.contains("format version")
{
let is_format_mismatch =
stderr.contains("invalid type: integer")
|| stderr.contains("unsupported rustdoc JSON format version")
|| stderr.contains("unsupported rustdoc JSON format")
|| stderr.contains("failed to parse rustdoc JSON");
if is_format_mismatch {

Copilot uses AI. Check for mistakes.
eprintln!(
" ⚠ {} skipped: rustdoc JSON format incompatible with installed cargo-public-api",
crate_name
);
format_error = true;
} else {
eprintln!(" ✗ Public API check failed for {}", crate_name);
all_passed = false;
}
}
}

if all_passed {
if format_error && all_passed {
println!(" ⚠️ Rustdoc JSON format mismatch — upgrade cargo-public-api or pin a compatible nightly");
Ok(false)
} else if all_passed {
Ok(true)
} else {
anyhow::bail!(
Expand Down
Loading