blob: be9ee1236bc12a9812ccde7d9eac7e98c4fe5eb3 [file] [edit]
# Reusable workflow that can be referenced by repositories in their `.github/workflows/release.yaml`.
# See example usage in https://github.com/bazel-contrib/rules-template/blob/main/.github/workflows/release.yaml
#
# This workflow calls `.github/workflows/release_prep.sh` as the command to prepare the release.
# Release notes are expected to be outputted to stdout from the release prep command.
#
# This workflow uses https://github.com/bazel-contrib/setup-bazel to prepare the cache folders.
# Caching may be disabled by setting `mount_bazel_caches` to false.
#
# The workflow requires the following permissions to be set on the invoking job:
#
# permissions:
# id-token: write # Needed to attest provenance
# attestations: write # Needed to attest provenance
# contents: write # Needed to upload release files
permissions: {}
on:
# Make this workflow reusable, see
# https://github.blog/2022-02-10-using-reusable-workflows-github-actions
workflow_call:
inputs:
release_files:
required: true
description: |
Newline-delimited globs of paths to assets to upload for release.
relative to the module repository. The paths should include any files
such as a release archive created by the release_prep script`.
See https://github.com/softprops/action-gh-release#inputs.
type: string
# TODO: there's a security design problem here:
# Users of a workflow_dispatch trigger could fill in something via the GH Web UI
# that would cause the release to use an arbitrary script.
# That change wouldn't be reflected in the sources in the repo, and therefore
# would not be verifiable by the attestation.
# For now, we force this path to be hard-coded.
#
# release_prep_command:
# default: .github/workflows/release_prep.sh
# description: |
# Command to run to prepare the release and generate release notes.
# Release notes are expected to be outputted to stdout.
# type: string
bazel_test_command:
default: "bazel test //..."
description: |
Bazel test command that may be overridden to set custom flags and targets.
The --disk_cache=~/.cache/bazel-disk-cache --repository_cache=~/.cache/bazel-repository-cache flags are
automatically appended to the command.
type: string
mount_bazel_caches:
default: true
description: |
Whether to enable caching in the bazel-contrib/setup-bazel action.
type: boolean
prerelease:
default: true
description: Indicator of whether or not this is a prerelease.
type: boolean
draft:
default: false
description: |
Whether the release should be created as a draft or published immediately.
type: boolean
generate_release_notes:
default: true
description: |
Whether to automatically generate the name and body for this release.
Controls the like-named setting on https://github.com/softprops/action-gh-release#inputs
The output of release_prep.sh will be pre-pended to the automatically generated notes.
type: boolean
tag_name:
description: |
The tag which is being released.
By default, https://github.com/softprops/action-gh-release will use `github.ref_name`.
type: string
jobs:
build:
outputs:
release-files-artifact-id: ${{ steps.upload-release-files.outputs.artifact-id }}
release-notes-artifact-id: ${{ steps.upload-release-notes.outputs.artifact-id }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: 34.0-hack1
- uses: bazel-contrib/setup-bazel@083175551ceeceebc757ebee2127fde78840ca77 # v0.18.0
with:
disk-cache: ${{ inputs.mount_bazel_caches }}
external-cache: ${{ inputs.mount_bazel_caches }}
repository-cache: ${{ inputs.mount_bazel_caches }}
- name: Test
run: ${{ inputs.bazel_test_command }} --disk_cache=~/.cache/bazel-disk-cache --repository_cache=~/.cache/bazel-repository-cache
# Fetch built artifacts (if any) from earlier jobs, which the release script may want to read.
# Extract into ${GITHUB_WORKSPACE}/artifacts/*
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
- name: Build release artifacts and prepare release notes
run: |
if [ ! -f ".github/workflows/release_prep.sh" ]; then
echo "ERROR: create a .github/workflows/release_prep.sh script"
exit 1
fi
.github/workflows/release_prep.sh v34.0
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
id: upload-release-files
with:
name: release_files
path: ${{ inputs.release_files }}
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
id: upload-release-notes
with:
name: release_notes
path: release_notes.txt
attest:
needs: build
outputs:
attestations-artifact-id: ${{ steps.upload-attestations.outputs.artifact-id }}
permissions:
id-token: write
attestations: write
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
artifact-ids: ${{ needs.build.outputs.release-files-artifact-id }}
path: release_files
# https://github.com/actions/attest-build-provenance
- name: Attest release files
id: attest_release
uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0
with:
subject-path: release_files/**/*
# The Bazel Central Registry requires an attestation per release archive, but the
# actions/attest-build-provenance action only produces a single attestation for a
# list of subjects. Copy the combined attestations into individually named
# .intoto.jsonl files.
- name: Write release archive attestations into intoto.jsonl
id: write_release_archive_attestation
run: |
# https://bazel.build/rules/lib/repo/http#http_archive
RELEASE_ARCHIVE_REGEX="(\.zip|\.jar|\.war|\.aar|\.tar|\.tar\.gz|\.tgz|\.tar\.xz|\.txz|\.tar\.xzt|\.tzst|\.tar\.bz2|\.ar|\.deb)$"
ATTESTATIONS_DIR=$(mktemp --directory)
for filename in $(find release_files/ -type f -printf "%f\n"); do
if [[ "${filename}" =~ $RELEASE_ARCHIVE_REGEX ]]; then
ATTESTATION_FILE="$(basename "${filename}").intoto.jsonl"
echo "Writing attestation to ${ATTESTATION_FILE}"
cat ${{ steps.attest_release.outputs.bundle-path }} | jq --compact-output > "${ATTESTATIONS_DIR}/${ATTESTATION_FILE}"
fi
done
echo "release_archive_attestations_dir=${ATTESTATIONS_DIR}" >> $GITHUB_OUTPUT
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
id: upload-attestations
with:
name: attestations
path: ${{ steps.write_release_archive_attestation.outputs.release_archive_attestations_dir }}/*
release:
needs: [build, attest]
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
artifact-ids: ${{ needs.build.outputs.release-files-artifact-id }}
path: release_files
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
artifact-ids: ${{ needs.build.outputs.release-notes-artifact-id }}
path: release_notes
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
artifact-ids: ${{ needs.attest.outputs.attestations-artifact-id }}
path: attestations
- name: Release
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
with:
prerelease: ${{ inputs.prerelease }}
draft: ${{ inputs.draft }}
# Use GH feature to populate the changelog automatically
generate_release_notes: ${{ inputs.generate_release_notes }}
body_path: release_notes/release_notes.txt
fail_on_unmatched_files: true
tag_name: ${{ inputs.tag_name }}
files: |
release_files/**/*
attestations/*