Add ordered first and last aggregates #292
Workflow file for this run
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: CI and release | |
| on: | |
| push: | |
| branches: | |
| - main | |
| tags: | |
| - "v*" | |
| pull_request: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| env: | |
| CRATE_NAME: hubuum-cli | |
| GITHUB_TOKEN: ${{ github.token }} | |
| RUST_BACKTRACE: 1 | |
| permissions: | |
| contents: read | |
| jobs: | |
| lint: | |
| name: Lint | |
| if: "!startsWith(github.ref, 'refs/tags/')" | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - name: Check out repository | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| - name: Install clippy | |
| run: rustup component add clippy | |
| - name: Run clippy | |
| run: cargo clippy --locked --all-targets -- -D warnings | |
| - name: Run Host extension wrapper tests | |
| run: examples/hubuum-wrappers/tests/test_wrappers.sh | |
| - name: Validate extension JSON Schema | |
| run: npx --yes ajv-cli@5.0.0 compile --spec=draft2020 -s schemas/hubuum-extension.schema.json | |
| - name: Markdown lint | |
| uses: DavidAnson/markdownlint-cli2-action@21c1be1b93ad9ed58fa840aacc3f279cde2a72ff # v24 | |
| with: | |
| config: ".markdownlint.json" | |
| globs: "**/*.md" | |
| test: | |
| name: ${{ matrix.platform.os_name }} with rust ${{ matrix.toolchain }} | |
| if: "!startsWith(github.ref, 'refs/tags/')" | |
| runs-on: ${{ matrix.platform.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| platform: | |
| - os_name: Linux-x86_64 | |
| os: ubuntu-24.04 | |
| target: x86_64-unknown-linux-gnu | |
| skip_tests: false | |
| - os_name: macOS-aarch64 | |
| os: macos-latest | |
| target: aarch64-apple-darwin | |
| skip_tests: true | |
| - os_name: Windows-x86_64 | |
| os: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| skip_tests: true | |
| toolchain: | |
| - stable | |
| - beta | |
| - nightly | |
| steps: | |
| - name: Check out repository | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| - name: Cache cargo and target directories | |
| uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2 | |
| - name: Build binary | |
| uses: houseabsolute/actions-rust-cross@21b0f18dc621b25bfae556ff2791fca4173121e8 # v1 | |
| with: | |
| command: build | |
| target: ${{ matrix.platform.target }} | |
| toolchain: ${{ matrix.toolchain }} | |
| args: "--locked --release" | |
| - name: Run tests | |
| if: ${{ !matrix.platform.skip_tests }} | |
| uses: houseabsolute/actions-rust-cross@21b0f18dc621b25bfae556ff2791fca4173121e8 # v1 | |
| with: | |
| command: test | |
| target: ${{ matrix.platform.target }} | |
| toolchain: ${{ matrix.toolchain }} | |
| args: "--locked --release" | |
| verify-tag-main-ci-success: | |
| name: Verify tagged commit already passed CI on main | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| runs-on: ubuntu-24.04 | |
| permissions: | |
| actions: read | |
| contents: read | |
| steps: | |
| - name: Check for successful main CI run on this commit | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| OWNER: ${{ github.repository_owner }} | |
| REPO: ${{ github.event.repository.name }} | |
| SHA: ${{ github.sha }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| api="https://api.github.com/repos/${OWNER}/${REPO}/actions/workflows/ci.yml/runs?event=push&branch=main&head_sha=${SHA}&status=completed&per_page=100" | |
| response="$( | |
| curl --silent --show-error --fail \ | |
| --header "Authorization: Bearer ${GH_TOKEN}" \ | |
| --header "Accept: application/vnd.github+json" \ | |
| "${api}" | |
| )" | |
| successful_run_count="$( | |
| jq '[.workflow_runs[] | select(.head_branch == "main" and .conclusion == "success")] | length' <<<"${response}" | |
| )" | |
| if [[ "${successful_run_count}" -eq 0 ]]; then | |
| echo "No successful CI run on main was found for commit ${SHA}." >&2 | |
| echo "Version tags must point at a green main commit." >&2 | |
| exit 1 | |
| fi | |
| echo "Found a successful main CI run for ${SHA}." | |
| validate-release: | |
| name: Validate tagged release metadata | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| needs: verify-tag-main-ci-success | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - name: Check out repository | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| - name: Validate version and changelog | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| version="${GITHUB_REF_NAME#v}" | |
| manifest_version="$(sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml | head -n 1)" | |
| if [[ -z "${manifest_version}" ]]; then | |
| echo "Unable to determine package version from Cargo.toml" >&2 | |
| exit 1 | |
| fi | |
| if [[ "${manifest_version}" != "${version}" ]]; then | |
| echo "Tag ${GITHUB_REF_NAME} does not match Cargo.toml version ${manifest_version}" >&2 | |
| exit 1 | |
| fi | |
| if [[ ! -f CHANGELOG.md ]]; then | |
| echo "CHANGELOG.md is required for versioned releases" >&2 | |
| exit 1 | |
| fi | |
| if ! grep -q "^## \[${version}\]" CHANGELOG.md; then | |
| echo "CHANGELOG.md is missing an entry for ${version}" >&2 | |
| exit 1 | |
| fi | |
| - name: Validate lockfile | |
| run: cargo check --locked | |
| build-release-artifacts: | |
| name: Build release artifact (${{ matrix.platform.name }}) | |
| if: >- | |
| always() && | |
| ( | |
| ( | |
| github.ref == 'refs/heads/main' && | |
| needs.lint.result == 'success' && | |
| needs.test.result == 'success' | |
| ) || | |
| ( | |
| startsWith(github.ref, 'refs/tags/v') && | |
| needs.validate-release.result == 'success' | |
| ) | |
| ) | |
| needs: | |
| - lint | |
| - test | |
| - validate-release | |
| runs-on: ${{ matrix.platform.runner }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| platform: | |
| - name: Linux-x86_64-musl | |
| kind: linux | |
| arch: amd64 | |
| os_name: linux-x86_64-musl | |
| runner: ubuntu-24.04 | |
| target: x86_64-unknown-linux-musl | |
| rustflags: "" | |
| - name: Linux-aarch64-musl | |
| kind: linux | |
| arch: arm64 | |
| os_name: linux-aarch64-musl | |
| runner: ubuntu-24.04-arm | |
| target: aarch64-unknown-linux-musl | |
| rustflags: "" | |
| - name: macOS-ARM64 | |
| kind: native | |
| arch: arm64 | |
| os_name: macos-aarch64 | |
| runner: macos-latest | |
| target: aarch64-apple-darwin | |
| rustflags: "-C link-arg=-Wl,-dead_strip" | |
| - name: Windows-x86_64 | |
| kind: native | |
| arch: amd64 | |
| os_name: windows-x86_64 | |
| runner: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| rustflags: "-C target-feature=+crt-static" | |
| steps: | |
| - name: Check out repository | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| - name: Set up Buildx | |
| if: matrix.platform.kind == 'linux' | |
| uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4 | |
| - name: Export stripped static Linux binary | |
| if: matrix.platform.kind == 'linux' | |
| uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7 | |
| with: | |
| context: . | |
| file: Dockerfile | |
| target: release-artifacts | |
| platforms: linux/${{ matrix.platform.arch }} | |
| outputs: type=local,dest=dist/bin | |
| build-args: | | |
| CARGO_BUILD_FLAGS=--locked --release | |
| HUBUUM_CLI_BUILD_CHANNEL=${{ github.ref == 'refs/heads/main' && 'main' || 'release' }} | |
| HUBUUM_CLI_BUILD_GIT_SHA=${{ github.sha }} | |
| cache-from: type=gha,scope=static-${{ matrix.platform.os_name }} | |
| cache-to: type=gha,mode=max,scope=static-${{ matrix.platform.os_name }} | |
| - name: Install stable Rust toolchain | |
| if: matrix.platform.kind == 'native' | |
| uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable | |
| with: | |
| targets: ${{ matrix.platform.target }} | |
| - name: Cache cargo and target directories | |
| if: matrix.platform.kind == 'native' | |
| uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2 | |
| with: | |
| shared-key: ${{ matrix.platform.target }}-stable-release | |
| - name: Build self-contained native binary | |
| if: matrix.platform.kind == 'native' | |
| env: | |
| HUBUUM_CLI_BUILD_CHANNEL: ${{ github.ref == 'refs/heads/main' && 'main' || 'release' }} | |
| HUBUUM_CLI_BUILD_GIT_SHA: ${{ github.sha }} | |
| RUSTFLAGS: ${{ matrix.platform.rustflags }} | |
| run: cargo build --locked --release --target ${{ matrix.platform.target }} | |
| - name: Verify static linkage and package Linux archive | |
| if: matrix.platform.kind == 'linux' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| binary_path="dist/bin/hubuum-cli" | |
| if readelf --dynamic "${binary_path}" | grep --quiet '(NEEDED)'; then | |
| echo "${binary_path} unexpectedly has dynamic runtime dependencies" >&2 | |
| readelf --dynamic "${binary_path}" >&2 | |
| exit 1 | |
| fi | |
| "${binary_path}" --version | |
| suffix="main" | |
| if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then | |
| suffix="${GITHUB_REF_NAME}" | |
| fi | |
| archive_name="hubuum-cli-${{ matrix.platform.os_name }}-${suffix}.tar.gz" | |
| tar czf "dist/${archive_name}" -C dist/bin hubuum-cli | |
| ( | |
| cd dist | |
| sha256sum "${archive_name}" > "${archive_name}.sha256" | |
| ) | |
| - name: Verify macOS runtime dependencies | |
| if: matrix.platform.os_name == 'macos-aarch64' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| binary_path="target/${{ matrix.platform.target }}/release/hubuum-cli" | |
| "${binary_path}" --version | |
| if xcrun otool -L "${binary_path}" | grep --extended-regexp --quiet '(/opt/homebrew|/usr/local|libssl|libcrypto)'; then | |
| echo "${binary_path} unexpectedly depends on a package-manager library" >&2 | |
| xcrun otool -L "${binary_path}" >&2 | |
| exit 1 | |
| fi | |
| - name: Package macOS archive | |
| if: matrix.platform.os_name == 'macos-aarch64' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| suffix="main" | |
| if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then | |
| suffix="${GITHUB_REF_NAME}" | |
| fi | |
| archive_name="hubuum-cli-${{ matrix.platform.os_name }}-${suffix}.tar.gz" | |
| mkdir -p dist | |
| tar czf "dist/${archive_name}" \ | |
| -C "target/${{ matrix.platform.target }}/release" \ | |
| hubuum-cli | |
| ( | |
| cd dist | |
| shasum -a 256 "${archive_name}" > "${archive_name}.sha256" | |
| ) | |
| - name: Verify Windows binary starts | |
| if: matrix.platform.os_name == 'windows-x86_64' | |
| shell: pwsh | |
| run: | | |
| & "target/${{ matrix.platform.target }}/release/hubuum-cli.exe" --version | |
| - name: Package Windows archive | |
| if: matrix.platform.os_name == 'windows-x86_64' | |
| shell: pwsh | |
| run: | | |
| $suffix = "main" | |
| if ($env:GITHUB_REF -like "refs/tags/v*") { | |
| $suffix = $env:GITHUB_REF_NAME | |
| } | |
| $archiveName = "hubuum-cli-${{ matrix.platform.os_name }}-$suffix.zip" | |
| New-Item -ItemType Directory -Path dist -Force | Out-Null | |
| Compress-Archive ` | |
| -Path "target/${{ matrix.platform.target }}/release/hubuum-cli.exe" ` | |
| -DestinationPath "dist/$archiveName" ` | |
| -Force | |
| $hash = (Get-FileHash "dist/$archiveName" -Algorithm SHA256).Hash.ToLower() | |
| [System.IO.File]::WriteAllText( | |
| "dist/$archiveName.sha256", | |
| "$hash $archiveName`n", | |
| [System.Text.UTF8Encoding]::new($false) | |
| ) | |
| - name: Upload packaged artifact | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: binaries-${{ matrix.platform.os_name }} | |
| path: | | |
| dist/*.tar.gz | |
| dist/*.zip | |
| dist/*.sha256 | |
| if-no-files-found: error | |
| publish-release: | |
| name: Publish release | |
| if: >- | |
| always() && | |
| needs.build-release-artifacts.result == 'success' && | |
| ( | |
| github.ref == 'refs/heads/main' || | |
| startsWith(github.ref, 'refs/tags/v') | |
| ) | |
| needs: build-release-artifacts | |
| runs-on: ubuntu-24.04 | |
| permissions: | |
| contents: write | |
| concurrency: | |
| group: publish-${{ github.ref }} | |
| cancel-in-progress: ${{ github.ref == 'refs/heads/main' }} | |
| steps: | |
| - name: Check out repository | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| with: | |
| fetch-depth: 0 | |
| - name: Download packaged artifacts | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| pattern: binaries-* | |
| path: dist | |
| merge-multiple: true | |
| - name: Verify artifact checksums | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| ( | |
| cd dist | |
| sha256sum --check --strict ./*.sha256 | |
| ) | |
| - name: Move main release tag | |
| if: github.ref == 'refs/heads/main' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| git tag -f main-latest "${GITHUB_SHA}" | |
| git push --force origin refs/tags/main-latest | |
| - name: Write main release notes | |
| if: github.ref == 'refs/heads/main' | |
| shell: bash | |
| run: | | |
| cat <<EOF > RELEASE_NOTES.md | |
| Rolling binaries from the latest successful push to \`main\`. | |
| Commit: ${GITHUB_SHA} | |
| EOF | |
| - name: Extract tagged release notes from changelog | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| version="${GITHUB_REF_NAME#v}" | |
| awk -v version="${version}" ' | |
| $0 ~ "^## \\[" version "\\]" { capture = 1 } | |
| capture && /^## \[/ && $0 !~ "^## \\[" version "\\]" { exit } | |
| capture { print } | |
| ' CHANGELOG.md > RELEASE_NOTES.md | |
| if [[ ! -s RELEASE_NOTES.md ]]; then | |
| echo "Failed to extract release notes for ${version}" >&2 | |
| exit 1 | |
| fi | |
| - name: Publish GitHub release | |
| uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3 | |
| with: | |
| tag_name: ${{ github.ref == 'refs/heads/main' && 'main-latest' || github.ref_name }} | |
| name: ${{ github.ref == 'refs/heads/main' && 'main' || github.ref_name }} | |
| body_path: RELEASE_NOTES.md | |
| draft: false | |
| prerelease: false | |
| make_latest: ${{ github.ref == 'refs/heads/main' && 'false' || 'true' }} | |
| overwrite_files: true | |
| fail_on_unmatched_files: true | |
| files: dist/* |