Release #20
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 | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| ref: | |
| description: Git tag to release, for example v1.2.3 | |
| required: true | |
| type: string | |
| permissions: | |
| contents: write | |
| env: | |
| CARGO_TERM_COLOR: always | |
| jobs: | |
| source-gates: | |
| name: Release source gates | |
| runs-on: ubuntu-latest | |
| env: | |
| RELEASE_REF: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.ref_name }} | |
| RUSTDOCFLAGS: -D warnings | |
| RUST_MIN_STACK: "8388608" | |
| RUST_TEST_THREADS: "1" | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ env.RELEASE_REF }} | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: clippy, rustfmt | |
| - name: Fetch locked dependencies | |
| run: cargo fetch --locked | |
| - name: cargo fmt | |
| run: cargo fmt --all -- --check | |
| - name: cargo clippy | |
| run: cargo clippy --workspace --all-targets --locked -- -D warnings | |
| - name: cargo test | |
| run: cargo test --workspace --locked --no-fail-fast | |
| - name: rustdoc with warnings denied | |
| run: cargo doc --workspace --locked --no-deps | |
| - name: Source boundary gates | |
| shell: bash | |
| run: | | |
| scripts/no-network-in-runtime.sh | |
| scripts/check-platform-neutrality.sh | |
| scripts/no-debug-assert-side-effects.sh | |
| build: | |
| name: Build ${{ matrix.target }} | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: ubuntu-latest | |
| target: x86_64-unknown-linux-gnu | |
| platform-label: linux-x86_64 | |
| binary: rmux | |
| archive: tar.gz | |
| - os: macos-15-intel | |
| target: x86_64-apple-darwin | |
| platform-label: macos-x86_64 | |
| binary: rmux | |
| archive: tar.gz | |
| - os: macos-15 | |
| target: aarch64-apple-darwin | |
| platform-label: macos-aarch64 | |
| binary: rmux | |
| archive: tar.gz | |
| - os: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| platform-label: windows-x86_64 | |
| binary: rmux.exe | |
| archive: zip | |
| env: | |
| RELEASE_REF: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.ref_name }} | |
| TARGET: ${{ matrix.target }} | |
| PLATFORM_LABEL: ${{ matrix.platform-label }} | |
| BINARY: ${{ matrix.binary }} | |
| BUILD_PROFILE: release | |
| PROFILE_DIR: release | |
| steps: | |
| - name: Validate release ref | |
| shell: bash | |
| run: | | |
| if [[ ! "$RELEASE_REF" =~ ^v[0-9]+\.[0-9]+\.[0-9]+([-.][0-9A-Za-z.-]+)?$ ]]; then | |
| echo "Invalid release ref: $RELEASE_REF" >&2 | |
| exit 1 | |
| fi | |
| echo "TAG=$RELEASE_REF" >> "$GITHUB_ENV" | |
| echo "VERSION=${RELEASE_REF#v}" >> "$GITHUB_ENV" | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ env.RELEASE_REF }} | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - name: Fetch locked dependencies | |
| run: cargo fetch --locked | |
| - name: Build rmux | |
| shell: bash | |
| run: cargo build --package rmux --locked --profile "$BUILD_PROFILE" --target "$TARGET" | |
| - name: Inspect release binary | |
| shell: bash | |
| run: | | |
| bin="target/$TARGET/$PROFILE_DIR/$BINARY" | |
| test -x "$bin" | |
| ls -lh "$bin" | |
| if [[ "$RUNNER_OS" != "Windows" ]]; then | |
| file "$bin" | |
| fi | |
| - name: Re-sign macOS binary | |
| if: runner.os == 'macOS' | |
| shell: bash | |
| run: | | |
| bin="target/$TARGET/$PROFILE_DIR/$BINARY" | |
| codesign --force --sign - "$bin" | |
| codesign --verify --verbose=2 "$bin" | |
| - name: Smoke binary | |
| shell: bash | |
| run: | | |
| bin="target/$TARGET/$PROFILE_DIR/$BINARY" | |
| "$bin" -V | tee version.txt | |
| grep -F "rmux $VERSION" version.txt | |
| - name: Install Linux package tooling | |
| if: matrix.target == 'x86_64-unknown-linux-gnu' | |
| shell: bash | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y cpio rpm createrepo-c | |
| - name: Windows runtime smoke | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = "Stop" | |
| $bin = "target/$env:TARGET/$env:PROFILE_DIR/$env:BINARY" | |
| & $bin -V | |
| & $bin list-commands | Out-Null | |
| - name: Create Unix archive | |
| if: matrix.archive == 'tar.gz' | |
| shell: bash | |
| run: | | |
| rm -rf dist | |
| if [[ "$RUNNER_OS" == "macOS" ]]; then | |
| export RMUX_PACKAGE_CODESIGN_ADHOC=1 | |
| fi | |
| scripts/package-unix.sh \ | |
| --configuration "$BUILD_PROFILE" \ | |
| --target "$TARGET" \ | |
| --output-dir dist | |
| archive="$(ls dist/rmux-*.tar.gz | head -n 1)" | |
| scripts/verify-package.sh "$archive" --checksums dist/SHA256SUMS.txt --run-binary --require-release-artifact | |
| - name: Create Linux distro packages | |
| if: matrix.target == 'x86_64-unknown-linux-gnu' | |
| shell: bash | |
| run: | | |
| scripts/package-debian.sh \ | |
| --configuration "$BUILD_PROFILE" \ | |
| --target "$TARGET" \ | |
| --output-dir dist \ | |
| --skip-build \ | |
| --reuse-release-binary | |
| deb="$(ls dist/rmux_*.deb | head -n 1)" | |
| scripts/verify-debian-package.sh "$deb" --checksums dist/SHA256SUMS.txt --run-binary --require-release-artifact | |
| scripts/package-rpm.sh \ | |
| --configuration "$BUILD_PROFILE" \ | |
| --target "$TARGET" \ | |
| --output-dir dist \ | |
| --skip-build \ | |
| --reuse-release-binary | |
| rpm="$(ls dist/rmux-*.rpm | head -n 1)" | |
| scripts/verify-rpm-package.sh "$rpm" --checksums dist/SHA256SUMS.txt --run-binary --require-release-artifact | |
| - name: Create Windows archive | |
| if: matrix.archive == 'zip' | |
| shell: pwsh | |
| run: | | |
| ./scripts/package-windows.ps1 ` | |
| -Configuration "$env:BUILD_PROFILE" ` | |
| -Target "$env:TARGET" ` | |
| -OutputDir dist ` | |
| -PlatformLabel "$env:PLATFORM_LABEL" | |
| $archive = Get-ChildItem -Path dist -Filter "rmux-*.zip" | Select-Object -First 1 | |
| if ($null -eq $archive) { | |
| throw "Windows package archive was not generated" | |
| } | |
| ./scripts/verify-package-windows.ps1 ` | |
| $archive.FullName ` | |
| -Checksums dist/SHA256SUMS.txt ` | |
| -RunBinary ` | |
| -RunDaemonSmoke | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: rmux-${{ env.RELEASE_REF }}-${{ matrix.target }} | |
| path: | | |
| dist/*.tar.gz | |
| dist/*.zip | |
| dist/*.deb | |
| dist/*.rpm | |
| if-no-files-found: error | |
| publish: | |
| name: Publish GitHub release assets | |
| runs-on: ubuntu-latest | |
| environment: release | |
| needs: | |
| - source-gates | |
| - build | |
| env: | |
| RELEASE_REF: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.ref_name }} | |
| GH_TOKEN: ${{ github.token }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ env.RELEASE_REF }} | |
| - uses: actions/download-artifact@v4 | |
| with: | |
| path: release-assets | |
| merge-multiple: true | |
| - name: Generate checksums | |
| shell: bash | |
| run: | | |
| cd release-assets | |
| shopt -s nullglob | |
| assets=( *.tar.gz *.zip *.deb *.rpm ) | |
| if (( ${#assets[@]} == 0 )); then | |
| echo "No release archives found" >&2 | |
| exit 1 | |
| fi | |
| printf '%s\0' "${assets[@]}" | sort -z | xargs -0 sha256sum > SHA256SUMS | |
| - name: Install repository metadata tooling | |
| shell: bash | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y createrepo-c gnupg rpm | |
| - name: Import Linux repository signing keys | |
| shell: bash | |
| env: | |
| RMUX_APT_GPG_PRIVATE_KEY: ${{ secrets.RMUX_APT_GPG_PRIVATE_KEY }} | |
| RMUX_APT_GPG_KEY: ${{ secrets.RMUX_APT_GPG_KEY }} | |
| RMUX_RPM_GPG_PRIVATE_KEY: ${{ secrets.RMUX_RPM_GPG_PRIVATE_KEY }} | |
| RMUX_RPM_GPG_KEY: ${{ secrets.RMUX_RPM_GPG_KEY }} | |
| RMUX_RPM_REPO_GPG_PRIVATE_KEY: ${{ secrets.RMUX_RPM_REPO_GPG_PRIVATE_KEY }} | |
| RMUX_RPM_REPO_GPG_KEY: ${{ secrets.RMUX_RPM_REPO_GPG_KEY }} | |
| run: | | |
| missing=0 | |
| for name in RMUX_APT_GPG_PRIVATE_KEY RMUX_APT_GPG_KEY RMUX_RPM_GPG_PRIVATE_KEY RMUX_RPM_GPG_KEY; do | |
| if [ -z "${!name:-}" ]; then | |
| echo "Missing required secret: $name" >&2 | |
| missing=1 | |
| fi | |
| done | |
| rpm_repo_key="${RMUX_RPM_REPO_GPG_KEY:-$RMUX_RPM_GPG_KEY}" | |
| if [ "$rpm_repo_key" != "$RMUX_RPM_GPG_KEY" ] && [ -z "${RMUX_RPM_REPO_GPG_PRIVATE_KEY:-}" ]; then | |
| echo "Missing required secret: RMUX_RPM_REPO_GPG_PRIVATE_KEY" >&2 | |
| missing=1 | |
| fi | |
| [ "$missing" -eq 0 ] || exit 1 | |
| install -m 700 -d ~/.gnupg | |
| printf '%s\n' "$RMUX_APT_GPG_PRIVATE_KEY" | gpg --batch --import | |
| printf '%s\n' "$RMUX_RPM_GPG_PRIVATE_KEY" | gpg --batch --import | |
| if [ -n "${RMUX_RPM_REPO_GPG_PRIVATE_KEY:-}" ]; then | |
| printf '%s\n' "$RMUX_RPM_REPO_GPG_PRIVATE_KEY" | gpg --batch --import | |
| fi | |
| gpg --batch --list-secret-keys "$RMUX_APT_GPG_KEY" >/dev/null | |
| gpg --batch --list-secret-keys "$RMUX_RPM_GPG_KEY" >/dev/null | |
| gpg --batch --list-secret-keys "$rpm_repo_key" >/dev/null | |
| - name: Generate Homebrew formula | |
| shell: bash | |
| run: | | |
| version="${RELEASE_REF#v}" | |
| mkdir -p target/homebrew/Formula | |
| scripts/generate-homebrew-formula.sh \ | |
| --version "$version" \ | |
| --checksums release-assets/SHA256SUMS \ | |
| --output target/homebrew/Formula/rmux.rb | |
| if command -v ruby >/dev/null 2>&1; then | |
| ruby -c target/homebrew/Formula/rmux.rb | |
| fi | |
| - name: Generate package manager metadata | |
| shell: bash | |
| run: | | |
| version="${RELEASE_REF#v}" | |
| mkdir -p \ | |
| target/package-managers/homebrew/Formula \ | |
| target/package-managers/winget \ | |
| target/package-managers/scoop \ | |
| target/package-managers/chocolatey | |
| cp target/homebrew/Formula/rmux.rb target/package-managers/homebrew/Formula/rmux.rb | |
| scripts/generate-winget-manifest.sh \ | |
| --version "$version" \ | |
| --checksums release-assets/SHA256SUMS \ | |
| --output target/package-managers/winget/Helvesec.RMUX.yaml | |
| sed -i \ | |
| -e 's/winget-manifest\.singleton\.1\.12\.0\.schema\.json/winget-manifest.singleton.1.10.0.schema.json/' \ | |
| -e 's/ManifestVersion: "1\.12\.0"/ManifestVersion: "1.10.0"/' \ | |
| target/package-managers/winget/Helvesec.RMUX.yaml | |
| scripts/generate-scoop-manifest.sh \ | |
| --version "$version" \ | |
| --checksums release-assets/SHA256SUMS \ | |
| --output target/package-managers/scoop/rmux.json | |
| scripts/generate-chocolatey-package.sh \ | |
| --version "$version" \ | |
| --checksums release-assets/SHA256SUMS \ | |
| --output-dir target/package-managers/chocolatey/rmux | |
| if command -v ruby >/dev/null 2>&1; then | |
| ruby -rjson -e 'JSON.parse(File.read(ARGV.fetch(0)))' target/package-managers/scoop/rmux.json | |
| fi | |
| - name: Validate WinGet metadata | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = "Stop" | |
| $version = $env:RELEASE_REF.Substring(1) | |
| ./scripts/validate-winget-manifest.ps1 ` | |
| -Manifest "target/package-managers/winget/Helvesec.RMUX.yaml" ` | |
| -Version $version ` | |
| -Checksums "release-assets/SHA256SUMS" ` | |
| -Repository $env:GITHUB_REPOSITORY | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: package-manager-metadata-${{ env.RELEASE_REF }} | |
| path: target/package-managers | |
| if-no-files-found: error | |
| - name: Generate Linux package repositories | |
| shell: bash | |
| env: | |
| RMUX_APT_GPG_KEY: ${{ secrets.RMUX_APT_GPG_KEY }} | |
| RMUX_RPM_GPG_KEY: ${{ secrets.RMUX_RPM_GPG_KEY }} | |
| RMUX_RPM_REPO_GPG_KEY: ${{ secrets.RMUX_RPM_REPO_GPG_KEY }} | |
| run: | | |
| : "${RMUX_APT_GPG_KEY:?missing RMUX_APT_GPG_KEY}" | |
| : "${RMUX_RPM_GPG_KEY:?missing RMUX_RPM_GPG_KEY}" | |
| rpm_repo_key="${RMUX_RPM_REPO_GPG_KEY:-$RMUX_RPM_GPG_KEY}" | |
| mkdir -p target/package-repositories | |
| scripts/generate-apt-repository.sh \ | |
| --input-dir release-assets \ | |
| --output-dir target/package-repositories/debian \ | |
| --suite stable \ | |
| --component main \ | |
| --architecture amd64 \ | |
| --signing-key "$RMUX_APT_GPG_KEY" | |
| scripts/generate-rpm-repository.sh \ | |
| --input-dir release-assets \ | |
| --output-dir target/package-repositories/rpm \ | |
| --baseurl https://packages.rmux.io/rpm \ | |
| --rpm-signing-key "$RMUX_RPM_GPG_KEY" \ | |
| --repo-signing-key "$rpm_repo_key" | |
| gpg --armor --export "$RMUX_APT_GPG_KEY" > target/package-repositories/debian/rmux.asc | |
| gpg --armor --export "$RMUX_RPM_GPG_KEY" > target/package-repositories/rpm/RPM-GPG-KEY-rmux | |
| test -f target/package-repositories/debian/rmux.asc | |
| test -f target/package-repositories/debian/dists/stable/Release | |
| test -f target/package-repositories/debian/dists/stable/InRelease | |
| test -f target/package-repositories/debian/dists/stable/Release.gpg | |
| test -f target/package-repositories/debian/dists/stable/main/binary-amd64/Packages.gz | |
| test -f target/package-repositories/rpm/RPM-GPG-KEY-rmux | |
| test -f target/package-repositories/rpm/repodata/repomd.xml | |
| test -f target/package-repositories/rpm/repodata/repomd.xml.asc | |
| test -f target/package-repositories/rpm/rmux.repo | |
| grep -qx 'gpgcheck=1' target/package-repositories/rpm/rmux.repo | |
| grep -qx 'repo_gpgcheck=1' target/package-repositories/rpm/rmux.repo | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: linux-package-repositories-${{ env.RELEASE_REF }} | |
| path: target/package-repositories | |
| if-no-files-found: error | |
| - name: Create or update release | |
| shell: bash | |
| run: | | |
| tag="$RELEASE_REF" | |
| version="${tag#v}" | |
| if ! gh release view "$tag" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then | |
| gh release create "$tag" \ | |
| --repo "$GITHUB_REPOSITORY" \ | |
| --title "$tag" \ | |
| --draft \ | |
| --notes "RMUX $version binary release." | |
| fi | |
| shopt -s nullglob | |
| assets=( | |
| release-assets/*.tar.gz | |
| release-assets/*.zip | |
| release-assets/*.deb | |
| release-assets/*.rpm | |
| release-assets/SHA256SUMS | |
| ) | |
| if (( ${#assets[@]} == 0 )); then | |
| echo "No release assets found" >&2 | |
| exit 1 | |
| fi | |
| gh release upload "$tag" --repo "$GITHUB_REPOSITORY" "${assets[@]}" --clobber | |
| gh release edit "$tag" --repo "$GITHUB_REPOSITORY" --draft=false | |
| - name: Deploy Linux package repositories | |
| shell: bash | |
| env: | |
| RMUX_PACKAGE_REPO_TOKEN: ${{ secrets.RMUX_PACKAGE_REPO_TOKEN }} | |
| RMUX_PACKAGE_REPO: Helvesec/rmux-packages | |
| RMUX_PACKAGE_REPO_BRANCH: main | |
| run: | | |
| : "${RMUX_PACKAGE_REPO_TOKEN:?missing RMUX_PACKAGE_REPO_TOKEN}" | |
| : "${RMUX_PACKAGE_REPO:?missing RMUX_PACKAGE_REPO}" | |
| : "${RMUX_PACKAGE_REPO_BRANCH:?missing RMUX_PACKAGE_REPO_BRANCH}" | |
| test -d target/package-repositories/debian | |
| test -d target/package-repositories/rpm | |
| work="$(mktemp -d)" | |
| trap 'rm -rf "$work"' EXIT | |
| package_repo_url="https://x-access-token:${RMUX_PACKAGE_REPO_TOKEN}@github.com/${RMUX_PACKAGE_REPO}.git" | |
| git clone --depth 1 --branch "$RMUX_PACKAGE_REPO_BRANCH" "$package_repo_url" "$work" | |
| rm -rf "$work/debian" "$work/rpm" | |
| cp -a target/package-repositories/debian "$work/debian" | |
| cp -a target/package-repositories/rpm "$work/rpm" | |
| cat > "$work/index.html" <<'EOF' | |
| <!doctype html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| <title>RMUX Packages</title> | |
| </head> | |
| <body> | |
| <h1>RMUX Packages</h1> | |
| <ul> | |
| <li><a href="/debian/dists/stable/InRelease">APT repository</a></li> | |
| <li><a href="/rpm/rmux.repo">RPM repository</a></li> | |
| </ul> | |
| </body> | |
| </html> | |
| EOF | |
| cat > "$work/_headers" <<'EOF' | |
| /debian/dists/* | |
| Cache-Control: public, max-age=300 | |
| /debian/rmux.asc | |
| Cache-Control: public, max-age=3600 | |
| /debian/pool/* | |
| Cache-Control: public, max-age=31536000, immutable | |
| /rpm/repodata/* | |
| Cache-Control: public, max-age=300 | |
| /rpm/RPM-GPG-KEY-rmux | |
| Cache-Control: public, max-age=3600 | |
| /rpm/rmux.repo | |
| Cache-Control: public, max-age=300 | |
| /rpm/*.rpm | |
| Cache-Control: public, max-age=31536000, immutable | |
| EOF | |
| cd "$work" | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| if [ -z "$(git status --porcelain)" ]; then | |
| echo "Linux package repository already points to $RELEASE_REF." | |
| exit 0 | |
| fi | |
| git add _headers index.html debian rpm | |
| git commit -m "packages: publish rmux $RELEASE_REF" | |
| git push "$package_repo_url" "HEAD:$RMUX_PACKAGE_REPO_BRANCH" | |
| validate-winget: | |
| name: Validate WinGet manifest | |
| runs-on: windows-latest | |
| needs: | |
| - publish | |
| env: | |
| RELEASE_REF: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.ref_name }} | |
| steps: | |
| - name: Validate release ref | |
| shell: pwsh | |
| run: | | |
| if ($env:RELEASE_REF -notmatch '^v[0-9]+\.[0-9]+\.[0-9]+([-.][0-9A-Za-z.-]+)?$') { | |
| throw "Invalid release ref: $env:RELEASE_REF" | |
| } | |
| "VERSION=$($env:RELEASE_REF.Substring(1))" | Out-File -FilePath $env:GITHUB_ENV -Append | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ env.RELEASE_REF }} | |
| - uses: actions/download-artifact@v4 | |
| with: | |
| name: package-manager-metadata-${{ env.RELEASE_REF }} | |
| path: package-manager-metadata | |
| - name: Download release checksums | |
| shell: pwsh | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| $ErrorActionPreference = "Stop" | |
| New-Item -ItemType Directory -Force -Path release-assets | Out-Null | |
| gh release download $env:RELEASE_REF ` | |
| --repo $env:GITHUB_REPOSITORY ` | |
| --pattern SHA256SUMS ` | |
| --dir release-assets ` | |
| --clobber | |
| - name: Validate generated WinGet manifest | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = "Stop" | |
| $manifest = "package-manager-metadata\winget\Helvesec.RMUX.yaml" | |
| .\scripts\validate-winget-manifest.ps1 ` | |
| -Manifest $manifest ` | |
| -Version $env:VERSION ` | |
| -Checksums "release-assets\SHA256SUMS" ` | |
| -Repository $env:GITHUB_REPOSITORY | |
| - name: Run winget validate | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = "Stop" | |
| $manifest = "package-manager-metadata\winget\Helvesec.RMUX.yaml" | |
| if (-not (Get-Command winget -ErrorAction SilentlyContinue)) { | |
| throw "winget is required on the Windows release runner so the generated manifest is validated by the real WinGet CLI." | |
| } | |
| winget --version | |
| winget validate --manifest $manifest --disable-interactivity | |
| publish-chocolatey: | |
| name: Publish Chocolatey package | |
| runs-on: windows-latest | |
| needs: | |
| - publish | |
| environment: release | |
| env: | |
| RELEASE_REF: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.ref_name }} | |
| CHOCOLATEY_API_KEY: ${{ secrets.CHOCOLATEY_API_KEY }} | |
| steps: | |
| - name: Validate release ref | |
| shell: pwsh | |
| run: | | |
| if ($env:RELEASE_REF -notmatch '^v[0-9]+\.[0-9]+\.[0-9]+([-.][0-9A-Za-z.-]+)?$') { | |
| throw "Invalid release ref: $env:RELEASE_REF" | |
| } | |
| "VERSION=$($env:RELEASE_REF.Substring(1))" | Out-File -FilePath $env:GITHUB_ENV -Append | |
| - uses: actions/download-artifact@v4 | |
| with: | |
| name: package-manager-metadata-${{ env.RELEASE_REF }} | |
| path: package-manager-metadata | |
| - name: Validate Chocolatey prerequisites | |
| shell: pwsh | |
| run: | | |
| if ([string]::IsNullOrWhiteSpace($env:CHOCOLATEY_API_KEY)) { | |
| throw "Missing required GitHub Actions secret: CHOCOLATEY_API_KEY" | |
| } | |
| choco --version | |
| - name: Pack and smoke-test Chocolatey package | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = "Stop" | |
| $version = $env:VERSION | |
| $packageRoot = (Resolve-Path "package-manager-metadata\chocolatey\rmux").Path | |
| $nuspecPath = Join-Path $packageRoot "rmux.nuspec" | |
| $installScript = Join-Path $packageRoot "tools\chocolateyInstall.ps1" | |
| $uninstallScript = Join-Path $packageRoot "tools\chocolateyUninstall.ps1" | |
| foreach ($required in @($nuspecPath, $installScript, $uninstallScript)) { | |
| if (-not (Test-Path $required)) { | |
| throw "Missing generated Chocolatey file: $required" | |
| } | |
| } | |
| [xml]$nuspec = Get-Content $nuspecPath | |
| if ($nuspec.package.metadata.id -ne "rmux") { | |
| throw "Unexpected Chocolatey package id: $($nuspec.package.metadata.id)" | |
| } | |
| if ($nuspec.package.metadata.version -ne $version) { | |
| throw "Unexpected Chocolatey package version: $($nuspec.package.metadata.version)" | |
| } | |
| Push-Location $packageRoot | |
| try { | |
| choco pack .\rmux.nuspec --outputdirectory . | |
| } finally { | |
| Pop-Location | |
| } | |
| $package = Join-Path $packageRoot "rmux.$version.nupkg" | |
| if (-not (Test-Path $package)) { | |
| throw "Chocolatey package was not generated: $package" | |
| } | |
| choco install rmux ` | |
| --source $packageRoot ` | |
| --version $version ` | |
| --yes ` | |
| --no-progress ` | |
| --force | |
| $versionOutput = (& rmux -V).Trim() | |
| if ($versionOutput -ne "rmux $version") { | |
| throw "Unexpected rmux version from Chocolatey install: $versionOutput" | |
| } | |
| choco uninstall rmux --yes --no-progress | |
| "CHOCOLATEY_PACKAGE=$package" | Out-File -FilePath $env:GITHUB_ENV -Append | |
| - name: Push Chocolatey package | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = "Stop" | |
| if (-not (Test-Path $env:CHOCOLATEY_PACKAGE)) { | |
| throw "Chocolatey package not found: $env:CHOCOLATEY_PACKAGE" | |
| } | |
| $version = $env:VERSION | |
| $query = "https://community.chocolatey.org/api/v2/FindPackagesById()?id='rmux'" | |
| $response = Invoke-WebRequest -Uri $query -Method Get | |
| [xml]$feed = $response.Content | |
| $namespaceManager = [System.Xml.XmlNamespaceManager]::new($feed.NameTable) | |
| $namespaceManager.AddNamespace("atom", "http://www.w3.org/2005/Atom") | |
| $namespaceManager.AddNamespace("m", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata") | |
| $namespaceManager.AddNamespace("d", "http://schemas.microsoft.com/ado/2007/08/dataservices") | |
| $existingVersion = $feed.SelectSingleNode("//atom:entry/m:properties[d:Version='$version']/d:Version", $namespaceManager) | |
| if ($existingVersion) { | |
| Write-Host "Chocolatey package rmux $version already exists; skipping push." | |
| exit 0 | |
| } | |
| choco push $env:CHOCOLATEY_PACKAGE ` | |
| --source "https://push.chocolatey.org/" ` | |
| --api-key $env:CHOCOLATEY_API_KEY ` | |
| --yes ` | |
| --no-progress |