Release smoke test #21
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release smoke test | |
| # Verifies a PUBLISHED release on Maven Central actually loads and runs on every | |
| # supported OS/arch — one runner per native classifier. Pulls the release jars | |
| # from Central (no source build, no submodule, no zig), so it tests exactly what | |
| # users consume. Trigger manually and pass the version to check. | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: Version to smoke-test. Leave blank to use the latest release on Maven Central. | |
| required: false | |
| default: "" | |
| schedule: | |
| # Weekly, Mondays 06:00 UTC. No input on scheduled runs, so the resolve job | |
| # picks the latest release on Maven Central — catches Central / runner-image | |
| # drift against the published release without a manual trigger. | |
| - cron: "0 6 * * 1" | |
| jobs: | |
| resolve: | |
| name: resolve version | |
| runs-on: ubuntu-latest | |
| permissions: {} | |
| outputs: | |
| version: ${{ steps.pick.outputs.version }} | |
| steps: | |
| - name: Resolve version (input, else latest on Maven Central) | |
| id: pick | |
| shell: bash | |
| env: | |
| INPUT_VERSION: ${{ inputs.version }} | |
| run: | | |
| version="$INPUT_VERSION" | |
| if [ -z "$version" ]; then | |
| # <release> in maven-metadata.xml is the latest non-snapshot release. | |
| version=$(curl -fsSL --proto '=https' --tlsv1.2 https://repo1.maven.org/maven2/io/github/dfa1/zstd/zstd/maven-metadata.xml \ | |
| | grep -oE '<release>[^<]+</release>' | sed -E 's/<\/?release>//g') | |
| fi | |
| if [ -z "$version" ]; then | |
| echo "could not resolve a version from Maven Central" >&2 | |
| exit 1 | |
| fi | |
| echo "Smoke-testing version: $version" | |
| echo "version=$version" >> "$GITHUB_OUTPUT" | |
| smoke: | |
| name: ${{ matrix.classifier }}${{ matrix.label && format(' ({0})', matrix.label) || '' }} | |
| needs: resolve | |
| # Every leg gates the workflow, including the 8 container legs — the | |
| # library claims to be portable across distros/libcs, so a failure on any | |
| # of them is a real regression, not a shrug. | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| # distribution is per-leg for clarity and easy override. Zulu ships JDK 25 | |
| # for all targets (incl. Windows/ARM64, which Temurin does not yet) and | |
| # matches publish.yml. Legs with `container` run the linux native inside a | |
| # container to check compatibility on other distributions and libcs. | |
| include: | |
| - { os: ubuntu-latest, classifier: linux-x86_64, distribution: zulu } | |
| - { os: ubuntu-24.04-arm, classifier: linux-aarch64, distribution: zulu } | |
| - { os: macos-14, classifier: osx-aarch64, distribution: zulu } | |
| - { os: windows-latest, classifier: windows-x86_64, distribution: zulu } | |
| - { os: windows-11-arm, classifier: windows-aarch64, distribution: zulu } | |
| # musl (Alpine) — glibc natives on a musl libc | |
| - { os: ubuntu-latest, classifier: linux-x86_64, distribution: zulu, container: "amazoncorretto:25-alpine", label: musl } | |
| - { os: ubuntu-24.04-arm, classifier: linux-aarch64, distribution: zulu, container: "amazoncorretto:25-alpine", label: musl } | |
| # Ubuntu 22.04 (Jammy) — glibc 2.35; eclipse-temurin has no bookworm tag for JDK 25 | |
| - { os: ubuntu-latest, classifier: linux-x86_64, distribution: zulu, container: "eclipse-temurin:25-jdk-jammy", label: jammy } | |
| - { os: ubuntu-24.04-arm, classifier: linux-aarch64, distribution: zulu, container: "eclipse-temurin:25-jdk-jammy", label: jammy } | |
| # Red Hat UBI 10 minimal — glibc 2.34 (RHEL-like) | |
| - { os: ubuntu-latest, classifier: linux-x86_64, distribution: zulu, container: "eclipse-temurin:25-jdk-ubi10-minimal", label: ubi } | |
| - { os: ubuntu-24.04-arm, classifier: linux-aarch64, distribution: zulu, container: "eclipse-temurin:25-jdk-ubi10-minimal", label: ubi } | |
| # Amazon Linux 2023 (RHEL-like) — glibc 2.34 | |
| - { os: ubuntu-latest, classifier: linux-x86_64, distribution: zulu, container: "amazoncorretto:25-al2023", label: al2023 } | |
| - { os: ubuntu-24.04-arm, classifier: linux-aarch64, distribution: zulu, container: "amazoncorretto:25-al2023", label: al2023 } | |
| runs-on: ${{ matrix.os }} | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout (smoke sources only) | |
| uses: actions/checkout@v7 | |
| # Host JDK is only needed for the native runner path — the container | |
| # path runs its own build entirely inside the target image (see below). | |
| - name: Set up JDK 25 (host) | |
| if: ${{ !matrix.container }} | |
| uses: actions/setup-java@v5 | |
| with: | |
| distribution: ${{ matrix.distribution }} | |
| java-version: '25' | |
| # --- native runner path (glibc / macOS / Windows): a real `mvn test` | |
| # against .github/smoke/pom.xml (JUnit 5 via Surefire), via the | |
| # vendored Maven Wrapper so no preinstalled Maven is required. | |
| # -Dzstd.version and -Dzstd.classifier pin the release and native | |
| # jar under test. --- | |
| - name: Smoke-test ${{ needs.resolve.outputs.version }} on ${{ matrix.classifier }} | |
| if: ${{ !matrix.container }} | |
| shell: bash | |
| env: | |
| VERSION: ${{ needs.resolve.outputs.version }} | |
| run: | | |
| sh .github/smoke/mvnw -f .github/smoke/pom.xml --no-transfer-progress \ | |
| -Dzstd.version="$VERSION" -Dzstd.classifier=${{ matrix.classifier }} \ | |
| test | |
| # --- container leg: extraction needs unzip, which some minimal images | |
| # (al2023) ship without any package manager at all to install it | |
| # with. Sidestep that entirely: extract Maven once on the host | |
| # (ubuntu-latest always has curl+unzip) from the same pinned | |
| # distributionUrl the wrapper uses, then mount it read-only into the | |
| # container. The container only needs its own `java` on PATH — no | |
| # unzip/tar/package manager required inside it at all. --- | |
| - name: Extract Maven (host, mounted read-only into the container) | |
| if: ${{ matrix.container }} | |
| shell: bash | |
| run: | | |
| distributionUrl=$(sed -n 's/^distributionUrl=//p' .github/smoke/.mvn/wrapper/maven-wrapper.properties) | |
| curl -fsSL --proto '=https' --tlsv1.2 "$distributionUrl" -o "$RUNNER_TEMP/maven.zip" | |
| unzip -q "$RUNNER_TEMP/maven.zip" -d "$RUNNER_TEMP/maven-extract" | |
| mv "$RUNNER_TEMP"/maven-extract/apache-maven-*/ "$RUNNER_TEMP/maven" | |
| # The same Maven build runs *inside* the target container (its own JDK, | |
| # no host JDK involved), so dependency resolution, compilation, and | |
| # native-lib loading all happen under that distro's libc. Only | |
| # `docker run` itself, plus the Maven extraction above, run on the host. | |
| - name: Smoke-test ${{ needs.resolve.outputs.version }} on ${{ matrix.classifier }} (${{ matrix.label }}) | |
| if: ${{ matrix.container }} | |
| shell: bash | |
| env: | |
| VERSION: ${{ needs.resolve.outputs.version }} | |
| run: | | |
| docker run --rm -v "$PWD:/w" -v "$RUNNER_TEMP/maven:/opt/maven:ro" -w /w "${{ matrix.container }}" \ | |
| /opt/maven/bin/mvn -f .github/smoke/pom.xml --no-transfer-progress \ | |
| -Dzstd.version="$VERSION" -Dzstd.classifier=${{ matrix.classifier }} \ | |
| test | |
| results: | |
| name: results | |
| needs: [resolve, smoke] | |
| if: always() | |
| runs-on: ubuntu-latest | |
| permissions: | |
| actions: read | |
| steps: | |
| # Per-leg results aren't visible to a needs-context (needs.smoke.result is | |
| # one aggregate string for the whole matrix), so pull the real per-job | |
| # conclusions from the Actions API and render one table up front instead | |
| # of making readers open all 13 jobs to see what actually passed. | |
| - name: Build results table | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| jobs=$(gh api "repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/jobs?per_page=100" \ | |
| --jq '[.jobs[] | select(.name != "resolve version" and .name != "results")]') | |
| { | |
| echo "### Release smoke — version ${{ needs.resolve.outputs.version }}" | |
| echo | |
| echo "Every host below gates the workflow — a failure on any one of them is a real portability regression." | |
| echo | |
| echo "| Host | Result | Duration |" | |
| echo "|---|---|---|" | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| echo "$jobs" | jq -r '.[] | | |
| (if .conclusion == "success" then "✅ pass" | |
| elif .conclusion == "skipped" then "⏭️ skipped" | |
| else "❌ **" + (.conclusion // "unknown") + "**" end) as $result | | |
| (((.completed_at | fromdateiso8601) - (.started_at | fromdateiso8601))) as $dur | | |
| (($dur / 60) | floor) as $m | ($dur % 60) as $s | | |
| (if $m > 0 then ($m | tostring) + "m " + ($s | tostring) + "s" else ($s | tostring) + "s" end) as $duration | | |
| "| " + .name + " | " + $result + " | " + $duration + " |"' >> "$GITHUB_STEP_SUMMARY" | |
| total=$(echo "$jobs" | jq 'length') | |
| pass=$(echo "$jobs" | jq '[.[] | select(.conclusion == "success")] | length') | |
| { | |
| echo | |
| echo "**$pass/$total passed**" | |
| } >> "$GITHUB_STEP_SUMMARY" |