diff --git a/.gitea/workflows/action-validation.yml b/.gitea/workflows/action-validation.yml new file mode 100644 index 0000000..2c5f504 --- /dev/null +++ b/.gitea/workflows/action-validation.yml @@ -0,0 +1,102 @@ +name: Action Validation + +on: + push: + branches: + - "**" + tags-ignore: + - "*" + workflow_dispatch: + +jobs: + validate-released-binary: + runs-on: ubuntu-latest + container: docker.io/catthehacker/ubuntu:act-latest + strategy: + fail-fast: false + matrix: + include: + - runner_arch: X64 + asset_arch: amd64 + run_command: ./vociferate + - runner_arch: ARM64 + asset_arch: arm64 + run_command: qemu-aarch64-static ./vociferate + defaults: + run: + shell: bash + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install arm64 emulator + if: ${{ matrix.runner_arch == 'ARM64' }} + run: | + set -euo pipefail + apt-get update + apt-get install -y qemu-user-static + + - name: Resolve latest released binary + id: resolve-binary + env: + API_URL: ${{ github.api_url }} + SERVER_URL: ${{ github.server_url }} + TOKEN: ${{ github.token }} + ASSET_ARCH: ${{ matrix.asset_arch }} + run: | + set -euo pipefail + + release_tag="$(curl -fsSL \ + -H "Authorization: token ${TOKEN}" \ + -H "Content-Type: application/json" \ + "${API_URL}/repos/aether/vociferate/releases/latest" | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n 1)" + + if [[ -z "$release_tag" ]]; then + echo "Unable to resolve latest vociferate release" >&2 + exit 1 + fi + + normalized_version="${release_tag#v}" + asset_name="vociferate_${normalized_version}_linux_${ASSET_ARCH}" + asset_url="${SERVER_URL}/aether/vociferate/releases/download/${release_tag}/${asset_name}" + + echo "release_tag=$release_tag" >> "$GITHUB_OUTPUT" + echo "asset_name=$asset_name" >> "$GITHUB_OUTPUT" + echo "asset_url=$asset_url" >> "$GITHUB_OUTPUT" + + - name: Download released binary + env: + TOKEN: ${{ github.token }} + ASSET_URL: ${{ steps.resolve-binary.outputs.asset_url }} + run: | + set -euo pipefail + + curl --fail --location \ + -H "Authorization: token ${TOKEN}" \ + -o vociferate \ + "$ASSET_URL" + chmod +x vociferate + + - name: Smoke test released binary + env: + RUN_COMMAND: ${{ matrix.run_command }} + run: | + set -euo pipefail + + recommended_tag="$($RUN_COMMAND --recommend --root .)" + case "$recommended_tag" in + v*.*.*) + ;; + *) + echo "Unexpected recommended tag: $recommended_tag" >&2 + exit 1 + ;; + esac + + { + echo "## Released Binary Validation" + echo + echo "- Release tag: ${{ steps.resolve-binary.outputs.release_tag }}" + echo "- Asset: ${{ steps.resolve-binary.outputs.asset_name }}" + echo "- Recommended tag: ${recommended_tag}" + } >> "$GITHUB_STEP_SUMMARY" \ No newline at end of file diff --git a/README.md b/README.md index b3b9a73..4a78bdc 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ Use the composite action directly: ```yaml - name: Prepare release files - uses: git.hrafn.xyz/aether/vociferate@main + uses: git.hrafn.xyz/aether/vociferate@v1.0.0 with: version-file: internal/myapp/version/version.go version-pattern: 'const Version = "([^"]+)"' @@ -80,6 +80,7 @@ Use the composite action directly: ``` Set `version` only when you want to override the recommended version. +Pin the composite action to a released tag. It downloads a prebuilt Linux binary from vociferate releases and caches it on the runner, so it does not require installing Go. Call the reusable release workflow: diff --git a/action.yml b/action.yml index 5425934..edfc1d2 100644 --- a/action.yml +++ b/action.yml @@ -2,6 +2,10 @@ name: vociferate description: Prepare release files or recommend a next semantic version tag. inputs: + token: + description: Optional token used to download the cached vociferate release binary. When omitted, the workflow token is used. + required: false + default: '' version: description: Optional semantic version override. When omitted, the recommended version is used. required: false @@ -32,13 +36,87 @@ runs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 + - name: Resolve vociferate binary metadata + id: resolve-binary + shell: bash + env: + ACTION_REF: ${{ github.action_ref }} + SERVER_URL: ${{ github.server_url }} + API_URL: ${{ github.api_url }} + TOKEN: ${{ inputs.token != '' && inputs.token || github.token }} + RUNNER_ARCH: ${{ runner.arch }} + RUNNER_TEMP: ${{ runner.temp }} + run: | + set -euo pipefail + + case "$RUNNER_ARCH" in + X64) + arch="amd64" + ;; + ARM64) + arch="arm64" + ;; + *) + echo "Unsupported runner architecture: $RUNNER_ARCH" >&2 + exit 1 + ;; + esac + + release_tag="$ACTION_REF" + if [[ -z "$release_tag" || "$release_tag" == refs/* || "$release_tag" != v* ]]; then + release_tag="$(curl -fsSL \ + -H "Authorization: token ${TOKEN}" \ + -H "Content-Type: application/json" \ + "${API_URL}/repos/aether/vociferate/releases/latest" | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n 1)" + fi + + if [[ -z "$release_tag" ]]; then + echo "Unable to resolve a vociferate release tag for binary download" >&2 + exit 1 + fi + + normalized_version="${release_tag#v}" + asset_name="vociferate_${normalized_version}_linux_${arch}" + cache_dir="${RUNNER_TEMP}/vociferate/${release_tag}/linux-${arch}" + binary_path="${cache_dir}/vociferate" + asset_url="${SERVER_URL}/aether/vociferate/releases/download/${release_tag}/${asset_name}" + + mkdir -p "$cache_dir" + + echo "release_tag=$release_tag" >> "$GITHUB_OUTPUT" + echo "asset_name=$asset_name" >> "$GITHUB_OUTPUT" + echo "asset_url=$asset_url" >> "$GITHUB_OUTPUT" + echo "cache_dir=$cache_dir" >> "$GITHUB_OUTPUT" + echo "binary_path=$binary_path" >> "$GITHUB_OUTPUT" + + - name: Restore cached vociferate binary + id: cache-vociferate + uses: actions/cache@v4 with: - go-version: '1.26.1' + path: ${{ steps.resolve-binary.outputs.cache_dir }} + key: vociferate-${{ steps.resolve-binary.outputs.release_tag }}-linux-${{ runner.arch }} + + - name: Download vociferate binary + if: steps.cache-vociferate.outputs.cache-hit != 'true' + shell: bash + env: + TOKEN: ${{ inputs.token != '' && inputs.token || github.token }} + ASSET_URL: ${{ steps.resolve-binary.outputs.asset_url }} + BINARY_PATH: ${{ steps.resolve-binary.outputs.binary_path }} + run: | + set -euo pipefail + + curl --fail --location \ + -H "Authorization: token ${TOKEN}" \ + -o "$BINARY_PATH" \ + "$ASSET_URL" + chmod +x "$BINARY_PATH" - name: Run vociferate id: run-vociferate shell: bash + env: + VOCIFERATE_BIN: ${{ steps.resolve-binary.outputs.binary_path }} run: | set -euo pipefail @@ -57,16 +135,16 @@ runs: fi if [[ "${{ inputs.recommend }}" == "true" ]]; then - resolved_version="$(go run git.hrafn.xyz/aether/vociferate/cmd/vociferate@latest "${common_args[@]}" --recommend)" + resolved_version="$("$VOCIFERATE_BIN" "${common_args[@]}" --recommend)" echo "$resolved_version" echo "version=$resolved_version" >> "$GITHUB_OUTPUT" exit 0 else resolved_version="$(printf '%s' "${{ inputs.version }}" | sed 's/^[[:space:]]\+//; s/[[:space:]]\+$//')" if [[ -z "$resolved_version" ]]; then - resolved_version="$(go run git.hrafn.xyz/aether/vociferate/cmd/vociferate@latest "${common_args[@]}" --recommend)" + resolved_version="$("$VOCIFERATE_BIN" "${common_args[@]}" --recommend)" fi fi echo "version=$resolved_version" >> "$GITHUB_OUTPUT" - go run git.hrafn.xyz/aether/vociferate/cmd/vociferate@latest "${common_args[@]}" --version "$resolved_version" --date "$(date -u +%F)" + "$VOCIFERATE_BIN" "${common_args[@]}" --version "$resolved_version" --date "$(date -u +%F)" diff --git a/changelog.md b/changelog.md index 9b1f555..be19d26 100644 --- a/changelog.md +++ b/changelog.md @@ -11,6 +11,8 @@ A `### Breaking` section is used in addition to Keep a Changelog's standard sect ### Changed +- The composite action now downloads and caches a released Linux `vociferate` binary instead of installing Go and running the module source directly. +- Added workflow coverage for the released Linux binaries consumed by the composite action on both `amd64` and `arm64`. - Release preparation now runs directly in the release workflow; the repository-local helper script and just recipe were removed. - Release artifacts are now limited to `linux/amd64` and `linux/arm64` binaries plus `checksums.txt`. - The CLI entrypoint, internal package paths, build outputs, and automation references now use the `vociferate` name instead of the earlier `releaseprep` naming.