From ee6de7d7866768f23097a4b3b1eeaa1dce091e90 Mon Sep 17 00:00:00 2001 From: hector <42570491+majinghe@users.noreply.github.com> Date: Wed, 23 Sep 2026 11:17:47 +0800 Subject: [PATCH] ci(package): build gnu and musl DEB/RPM variants with distinct file names (#8079) * ci(package): build gnu and musl DEB/RPM variants with distinct file names The Build and Release workflow produces four Linux binaries (x86_64-gnu, aarch64-gnu, x86_64-musl, aarch64-musl), but packaging only consumed the two gnu artifacts. Add matrix entries for the two musl artifacts so every release ships all four DEB/RPM variants. The libc variant is now part of the package file names, which would otherwise collide between gnu and musl builds of the same version: - deb: rustfs___.deb - rpm: rustfs---..rpm The dpkg Package and rpm Name stay plain "rustfs", so gnu and musl remain mutually exclusive upgrades of one package rather than co-installable packages fighting over /usr/bin/rustfs. Dependency declarations now follow the linkage: gnu binaries dynamically link glibc and keep Depends: libc6 (>= 2.31) / glibc >= 2.31; musl binaries are statically linked and declare no libc dependency. The libc variant is also visible in the package description. scripts/release/package_versions.sh gains a LIBC argument and its contract tests cover both variants plus the invalid-libc cases. * ci(package): align deb/rpm file names with the zip artifact naming Rename the package file names so every release asset of one build shares the same stem as its binary artifact, differing only by extension: - before: rustfs___.deb rustfs---..rpm - after: rustfs-linux---v.deb / .rpm e.g. rustfs-linux-x86_64-gnu-v1.0.0.zip, rustfs-linux-x86_64-gnu-v1.0.0.deb, rustfs-linux-x86_64-gnu-v1.0.0.rpm. Non-development builds embed the raw release tag (with 'v'), like the zips; development builds embed dev-. The dpkg/rpm versions (including the '~' prerelease ordering) are unchanged - they live in the package metadata, and a side effect is that release asset names no longer contain '~' (which GitHub normalizes to '.'). package_versions.sh now takes the target arch (x86_64|aarch64) instead of the deb/rpm arch pair; the deb Architecture (amd64/arm64) in the control metadata still comes from the workflow matrix. The two test workflows that assemble deb download URLs from a release tag (rustfs-table-test, rustfs-upgrade-test) are updated to the new name, which also removes their '~'-to-'.' asset name workaround. --- .github/workflows/package.yml | 79 ++++++++++++---- .github/workflows/rustfs-table-test.yml | 2 +- .github/workflows/rustfs-upgrade-test.yml | 2 +- scripts/release/package_versions.sh | 41 +++++++-- scripts/test_package_versions.sh | 106 ++++++++++++---------- 5 files changed, 155 insertions(+), 75 deletions(-) diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index faa46ed64..cbcc2b88e 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -25,9 +25,10 @@ # # Flow: # 1. Resolve and validate the selected Build workflow run and source identity -# 2. Download Linux binaries (x86_64-gnu, aarch64-gnu) from build artifacts -# 3. Build DEB packages for amd64 and arm64 -# 4. Build RPM packages for x86_64 and aarch64 +# 2. Download Linux binaries (x86_64-gnu, aarch64-gnu, x86_64-musl, +# aarch64-musl) from build artifacts +# 3. Build DEB packages for amd64 and arm64, gnu and musl variants +# 4. Build RPM packages for x86_64 and aarch64, gnu and musl variants # 5. Upload all packages to Cloudflare R2 and the GitHub release name: Package DEB/RPM @@ -224,9 +225,9 @@ jobs: echo " Build run ID: $BUILD_RUN_ID" echo " Build run number: $RUN_NUMBER" - # Build DEB and RPM packages for each architecture + # Build DEB and RPM packages for each architecture and libc variant package: - name: Package (${{ matrix.arch }}) + name: Package (${{ matrix.arch }}-${{ matrix.libc }}) needs: resolve runs-on: ubuntu-latest timeout-minutes: 30 @@ -236,13 +237,35 @@ jobs: matrix: include: - arch: x86_64 + libc: gnu deb_arch: amd64 rpm_arch: x86_64 artifact_name: "rustfs-linux-x86_64-gnu" + # gnu binaries dynamically link glibc; musl binaries are static + # and run without a libc dependency. + deb_depends: "libc6 (>= 2.31)" + rpm_depends: "glibc >= 2.31" - arch: aarch64 + libc: gnu deb_arch: arm64 rpm_arch: aarch64 artifact_name: "rustfs-linux-aarch64-gnu" + deb_depends: "libc6 (>= 2.31)" + rpm_depends: "glibc >= 2.31" + - arch: x86_64 + libc: musl + deb_arch: amd64 + rpm_arch: x86_64 + artifact_name: "rustfs-linux-x86_64-musl" + deb_depends: "" + rpm_depends: "" + - arch: aarch64 + libc: musl + deb_arch: arm64 + rpm_arch: aarch64 + artifact_name: "rustfs-linux-aarch64-musl" + deb_depends: "" + rpm_depends: "" steps: - name: Checkout repository uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 @@ -256,13 +279,13 @@ jobs: BUILD_TYPE: ${{ needs.resolve.outputs.build_type }} SOURCE_VERSION: ${{ needs.resolve.outputs.version }} DEV_SEQUENCE: ${{ needs.resolve.outputs.dev_sequence }} - DEB_ARCH: ${{ matrix.deb_arch }} - RPM_ARCH: ${{ matrix.rpm_arch }} + ARCH: ${{ matrix.rpm_arch }} + LIBC: ${{ matrix.libc }} run: | set -euo pipefail normalized=$(./scripts/release/package_versions.sh \ - "$BUILD_TYPE" "$SOURCE_VERSION" "$DEV_SEQUENCE" "$DEB_ARCH" "$RPM_ARCH") + "$BUILD_TYPE" "$SOURCE_VERSION" "$DEV_SEQUENCE" "$ARCH" "$LIBC") printf '%s\n' "$normalized" >> "$GITHUB_OUTPUT" - name: Download binary artifact from build run @@ -308,6 +331,8 @@ jobs: DEB_VERSION: ${{ steps.versions.outputs.deb_version }} DEB_ARCH: ${{ matrix.deb_arch }} DEB_FILE: ${{ steps.versions.outputs.deb_file }} + DEB_DEPENDS: ${{ matrix.deb_depends }} + LIBC: ${{ matrix.libc }} run: | set -euo pipefail @@ -345,9 +370,17 @@ jobs: Section: utils Priority: optional Architecture: ${DEB_ARCH} - Depends: libc6 (>= 2.31) + EOF + + # gnu binaries dynamically link glibc and must declare it; musl + # binaries are statically linked and need no libc dependency. + if [[ -n "$DEB_DEPENDS" ]]; then + echo "Depends: ${DEB_DEPENDS}" >> "${PKG_DIR}/DEBIAN/control" + fi + + cat >> "${PKG_DIR}/DEBIAN/control" << EOF Maintainer: RustFS Team - Description: High-performance distributed object storage + Description: High-performance distributed object storage (${LIBC} build) RustFS is a high-performance distributed object storage software built using Rust. It is compatible with MinIO and S3 API. Homepage: https://rustfs.com @@ -389,15 +422,24 @@ jobs: RPM_RELEASE: ${{ steps.versions.outputs.rpm_release }} RPM_ARCH: ${{ matrix.rpm_arch }} RPM_FILE: ${{ steps.versions.outputs.rpm_file }} + RPM_DEPENDS: ${{ matrix.rpm_depends }} + LIBC: ${{ matrix.libc }} run: | set -euo pipefail - echo "Building RPM for ${RPM_ARCH}" + echo "Building RPM for ${RPM_ARCH} (${LIBC})" sudo apt-get update && sudo apt-get install -y ruby ruby-dev build-essential rpm sudo gem install fpm ./scripts/test_package_versions.sh --require-package-managers + # gnu binaries dynamically link glibc and must declare it; musl + # binaries are statically linked and need no libc dependency. + depends_args=() + if [[ -n "$RPM_DEPENDS" ]]; then + depends_args+=(--depends "$RPM_DEPENDS") + fi + # Create config file for fpm (DEB build creates it in its package dir structure, # but fpm needs the file to exist before packaging) mkdir -p ./tmp-pkg/etc/default @@ -420,9 +462,9 @@ jobs: --iteration "$RPM_RELEASE" \ --architecture "$RPM_ARCH" \ --package "$RPM_FILE" \ - --depends "glibc >= 2.31" \ + "${depends_args[@]}" \ + --description "High-performance distributed object storage (${LIBC} build)" \ --maintainer "RustFS Team " \ - --description "High-performance distributed object storage" \ --url "https://rustfs.com" \ --license "Apache-2.0" \ --before-install <(./scripts/release/package_service_scripts.sh rpm-before-install) \ @@ -455,7 +497,7 @@ jobs: - name: Upload packages to artifacts uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: - name: packages-${{ matrix.arch }} + name: packages-${{ matrix.arch }}-${{ matrix.libc }} path: | *.deb *.rpm @@ -551,10 +593,11 @@ jobs: for f in "$DEB_FILE" "$RPM_FILE"; do if [[ -n "$f" && -f "$f" ]]; then base="$(basename "$f")" - # GitHub stores release asset names with '~' normalized to '.' - # (e.g. rustfs_1.0.0~rc.2_amd64.deb is stored as - # rustfs_1.0.0.rc.2_amd64.deb), so checksum entries must - # reference the name as stored on the release. + # GitHub stores release asset names with '~' normalized to '.'. + # Current package file names embed the raw tag and contain no + # '~', but older releases may still ship such assets, so the + # checksum entries must reference the name as stored on the + # release. github_base="${base//\~/.}" # Remove any stale entry (both naming variants), then append grep -Fv -- "$base" "$checksum_file" > "${checksum_file}.tmp" || true diff --git a/.github/workflows/rustfs-table-test.yml b/.github/workflows/rustfs-table-test.yml index 41185565b..a45b6963d 100644 --- a/.github/workflows/rustfs-table-test.yml +++ b/.github/workflows/rustfs-table-test.yml @@ -133,7 +133,7 @@ jobs: if [ -n "${PACKAGE_URL}" ]; then ARGS+=(--package-url "${PACKAGE_URL}") elif [ -n "${RUSTFS_VERSION}" ] && [ "${RUSTFS_VERSION}" != "null" ]; then - ARGS+=(--package-url "https://github.com/rustfs/rustfs/releases/download/${RUSTFS_VERSION}/rustfs_${RUSTFS_VERSION}_amd64.deb") + ARGS+=(--package-url "https://github.com/rustfs/rustfs/releases/download/${RUSTFS_VERSION}/rustfs-linux-x86_64-gnu-v${RUSTFS_VERSION}.deb") else ARGS+=(--package-url "${RUSTFS_NIGHTLY_PACKAGE_URL}") fi diff --git a/.github/workflows/rustfs-upgrade-test.yml b/.github/workflows/rustfs-upgrade-test.yml index 8c74ce845..caa63d89c 100644 --- a/.github/workflows/rustfs-upgrade-test.yml +++ b/.github/workflows/rustfs-upgrade-test.yml @@ -207,7 +207,7 @@ jobs: local version="$1" tag asset url [ -n "${version}" ] && [ "${version}" != "null" ] || return 0 tag="${version#v}" - asset="rustfs_${tag//-/.}_amd64.deb" + asset="rustfs-linux-x86_64-gnu-v${tag}.deb" url="https://github.com/rustfs/rustfs/releases/download/${tag}/${asset}" if ! gh api "repos/rustfs/rustfs/releases/tags/${tag}" --jq '.assets[].name' 2>/dev/null | grep -qxF "${asset}"; then echo "ERROR: release ${tag} has no downloadable asset ${asset}:" >&2 diff --git a/scripts/release/package_versions.sh b/scripts/release/package_versions.sh index e265cfbef..322f95dbc 100755 --- a/scripts/release/package_versions.sh +++ b/scripts/release/package_versions.sh @@ -21,18 +21,28 @@ fail() { } if [[ $# -ne 5 ]]; then - fail "expected BUILD_TYPE SOURCE_VERSION DEV_SEQUENCE DEB_ARCH RPM_ARCH" + fail "expected BUILD_TYPE SOURCE_VERSION DEV_SEQUENCE ARCH LIBC" fi build_type=$1 source_version=$2 dev_sequence=$3 -deb_arch=$4 -rpm_arch=$5 +arch=$4 +libc=$5 -case "${deb_arch}:${rpm_arch}" in - amd64:x86_64 | arm64:aarch64) ;; - *) fail "unsupported or mismatched architecture pair" ;; +case "$arch" in + x86_64 | aarch64) ;; + *) fail "unsupported architecture (expected x86_64 or aarch64)" ;; +esac + +# The libc variant of the binary being packaged. It only distinguishes the +# package FILE names (gnu and musl builds of the same version would otherwise +# collide on the release); the dpkg/rpm package identity stays plain "rustfs" +# so the two variants remain mutually exclusive upgrades, not co-installable +# packages. +case "$libc" in + gnu | musl) ;; + *) fail "unsupported libc variant (expected gnu or musl)" ;; esac semver_core='(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)' @@ -89,8 +99,23 @@ case "$build_type" in *) fail "unsupported build type" ;; esac -deb_file="rustfs_${deb_version}_${deb_arch}.deb" -rpm_file="rustfs-${rpm_version}-${rpm_release}.${rpm_arch}.rpm" +# Package file names mirror the binary artifact names, whose zips are named +# rustfs-linux---.zip: all release assets of one build +# share the same stem and differ only by extension. Non-development builds +# embed the raw release tag after the 'v' marker exactly like the zips; +# development builds embed dev- (zips use the short SHA, packages the +# full one). The dpkg/rpm versions with their '~' prerelease ordering live +# in the package metadata above and are independent of the file name. +case "$build_type" in + development) + package_stem="rustfs-linux-${arch}-${libc}-dev-${source_sha}" + ;; + *) + package_stem="rustfs-linux-${arch}-${libc}-v${source_version}" + ;; +esac +deb_file="${package_stem}.deb" +rpm_file="${package_stem}.rpm" # Emit only after every input and derived value has been validated. Consumers # may append this fixed five-line protocol directly to GITHUB_OUTPUT. diff --git a/scripts/test_package_versions.sh b/scripts/test_package_versions.sh index a847de815..3573f0620 100755 --- a/scripts/test_package_versions.sh +++ b/scripts/test_package_versions.sh @@ -70,61 +70,73 @@ run_failure() { sha=0123456789abcdef0123456789abcdef01234567 -run_success stable-amd64 \ - $'deb_version=1.2.3\nrpm_version=1.2.3\nrpm_release=1\ndeb_file=rustfs_1.2.3_amd64.deb\nrpm_file=rustfs-1.2.3-1.x86_64.rpm' \ - release 1.2.3 '' amd64 x86_64 -run_success alpha-arm64 \ - $'deb_version=1.2.3~alpha.1\nrpm_version=1.2.3~alpha.1\nrpm_release=1\ndeb_file=rustfs_1.2.3~alpha.1_arm64.deb\nrpm_file=rustfs-1.2.3~alpha.1-1.aarch64.rpm' \ - prerelease 1.2.3-alpha.1 '' arm64 aarch64 -run_success beta-amd64 \ - $'deb_version=1.2.3~beta.2\nrpm_version=1.2.3~beta.2\nrpm_release=1\ndeb_file=rustfs_1.2.3~beta.2_amd64.deb\nrpm_file=rustfs-1.2.3~beta.2-1.x86_64.rpm' \ - prerelease 1.2.3-beta.2 '' amd64 x86_64 -run_success rc-amd64 \ - $'deb_version=1.2.3~rc.4\nrpm_version=1.2.3~rc.4\nrpm_release=1\ndeb_file=rustfs_1.2.3~rc.4_amd64.deb\nrpm_file=rustfs-1.2.3~rc.4-1.x86_64.rpm' \ - prerelease 1.2.3-rc.4 '' amd64 x86_64 -run_success preview-amd64 \ - $'deb_version=1.0.0~rc.5~preview.2\nrpm_version=1.0.0~rc.5~preview.2\nrpm_release=1\ndeb_file=rustfs_1.0.0~rc.5~preview.2_amd64.deb\nrpm_file=rustfs-1.0.0~rc.5~preview.2-1.x86_64.rpm' \ - preview 1.0.0-rc.5-preview.2 '' amd64 x86_64 -run_success development-amd64 \ +run_success stable-x86_64-gnu \ + $'deb_version=1.2.3\nrpm_version=1.2.3\nrpm_release=1\ndeb_file=rustfs-linux-x86_64-gnu-v1.2.3.deb\nrpm_file=rustfs-linux-x86_64-gnu-v1.2.3.rpm' \ + release 1.2.3 '' x86_64 gnu +run_success stable-x86_64-musl \ + $'deb_version=1.2.3\nrpm_version=1.2.3\nrpm_release=1\ndeb_file=rustfs-linux-x86_64-musl-v1.2.3.deb\nrpm_file=rustfs-linux-x86_64-musl-v1.2.3.rpm' \ + release 1.2.3 '' x86_64 musl +run_success alpha-aarch64-gnu \ + $'deb_version=1.2.3~alpha.1\nrpm_version=1.2.3~alpha.1\nrpm_release=1\ndeb_file=rustfs-linux-aarch64-gnu-v1.2.3-alpha.1.deb\nrpm_file=rustfs-linux-aarch64-gnu-v1.2.3-alpha.1.rpm' \ + prerelease 1.2.3-alpha.1 '' aarch64 gnu +run_success alpha-aarch64-musl \ + $'deb_version=1.2.3~alpha.1\nrpm_version=1.2.3~alpha.1\nrpm_release=1\ndeb_file=rustfs-linux-aarch64-musl-v1.2.3-alpha.1.deb\nrpm_file=rustfs-linux-aarch64-musl-v1.2.3-alpha.1.rpm' \ + prerelease 1.2.3-alpha.1 '' aarch64 musl +run_success beta-x86_64-gnu \ + $'deb_version=1.2.3~beta.2\nrpm_version=1.2.3~beta.2\nrpm_release=1\ndeb_file=rustfs-linux-x86_64-gnu-v1.2.3-beta.2.deb\nrpm_file=rustfs-linux-x86_64-gnu-v1.2.3-beta.2.rpm' \ + prerelease 1.2.3-beta.2 '' x86_64 gnu +run_success rc-x86_64-musl \ + $'deb_version=1.2.3~rc.4\nrpm_version=1.2.3~rc.4\nrpm_release=1\ndeb_file=rustfs-linux-x86_64-musl-v1.2.3-rc.4.deb\nrpm_file=rustfs-linux-x86_64-musl-v1.2.3-rc.4.rpm' \ + prerelease 1.2.3-rc.4 '' x86_64 musl +run_success preview-x86_64-gnu \ + $'deb_version=1.0.0~rc.5~preview.2\nrpm_version=1.0.0~rc.5~preview.2\nrpm_release=1\ndeb_file=rustfs-linux-x86_64-gnu-v1.0.0-rc.5-preview.2.deb\nrpm_file=rustfs-linux-x86_64-gnu-v1.0.0-rc.5-preview.2.rpm' \ + preview 1.0.0-rc.5-preview.2 '' x86_64 gnu +run_success preview-aarch64-musl \ + $'deb_version=1.0.0~rc.5~preview.2\nrpm_version=1.0.0~rc.5~preview.2\nrpm_release=1\ndeb_file=rustfs-linux-aarch64-musl-v1.0.0-rc.5-preview.2.deb\nrpm_file=rustfs-linux-aarch64-musl-v1.0.0-rc.5-preview.2.rpm' \ + preview 1.0.0-rc.5-preview.2 '' aarch64 musl +run_success development-x86_64-gnu \ "deb_version=0~dev.7463.${sha} rpm_version=0 rpm_release=0.dev.7463.${sha} -deb_file=rustfs_0~dev.7463.${sha}_amd64.deb -rpm_file=rustfs-0-0.dev.7463.${sha}.x86_64.rpm" \ - development "dev-${sha}" 7463 amd64 x86_64 -run_success development-arm64 \ +deb_file=rustfs-linux-x86_64-gnu-dev-${sha}.deb +rpm_file=rustfs-linux-x86_64-gnu-dev-${sha}.rpm" \ + development "dev-${sha}" 7463 x86_64 gnu +run_success development-aarch64-musl \ "deb_version=0~dev.7463.${sha} rpm_version=0 rpm_release=0.dev.7463.${sha} -deb_file=rustfs_0~dev.7463.${sha}_arm64.deb -rpm_file=rustfs-0-0.dev.7463.${sha}.aarch64.rpm" \ - development "dev-${sha}" 7463 arm64 aarch64 +deb_file=rustfs-linux-aarch64-musl-dev-${sha}.deb +rpm_file=rustfs-linux-aarch64-musl-dev-${sha}.rpm" \ + development "dev-${sha}" 7463 aarch64 musl run_failure missing-arguments -run_failure empty-build-type '' 1.2.3 '' amd64 x86_64 -run_failure unknown-build-type nightly 1.2.3 '' amd64 x86_64 -run_failure empty-version release '' '' amd64 x86_64 -run_failure release-with-sequence release 1.2.3 1 amd64 x86_64 -run_failure release-prerelease-mismatch release 1.2.3-rc.1 '' amd64 x86_64 -run_failure prerelease-release-mismatch prerelease 1.2.3 '' amd64 x86_64 -run_failure preview-malformed preview 1.2.3-rc.1-preview '' amd64 x86_64 -run_failure preview-wrong-shape preview 1.2.3-preview.1 '' amd64 x86_64 -run_failure short-semver release 1.2 '' amd64 x86_64 -run_failure leading-v release v1.2.3 '' amd64 x86_64 -run_failure leading-zero release 01.2.3 '' amd64 x86_64 -run_failure zero-sequence development "dev-${sha}" 0 amd64 x86_64 -run_failure leading-zero-sequence development "dev-${sha}" 01 amd64 x86_64 -run_failure non-decimal-sequence development "dev-${sha}" seven amd64 x86_64 -run_failure empty-dev-sha development dev- 1 amd64 x86_64 -run_failure short-dev-sha development dev-0123456 1 amd64 x86_64 -run_failure uppercase-dev-sha development dev-0123456789ABCDEF0123456789ABCDEF01234567 1 amd64 x86_64 -run_failure dev-extra-suffix development "dev-${sha}-dirty" 1 amd64 x86_64 -run_failure whitespace release '1.2.3 bad' '' amd64 x86_64 -run_failure command-substitution release "1.2.3\$(id)" '' amd64 x86_64 -run_failure backticks release "1.2.3\`id\`" '' amd64 x86_64 -run_failure newline release $'1.2.3\nforged=1' '' amd64 x86_64 -run_failure unsupported-deb-arch release 1.2.3 '' x86_64 x86_64 -run_failure mismatched-arch release 1.2.3 '' amd64 aarch64 +run_failure empty-build-type '' 1.2.3 '' x86_64 gnu +run_failure unknown-build-type nightly 1.2.3 '' x86_64 gnu +run_failure empty-version release '' '' x86_64 gnu +run_failure release-with-sequence release 1.2.3 1 x86_64 gnu +run_failure release-prerelease-mismatch release 1.2.3-rc.1 '' x86_64 gnu +run_failure prerelease-release-mismatch prerelease 1.2.3 '' x86_64 gnu +run_failure preview-malformed preview 1.2.3-rc.1-preview '' x86_64 gnu +run_failure preview-wrong-shape preview 1.2.3-preview.1 '' x86_64 gnu +run_failure short-semver release 1.2 '' x86_64 gnu +run_failure leading-v release v1.2.3 '' x86_64 gnu +run_failure leading-zero release 01.2.3 '' x86_64 gnu +run_failure zero-sequence development "dev-${sha}" 0 x86_64 gnu +run_failure leading-zero-sequence development "dev-${sha}" 01 x86_64 gnu +run_failure non-decimal-sequence development "dev-${sha}" seven x86_64 gnu +run_failure empty-dev-sha development dev- 1 x86_64 gnu +run_failure short-dev-sha development dev-0123456 1 x86_64 gnu +run_failure uppercase-dev-sha development dev-0123456789ABCDEF0123456789ABCDEF01234567 1 x86_64 gnu +run_failure dev-extra-suffix development "dev-${sha}-dirty" 1 x86_64 gnu +run_failure whitespace release '1.2.3 bad' '' x86_64 gnu +run_failure command-substitution release "1.2.3\$(id)" '' x86_64 gnu +run_failure backticks release "1.2.3\`id\`" '' x86_64 gnu +run_failure newline release $'1.2.3\nforged=1' '' x86_64 gnu +run_failure unsupported-arch release 1.2.3 '' armv7 gnu +run_failure empty-arch release 1.2.3 '' '' gnu +run_failure empty-libc release 1.2.3 '' x86_64 '' +run_failure unknown-libc release 1.2.3 '' x86_64 static +run_failure too-many-arguments release 1.2.3 '' x86_64 gnu extra # Ordering contract shared by both package managers: every pre-release sorts # below its final release, every preview sorts below the pre-release it