update from upstream #3636
Workflow file for this run
This file contains 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
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json | |
name: Build | |
on: | |
push: | |
branches: | |
- main | |
pull_request: | |
branches: | |
- main | |
permissions: | |
contents: read | |
checks: write | |
pull-requests: write | |
issues: write | |
packages: write | |
env: | |
CARGO_TERM_COLOR: always | |
# set this to true in GitHub variables to enable building the container | |
# HAS_CONTAINER: true | |
# Use docker.io for Docker Hub if empty | |
REGISTRY: ghcr.io | |
# github.repository as <account>/<repo> | |
IMAGE_NAME: ${{ github.repository }} | |
# just a name, but storing it separately as we're nice people | |
RUSTFLAGS: --deny=warnings | |
concurrency: | |
# each new commit to a PR runs this workflow | |
# so we need to avoid a long running older one from overwriting the "pr-<number>-latest" | |
group: "${{ github.workflow }} @ ${{ github.ref_name }}" | |
cancel-in-progress: true | |
jobs: | |
build-rust: | |
name: Build Rust code | |
uses: ./.github/workflows/build-rust.yml | |
secrets: inherit | |
build-typescript: | |
name: Build TypeScript code | |
uses: ./.github/workflows/build-typescript.yml | |
secrets: inherit | |
repo-has-container: | |
name: Repo has container? | |
runs-on: ubuntu-latest | |
outputs: | |
has_container: ${{ steps.determine.outputs.has_container }} | |
steps: | |
- name: Repo has docker container? | |
shell: bash | |
id: determine | |
run: | | |
HAS_CONTAINER="${{ vars.HAS_CONTAINER }}" | |
echo "has_container=${HAS_CONTAINER:-false}" >> ${GITHUB_OUTPUT} | |
changes: | |
name: Detect changes | |
runs-on: ubuntu-latest | |
outputs: | |
docker: ${{ steps.filter.outputs.docker }} | |
rust: ${{ steps.filter.outputs.rust }} | |
typescript: ${{ steps.filter.outputs.typescript }} | |
steps: | |
- name: Checkout | |
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
with: | |
show-progress: false | |
submodules: true | |
- name: Check if we actually made changes | |
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 | |
id: filter | |
with: | |
token: ${{ secrets.GITHUB_TOKEN }} | |
filters: .github/file-filters.yml | |
calculate-version: | |
name: Calculate version | |
runs-on: ubuntu-latest | |
needs: | |
- changes | |
- repo-has-container | |
outputs: | |
version: ${{ steps.version.outputs.version }} | |
if: | | |
github.event_name == 'pull_request' && | |
fromJSON(needs.repo-has-container.outputs.has_container) == true && | |
( | |
fromJSON(needs.changes.outputs.docker) == true || | |
fromJSON(needs.changes.outputs.rust) == true || | |
fromJSON(needs.changes.outputs.typescript) == true | |
) | |
steps: | |
- name: Checkout | |
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
with: | |
show-progress: false | |
fetch-depth: 0 | |
- name: Cache dependencies | |
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 | |
env: | |
CACHE_NAME: cargo-cache-dependencies | |
with: | |
path: | | |
~/.cargo | |
./target | |
key: ${{ runner.os }}-build-${{ env.CACHE_NAME }}-${{ hashFiles('Cargo.lock') }}-cocogitto | |
restore-keys: | | |
${{ runner.os }}-build-${{ env.CACHE_NAME }}-${{ hashFiles('Cargo.lock') }}- | |
${{ runner.os }}-build-${{ env.CACHE_NAME }}- | |
- name: Set up mold | |
uses: rui314/setup-mold@8ec40be1d14871f7ce8fbf273c4b33f3ff75f1d1 # v1 | |
- name: Set up toolchain | |
shell: bash | |
run: | | |
rm ${HOME}/.cargo/bin/cargo-fmt | |
rm ${HOME}/.cargo/bin/rust-analyzer | |
rm ${HOME}/.cargo/bin/rustfmt | |
rustup update | |
cargo --version | |
- name: Get binstall | |
shell: bash | |
run: | | |
cd /tmp | |
archive="cargo-binstall-x86_64-unknown-linux-musl.tgz" | |
wget "https://github.com/cargo-bins/cargo-binstall/releases/latest/download/${archive}" | |
tar -xvf "./${archive}" | |
rm "./${archive}" | |
mv ./cargo-binstall ~/.cargo/bin/ | |
- name: Install cocogitto to get the next version number | |
shell: bash | |
run: | | |
cargo binstall --no-confirm cocogitto --target x86_64-unknown-linux-musl --pkg-url "{ repo }/releases/download/{ version }/{ name }-{ version }-{ target }.tar.gz" --bin-dir "{ bin }" --pkg-fmt tgz | |
- name: Calculate next version | |
shell: bash | |
id: version | |
run: | | |
VERSION="$(cog bump --auto --dry-run || true)" | |
if [[ "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | |
echo "New version: ${VERSION}" | |
else | |
VERSION="v$(cog -v get-version)" | |
echo "No version generated, defaulting to latest tag: ${VERSION}" | |
fi | |
# remove v | |
VERSION="${VERSION//v/}" | |
# store | |
echo "version=${VERSION}" >> ${GITHUB_OUTPUT} | |
docker-build: | |
name: Build Docker container | |
runs-on: ubuntu-latest | |
needs: | |
- calculate-version | |
- repo-has-container | |
- changes | |
if: | | |
github.event_name == 'pull_request' && | |
fromJSON(needs.repo-has-container.outputs.has_container) == true && | |
(!( | |
contains(needs.*.result, 'failure') || | |
contains(needs.*.result, 'cancelled') | |
)) && | |
( | |
fromJSON(needs.changes.outputs.docker) == true || | |
fromJSON(needs.changes.outputs.rust) == true || | |
fromJSON(needs.changes.outputs.typescript) == true | |
) | |
env: | |
APPLICATION_NAME: PLACEHOLDER # overridden in step 'Set application name', this is merely to satisfy the linter | |
PATH_TO_TAR: PLACEHOLDER # same ^ | |
UNIQUE_TAG: PLACEHOLDER # same ^ | |
steps: | |
- name: Checkout | |
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
with: | |
show-progress: false | |
- name: Get binstall | |
shell: bash | |
run: | | |
archive="cargo-binstall-x86_64-unknown-linux-musl.tgz" | |
wget "https://github.com/cargo-bins/cargo-binstall/releases/latest/download/${archive}" | |
tar -xvf "./${archive}" | |
rm "./${archive}" | |
mv ./cargo-binstall ~/.cargo/bin/ | |
- name: Install binstall to do set-version | |
shell: bash | |
run: | | |
cargo binstall cargo-edit | |
- name: Set the Cargo.toml version before we copy in the data into the Docker container | |
shell: bash | |
run: | | |
cargo set-version ${{ needs.calculate-version.outputs.version }} | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0 | |
# TODO validate no changes between github.event.pull_request.head.sha and the actual current sha (representing the hypothetical merge) | |
- name: Lowercase the image name | |
shell: bash | |
run: | | |
echo "IMAGE_NAME=${IMAGE_NAME,,}" >> ${GITHUB_ENV} | |
- name: Set Docker tag | |
shell: bash | |
run: | | |
UNIQUE_TAG=pr-${{ github.event.pull_request.base.sha }}-${{ github.event.pull_request.head.sha }} | |
echo "UNIQUE_TAG=${UNIQUE_TAG##*/}" >> ${GITHUB_ENV} | |
# Extract metadata (tags, labels) for Docker | |
# https://github.com/docker/metadata-action | |
- name: Extract Docker metadata | |
uses: docker/metadata-action@369eb591f429131d6889c46b94e711f089e6ca96 # v5.6.1 | |
id: meta | |
with: | |
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
tags: | | |
type=raw,value=${{ env.UNIQUE_TAG }} | |
labels: | | |
org.opencontainers.image.version=pr-${{ github.event.number }} | |
org.opencontainers.image.source=${{ github.event.pull_request.html_url }} | |
- name: Log into registry ${{ env.REGISTRY }} | |
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 | |
with: | |
registry: ${{ env.REGISTRY }} | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Set application name | |
shell: bash | |
run: | | |
APPLICATION_NAME=${{ github.repository }} | |
echo "APPLICATION_NAME=${APPLICATION_NAME##*/}" >> ${GITHUB_ENV} | |
- name: Build Docker image | |
uses: docker/build-push-action@b32b51a8eda65d6793cd0494a773d4f6bcef32dc # v6.11.0 | |
with: | |
build-args: | | |
APPLICATION_NAME=${{ env.APPLICATION_NAME }} | |
context: . | |
# this container is THE PR's artifact, and we will re-tag it | |
# once the PR has been accepted | |
tags: ${{ steps.meta.outputs.tags }} | |
labels: ${{ steps.meta.outputs.labels }} | |
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache-${{ env.APPLICATION_NAME }} | |
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache-${{ env.APPLICATION_NAME }},mode=max | |
platforms: linux/amd64, linux/arm64 | |
outputs: type=oci,dest=/tmp/${{ env.UNIQUE_TAG }}.tar | |
- name: Upload artifact | |
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 | |
with: | |
name: containers-${{ env.APPLICATION_NAME }} | |
path: /tmp/${{ env.UNIQUE_TAG }}.tar | |
if-no-files-found: error | |
retention-days: 1 | |
docker-publish: | |
name: Publish Docker container | |
runs-on: ubuntu-latest | |
needs: | |
- docker-build | |
# Check if the event is not triggered by a fork | |
if: | | |
github.event.pull_request.head.repo.full_name == github.repository && | |
github.event_name == 'pull_request' | |
env: | |
APPLICATION_NAME: PLACEHOLDER # overridden in step 'Set application name', this is merely to satisfy the linter | |
steps: | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0 | |
- name: Download artifact | |
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 | |
with: | |
path: /tmp/containers | |
pattern: containers-* | |
merge-multiple: true | |
- name: Log into registry ${{ env.REGISTRY }} | |
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 | |
with: | |
registry: ${{ env.REGISTRY }} | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Set application name | |
shell: bash | |
run: | | |
APPLICATION_NAME=${{ github.repository }} | |
echo "APPLICATION_NAME=${APPLICATION_NAME##*/}" >> ${GITHUB_ENV} | |
- name: Lowercase the image name | |
shell: bash | |
run: | | |
echo "IMAGE_NAME=${IMAGE_NAME,,}" >> ${GITHUB_ENV} | |
- name: Ensure we have oras | |
uses: oras-project/setup-oras@9c92598691bfef1424de2f8fae81941568f5889c # v1.2.1 | |
- name: Load images from artifacts | |
shell: bash | |
id: image | |
working-directory: /tmp/containers | |
run: | | |
echo "${{ secrets.GITHUB_TOKEN }}" | oras login -u "${{ github.actor }}" --password-stdin ${{ env.REGISTRY }} | |
ls -l /tmp/containers | |
for container in /tmp/containers/* | |
do | |
echo "Found ${container}" | |
tag=$(basename -- $container .tar) | |
oras copy --from-oci-layout "${container}:${tag}" "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${tag}" | |
done | |
- name: Extract Docker metadata | |
uses: docker/metadata-action@369eb591f429131d6889c46b94e711f089e6ca96 # v5.6.1 | |
id: meta | |
with: | |
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
tags: | | |
type=ref,event=pr,suffix=-latest | |
type=raw,value=pr-${{ github.event.pull_request.base.sha }}-${{ github.event.pull_request.head.sha }} | |
- name: Merge images | |
shell: bash | |
working-directory: /tmp/containers | |
run: | | |
# all files in dir | |
containers=(*) | |
# yeet extension | |
containers=${containers[@]%.tar} | |
new_tags="${{ join(steps.meta.outputs.tags, ' ') }}" | |
new_tags=$(printf -- '--tag %s ' $new_tags) | |
expanded_containters_tags=$(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:%s ' ${containers}) | |
docker buildx imagetools create $new_tags $expanded_containters_tags | |
for new_tag in $(echo "${{ join(steps.meta.outputs.tags, ' ') }}"); do | |
docker buildx imagetools inspect --raw $new_tag | |
done | |
all-done: | |
name: All done | |
# this is the job that should be marked as required on GitHub. It's the only one that'll reliably trigger | |
# when any upstream fails: success | |
# when all upstream skips: pass | |
# when all upstream success: success | |
# combination of upstream skip and success: success | |
runs-on: ubuntu-latest | |
needs: | |
- build-rust | |
- build-typescript | |
- docker-build | |
- docker-publish | |
if: | | |
always() | |
steps: | |
- name: Fail! | |
shell: bash | |
if: | | |
contains(needs.*.result, 'failure') || | |
contains(needs.*.result, 'cancelled') | |
run: | | |
echo "One / more upstream failed or was cancelled. Failing job..." | |
exit 1 | |
- name: Success! | |
shell: bash | |
run: | | |
echo "Great success!" |