Some checks failed
Release Docker Image / define-variables (pull_request) Successful in 8s
Documentation / Build and Deploy Documentation (pull_request) Successful in 27s
Checks / Prek / Pre-commit & Formatting (pull_request) Successful in 41s
Checks / Prek / Clippy and Cargo Tests (pull_request) Successful in 4m31s
Release Docker Image / build-image (linux/amd64, release, linux-amd64, base) (pull_request) Successful in 6m27s
Release Docker Image / build-image (linux/arm64, release, linux-arm64, base) (pull_request) Successful in 6m47s
Release Docker Image / merge (pull_request) Successful in 8s
Release Docker Image / define-variables (push) Successful in 6s
Release Docker Image / build-image (linux/amd64, release, linux-amd64, base) (push) Has been cancelled
Release Docker Image / build-image (linux/arm64, release, linux-arm64, base) (push) Has been cancelled
Release Docker Image / merge (push) Has been cancelled
Documentation / Build and Deploy Documentation (push) Successful in 30s
Checks / Prek / Pre-commit & Formatting (push) Has been cancelled
Checks / Prek / Clippy and Cargo Tests (push) Has been cancelled
After #992, builds without registry credentials skip Docker image output but still extract binary artifacts. However, we were still trying to upload digests for images that weren't created. Add conditional check to only upload digests when actually pushing to registry.
333 lines
14 KiB
YAML
333 lines
14 KiB
YAML
name: Release Docker Image
|
|
concurrency:
|
|
group: "release-image-${{ github.ref }}"
|
|
|
|
on:
|
|
pull_request:
|
|
paths-ignore:
|
|
- "*.md"
|
|
- "**/*.md"
|
|
- ".gitlab-ci.yml"
|
|
- ".gitignore"
|
|
- "renovate.json"
|
|
- "pkg/**"
|
|
- "docs/**"
|
|
push:
|
|
branches:
|
|
- main
|
|
paths-ignore:
|
|
- "*.md"
|
|
- "**/*.md"
|
|
- ".gitlab-ci.yml"
|
|
- ".gitignore"
|
|
- "renovate.json"
|
|
- "pkg/**"
|
|
- "docs/**"
|
|
# Allows you to run this workflow manually from the Actions tab
|
|
workflow_dispatch:
|
|
|
|
env:
|
|
BUILTIN_REGISTRY: forgejo.ellis.link
|
|
BUILTIN_REGISTRY_ENABLED: "${{ ((vars.BUILTIN_REGISTRY_USER && secrets.BUILTIN_REGISTRY_PASSWORD) || (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false)) && 'true' || 'false' }}"
|
|
|
|
jobs:
|
|
define-variables:
|
|
runs-on: ubuntu-latest
|
|
|
|
outputs:
|
|
images: ${{ steps.var.outputs.images }}
|
|
images_list: ${{ steps.var.outputs.images_list }}
|
|
build_matrix: ${{ steps.var.outputs.build_matrix }}
|
|
|
|
steps:
|
|
- name: Setting variables
|
|
uses: https://github.com/actions/github-script@v7
|
|
id: var
|
|
with:
|
|
script: |
|
|
const githubRepo = '${{ github.repository }}'.toLowerCase()
|
|
const repoId = githubRepo.split('/')[1]
|
|
|
|
core.setOutput('github_repository', githubRepo)
|
|
const builtinImage = '${{ env.BUILTIN_REGISTRY }}/' + githubRepo
|
|
let images = []
|
|
if (process.env.BUILTIN_REGISTRY_ENABLED === "true") {
|
|
images.push(builtinImage)
|
|
} else {
|
|
// Fallback to official registry for forks/PRs without credentials
|
|
images.push('forgejo.ellis.link/continuwuation/continuwuity')
|
|
}
|
|
core.setOutput('images', images.join("\n"))
|
|
core.setOutput('images_list', images.join(","))
|
|
const platforms = ['linux/amd64', 'linux/arm64']
|
|
core.setOutput('build_matrix', JSON.stringify({
|
|
platform: platforms,
|
|
target_cpu: ['base'],
|
|
include: platforms.map(platform => { return {
|
|
platform,
|
|
slug: platform.replace('/', '-')
|
|
}})
|
|
}))
|
|
|
|
build-image:
|
|
runs-on: dind
|
|
needs: define-variables
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
attestations: write
|
|
id-token: write
|
|
strategy:
|
|
matrix:
|
|
{
|
|
"target_cpu": ["base"],
|
|
"profile": ["release"],
|
|
"include":
|
|
[
|
|
{ "platform": "linux/amd64", "slug": "linux-amd64" },
|
|
{ "platform": "linux/arm64", "slug": "linux-arm64" },
|
|
],
|
|
"platform": ["linux/amd64", "linux/arm64"],
|
|
}
|
|
|
|
steps:
|
|
- name: Echo strategy
|
|
run: echo '${{ toJSON(fromJSON(needs.define-variables.outputs.build_matrix)) }}'
|
|
- name: Echo matrix
|
|
run: echo '${{ toJSON(matrix) }}'
|
|
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
with:
|
|
persist-credentials: false
|
|
- name: Install rust
|
|
if: ${{ env.BUILDKIT_ENDPOINT == '' }}
|
|
id: rust-toolchain
|
|
uses: ./.forgejo/actions/rust-toolchain
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
with:
|
|
# Use persistent BuildKit if BUILDKIT_ENDPOINT is set (e.g. tcp://buildkit:8125)
|
|
driver: ${{ env.BUILDKIT_ENDPOINT != '' && 'remote' || 'docker-container' }}
|
|
endpoint: ${{ env.BUILDKIT_ENDPOINT || '' }}
|
|
- name: Set up QEMU
|
|
if: ${{ env.BUILDKIT_ENDPOINT == '' }}
|
|
uses: docker/setup-qemu-action@v3
|
|
# Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here.
|
|
- name: Login to builtin registry
|
|
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ${{ env.BUILTIN_REGISTRY }}
|
|
username: ${{ vars.BUILTIN_REGISTRY_USER || github.actor }}
|
|
password: ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}
|
|
|
|
# This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels.
|
|
- name: Extract metadata (labels, annotations) for Docker
|
|
id: meta
|
|
uses: docker/metadata-action@v5
|
|
with:
|
|
images: ${{needs.define-variables.outputs.images}}
|
|
# default labels & annotations: https://github.com/docker/metadata-action/blob/master/src/meta.ts#L509
|
|
env:
|
|
DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index
|
|
|
|
# This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages.
|
|
# It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository.
|
|
# It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step.
|
|
# It will not push images generated from a pull request
|
|
- name: Get short git commit SHA
|
|
id: sha
|
|
run: |
|
|
calculatedSha=$(git rev-parse --short ${{ github.sha }})
|
|
echo "COMMIT_SHORT_SHA=$calculatedSha" >> $GITHUB_ENV
|
|
echo "Short SHA: $calculatedSha"
|
|
- name: Get Git commit timestamps
|
|
run: |
|
|
timestamp=$(git log -1 --pretty=%ct)
|
|
echo "TIMESTAMP=$timestamp" >> $GITHUB_ENV
|
|
echo "Commit timestamp: $timestamp"
|
|
|
|
- uses: ./.forgejo/actions/timelord
|
|
if: ${{ env.BUILDKIT_ENDPOINT == '' }}
|
|
with:
|
|
key: timelord-v0
|
|
path: .
|
|
|
|
- name: Cache Rust registry
|
|
if: ${{ env.BUILDKIT_ENDPOINT == '' }}
|
|
uses: actions/cache@v3
|
|
with:
|
|
path: |
|
|
.cargo/git
|
|
.cargo/git/checkouts
|
|
.cargo/registry
|
|
.cargo/registry/src
|
|
key: rust-registry-image-${{hashFiles('**/Cargo.lock') }}
|
|
- name: Cache cargo target
|
|
if: ${{ env.BUILDKIT_ENDPOINT == '' }}
|
|
id: cache-cargo-target
|
|
uses: actions/cache@v3
|
|
with:
|
|
path: |
|
|
cargo-target-${{ matrix.target_cpu }}-${{ matrix.slug }}-${{ matrix.profile }}
|
|
key: cargo-target-${{ matrix.target_cpu }}-${{ matrix.slug }}-${{ matrix.profile }}-${{hashFiles('**/Cargo.lock') }}-${{steps.rust-toolchain.outputs.rustc_version}}
|
|
- name: Cache apt cache
|
|
if: ${{ env.BUILDKIT_ENDPOINT == '' }}
|
|
id: cache-apt
|
|
uses: actions/cache@v3
|
|
with:
|
|
path: |
|
|
var-cache-apt-${{ matrix.slug }}
|
|
key: var-cache-apt-${{ matrix.slug }}
|
|
- name: Cache apt lib
|
|
if: ${{ env.BUILDKIT_ENDPOINT == '' }}
|
|
id: cache-apt-lib
|
|
uses: actions/cache@v3
|
|
with:
|
|
path: |
|
|
var-lib-apt-${{ matrix.slug }}
|
|
key: var-lib-apt-${{ matrix.slug }}
|
|
- name: inject cache into docker
|
|
if: ${{ env.BUILDKIT_ENDPOINT == '' }}
|
|
uses: https://github.com/reproducible-containers/buildkit-cache-dance@v3.3.0
|
|
with:
|
|
cache-map: |
|
|
{
|
|
".cargo/registry": "/usr/local/cargo/registry",
|
|
".cargo/git/db": "/usr/local/cargo/git/db",
|
|
"cargo-target-${{ matrix.target_cpu }}-${{ matrix.slug }}-${{ matrix.profile }}": {
|
|
"target": "/app/target",
|
|
"id": "cargo-target-${{ matrix.target_cpu }}-${{ matrix.slug }}-${{ matrix.profile }}"
|
|
},
|
|
"var-cache-apt-${{ matrix.slug }}": "/var/cache/apt",
|
|
"var-lib-apt-${{ matrix.slug }}": "/var/lib/apt"
|
|
}
|
|
skip-extraction: ${{ steps.cache.outputs.cache-hit }}
|
|
|
|
- name: Build and push Docker image by digest
|
|
id: build
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: .
|
|
file: "docker/Dockerfile"
|
|
build-args: |
|
|
GIT_COMMIT_HASH=${{ github.sha }}
|
|
GIT_COMMIT_HASH_SHORT=${{ env.COMMIT_SHORT_SHA }}
|
|
GIT_REMOTE_URL=${{github.event.repository.html_url }}
|
|
GIT_REMOTE_COMMIT_URL=${{github.event.head_commit.url }}
|
|
platforms: ${{ matrix.platform }}
|
|
labels: ${{ steps.meta.outputs.labels }}
|
|
annotations: ${{ steps.meta.outputs.annotations }}
|
|
cache-from: type=gha
|
|
# cache-to: type=gha,mode=max
|
|
sbom: true
|
|
outputs: |
|
|
${{ env.BUILTIN_REGISTRY_ENABLED == 'true' && format('type=image,"name={0}",push-by-digest=true,name-canonical=true,push=true', needs.define-variables.outputs.images_list) || format('type=image,"name={0}",push=false', needs.define-variables.outputs.images_list) }}
|
|
type=local,dest=/tmp/binaries
|
|
env:
|
|
SOURCE_DATE_EPOCH: ${{ env.TIMESTAMP }}
|
|
|
|
# For publishing multi-platform manifests
|
|
- name: Export digest
|
|
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
|
|
run: |
|
|
mkdir -p /tmp/digests
|
|
digest="${{ steps.build.outputs.digest }}"
|
|
touch "/tmp/digests/${digest#sha256:}"
|
|
|
|
# Binary extracted via local output for all builds
|
|
- name: Rename extracted binary
|
|
run: mv /tmp/binaries/sbin/conduwuit /tmp/binaries/conduwuit-${{ matrix.target_cpu }}-${{ matrix.slug }}-${{ matrix.profile }}
|
|
|
|
- name: Upload binary artifact
|
|
uses: forgejo/upload-artifact@v4
|
|
with:
|
|
name: conduwuit-${{ matrix.target_cpu }}-${{ matrix.slug }}-${{ matrix.profile }}
|
|
path: /tmp/binaries/conduwuit-${{ matrix.target_cpu }}-${{ matrix.slug }}-${{ matrix.profile }}
|
|
if-no-files-found: error
|
|
|
|
- name: Upload digest
|
|
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
|
|
uses: forgejo/upload-artifact@v4
|
|
with:
|
|
name: digests-${{ matrix.slug }}
|
|
path: /tmp/digests/*
|
|
if-no-files-found: error
|
|
retention-days: 5
|
|
|
|
merge:
|
|
runs-on: dind
|
|
needs: [define-variables, build-image]
|
|
steps:
|
|
- name: Download digests
|
|
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
|
|
uses: forgejo/download-artifact@v4
|
|
with:
|
|
path: /tmp/digests
|
|
pattern: digests-*
|
|
merge-multiple: true
|
|
# Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here.
|
|
- name: Login to builtin registry
|
|
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ${{ env.BUILTIN_REGISTRY }}
|
|
username: ${{ vars.BUILTIN_REGISTRY_USER || github.actor }}
|
|
password: ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Set up Docker Buildx
|
|
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
|
|
uses: docker/setup-buildx-action@v3
|
|
with:
|
|
# Use persistent BuildKit if BUILDKIT_ENDPOINT is set (e.g. tcp://buildkit:8125)
|
|
driver: ${{ env.BUILDKIT_ENDPOINT != '' && 'remote' || 'docker-container' }}
|
|
endpoint: ${{ env.BUILDKIT_ENDPOINT || '' }}
|
|
|
|
- name: Extract metadata (tags) for Docker
|
|
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
|
|
id: meta
|
|
uses: docker/metadata-action@v5
|
|
with:
|
|
tags: |
|
|
type=semver,pattern={{version}},prefix=v
|
|
type=semver,pattern={{major}}.{{minor}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.0.') }},prefix=v
|
|
type=semver,pattern={{major}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.') }},prefix=v
|
|
type=ref,event=branch,prefix=${{ format('refs/heads/{0}', github.event.repository.default_branch) != github.ref && 'branch-' || '' }}
|
|
type=ref,event=pr
|
|
type=sha,format=long
|
|
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }}
|
|
images: ${{needs.define-variables.outputs.images}}
|
|
# default labels & annotations: https://github.com/docker/metadata-action/blob/master/src/meta.ts#L509
|
|
env:
|
|
DOCKER_METADATA_ANNOTATIONS_LEVELS: index
|
|
|
|
- name: Create manifest list and push
|
|
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
|
|
working-directory: /tmp/digests
|
|
env:
|
|
IMAGES: ${{needs.define-variables.outputs.images}}
|
|
shell: bash
|
|
run: |
|
|
IFS=$'\n'
|
|
IMAGES_LIST=($IMAGES)
|
|
ANNOTATIONS_LIST=($DOCKER_METADATA_OUTPUT_ANNOTATIONS)
|
|
TAGS_LIST=($DOCKER_METADATA_OUTPUT_TAGS)
|
|
for REPO in "${IMAGES_LIST[@]}"; do
|
|
docker buildx imagetools create \
|
|
$(for tag in "${TAGS_LIST[@]}"; do echo "--tag"; echo "$tag"; done) \
|
|
$(for annotation in "${ANNOTATIONS_LIST[@]}"; do echo "--annotation"; echo "$annotation"; done) \
|
|
$(for reference in *; do printf "$REPO@sha256:%s\n" $reference; done)
|
|
done
|
|
|
|
- name: Inspect image
|
|
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
|
|
env:
|
|
IMAGES: ${{needs.define-variables.outputs.images}}
|
|
shell: bash
|
|
run: |
|
|
IMAGES_LIST=($IMAGES)
|
|
for REPO in "${IMAGES_LIST[@]}"; do
|
|
docker buildx imagetools inspect $REPO:${{ steps.meta.outputs.version }}
|
|
done
|