From 5889dc03a83c3e1a296b63489fab3173b09c0c4c Mon Sep 17 00:00:00 2001 From: Nikolay Petrov Date: Wed, 21 Oct 2026 22:48:28 -0700 Subject: [PATCH] CI: add abicheck ABI scan alongside abi-compliance-checker build-quick.yml stages the ubuntu:24.04 Release install (loader and both layers) and a new advisory abicheck job compares it, as one directory, against ABI facts stored on the latest release. abicheck-baseline.yml records those facts (one zstd JSON asset, write-once) when a release is published or on dispatch. The job summary lists breaks, additions and removals per library. check-abi.yml is unchanged. Signed-off-by: Nikolay Petrov --- .github/abicheck.yml | 5 ++ .github/workflows/abicheck-baseline.yml | 71 +++++++++++++++++++ .github/workflows/build-quick.yml | 90 +++++++++++++++++++++++++ 3 files changed, 166 insertions(+) create mode 100644 .github/abicheck.yml create mode 100644 .github/workflows/abicheck-baseline.yml diff --git a/.github/abicheck.yml b/.github/abicheck.yml new file mode 100644 index 00000000..1ea4f690 --- /dev/null +++ b/.github/abicheck.yml @@ -0,0 +1,5 @@ +# Trusted abicheck config, passed explicitly (build-config) by the abicheck +# jobs. The stored release baseline (v1.34.0: 133 MB of JSON, about 5M nodes +# counting keys and scalars) is above abicheck's default decode ceiling of 1M. +resource_limits: + max_bundle_facts_decode_nodes: 12000000 diff --git a/.github/workflows/abicheck-baseline.yml b/.github/workflows/abicheck-baseline.yml new file mode 100644 index 00000000..243b4d6d --- /dev/null +++ b/.github/workflows/abicheck-baseline.yml @@ -0,0 +1,71 @@ +on: + release: + types: [published] + workflow_dispatch: + inputs: + tag: + description: Existing release tag to attach the abicheck baseline to + required: true + +permissions: read-all + +defaults: + run: + shell: bash + +# Stores the ABI facts of a release (loader + both layers, one zstd JSON +# asset, about 1.4 MB) so build-quick.yml compares PRs against the shipped +# ABI without rebuilding the tag. Built with the same Release flags and +# Ubuntu 24.04 toolchain as build-quick.yml's ubuntu:24.04 leg. Write-once: a re-run never replaces the asset; to +# re-baseline, delete it deliberately first. + +jobs: + baseline: + if: github.repository_owner == 'oneapi-src' + runs-on: ubuntu-24.04 + permissions: + contents: write + env: + TAG: ${{ github.event.release.tag_name || inputs.tag }} + ASSET: level-zero.abicheck-bundle.json.zst + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ env.TAG }} + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + path: cfg + sparse-checkout: .github + - name: Build and stage ${{ env.TAG }} + run: | + cmake -B build -D CMAKE_BUILD_TYPE=Release + cmake --build build -j$(nproc) + cmake --install build --prefix "$PWD/abi-inst" + mkdir -p abi/lib + cp -a abi-inst/include abi/ + cp -a abi-inst/lib/libze_loader.so* abi-inst/lib/libze_validation_layer.so* abi-inst/lib/libze_tracing_layer.so* abi/lib/ + - name: Record facts + uses: abicheck/abicheck@9ce5f169d5c5164be9812d61337ba4e712e3ab69 # main 2026-10-21; keep in sync with build-quick.yml + with: + old-library: abi + new-library: abi + old-header: abi/include/level_zero + new-header: abi/include/level_zero + old-version: ${{ env.TAG }} + new-version: ${{ env.TAG }} + build-config: cfg/.github/abicheck.yml + python-version: '3.15t' + extra-args: --bundle-facts-out level-zero.abicheck-bundle.json + pr-comment: 'false' + fail-on-breaking: 'false' + fail-on-api-break: 'false' + - name: Attach to release (write-once) + env: + GH_TOKEN: ${{ github.token }} + run: | + zstd -q -19 -T0 level-zero.abicheck-bundle.json -o "$ASSET" + if gh release view "$TAG" --json assets -q '.assets[].name' | grep -Fxq "$ASSET"; then + echo "::error::$ASSET already exists on $TAG. The baseline is write-once; delete it deliberately (gh release delete-asset $TAG $ASSET) to re-baseline." >&2 + exit 1 + fi + gh release upload "$TAG" "$ASSET" diff --git a/.github/workflows/build-quick.yml b/.github/workflows/build-quick.yml index a7234323..951c850d 100644 --- a/.github/workflows/build-quick.yml +++ b/.github/workflows/build-quick.yml @@ -46,6 +46,20 @@ jobs: ZEL_LIBRARY_PATH: '${{ github.workspace }}/build/lib' working-directory: build run: ctest -V + - name: Stage libraries and headers for abicheck + if: matrix.container == 'ubuntu:24.04' + run: | + cmake --install build --prefix "$PWD/abi-inst" + # Only the shipped loader and layers; not the NULL test driver. + mkdir -p abi/lib + cp -a abi-inst/include abi/ + cp -a abi-inst/lib/libze_loader.so* abi-inst/lib/libze_validation_layer.so* abi-inst/lib/libze_tracing_layer.so* abi/lib/ + - if: matrix.container == 'ubuntu:24.04' + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: abicheck-inst + path: abi + retention-days: 3 - name: Install loader and NULL driver working-directory: build run: make install @@ -67,6 +81,82 @@ jobs: working-directory: build run: make uninstall || xargs rm -v < install_manifest.txt + # Advisory ABI scan with https://github.com/abicheck/abicheck, next to + # check-abi.yml. Compares the ubuntu:24.04 build above, as one directory + # (loader + both layers), against the facts that abicheck-baseline.yml + # stored on the latest release. Reports breaks, additions and removals; + # never fails the PR. + abicheck: + needs: build-linux + if: github.repository_owner == 'oneapi-src' && github.event_name == 'pull_request' + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + sparse-checkout: .github + - uses: actions-ecosystem/action-get-latest-tag@b7c32daec3395a9616f88548363a42652b22d435 # v1.6.0 + id: tag + with: + semver_only: true + - name: Fetch stored baseline of ${{ steps.tag.outputs.tag }} + id: baseline + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ steps.tag.outputs.tag }} + run: | + if gh release download "$TAG" -R "$GITHUB_REPOSITORY" -p level-zero.abicheck-bundle.json.zst; then + echo "found=true" >> "$GITHUB_OUTPUT" + else + echo "Release $TAG has no level-zero.abicheck-bundle.json.zst; run abicheck-baseline.yml with tag=$TAG to attach it." >> "$GITHUB_STEP_SUMMARY" + fi + - if: steps.baseline.outputs.found == 'true' + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + with: + name: abicheck-inst + path: new + - name: abicheck vs ${{ steps.tag.outputs.tag }} + if: steps.baseline.outputs.found == 'true' + id: abicheck + uses: abicheck/abicheck@9ce5f169d5c5164be9812d61337ba4e712e3ab69 # main 2026-10-21; keep in sync with abicheck-baseline.yml + with: + old-library: level-zero.abicheck-bundle.json.zst + new-library: new + new-header: new/include/level_zero + new-version: ${{ github.event.pull_request.head.sha }} + build-config: .github/abicheck.yml + python-version: '3.15t' + extra-args: -o markdown=abicheck.md -o json=abicheck.json + annotate: 'true' + annotate-additions: 'true' + pr-comment: 'false' + fail-on-breaking: 'false' + fail-on-api-break: 'false' + - name: Job summary + if: always() && steps.baseline.outputs.found == 'true' + # Counts and symbol lists come from the JSON report: the directory + # markdown has no added/removed columns yet (abicheck/abicheck#1706). + run: | + [ -f abicheck.json ] || exit 0 + jq -r ' + "## abicheck: additions, removals and breaks per library", "", + "| Library | Verdict | Breaking | Added | Removed | Changed |", "|---|---|---|---|---|---|", + (.libraries | to_entries[] | .value.result_counts as $c + | "| \(.key) | `\(.value.verdict)` | \($c.gating) | \($c.public_additions) | \($c.public_removals) | \($c.public_modifications) |"), + "", + (.libraries | to_entries[] | .key as $lib | .value.changes as $ch + | ("removed", "added") as $k + | [$ch[] | select(.kind | endswith("_" + $k)) | .symbol | select(startswith("__abicheck_") | not)] | unique + | select(length > 0) + | "
\($lib): \($k) (\(length))\n\n" + (map("- `\(.)`") | join("\n")) + "\n
\n") + ' abicheck.json >> "$GITHUB_STEP_SUMMARY" + { echo "
Full abicheck report"; echo; cat abicheck.md; echo "
"; } >> "$GITHUB_STEP_SUMMARY" + - if: always() && steps.baseline.outputs.found == 'true' + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: abicheck-report + path: abicheck.* + build-windows: if: github.repository_owner == 'oneapi-src' runs-on: [windows-latest]