Build and Push Image #658
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: Build and Push Image | |
on: | |
push: | |
branches: | |
- "custom" | |
schedule: | |
- cron: "00 01 * * *" # 10:00am everyday | |
merge_group: | |
pull_request: | |
branches: | |
- custom | |
paths-ignore: | |
- "**.md" | |
workflow_dispatch: | |
env: | |
IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }} | |
concurrency: | |
group: ${{ github.workflow }}-${{ github.ref || github.run_id }} | |
cancel-in-progress: true | |
jobs: | |
push-ghcr: | |
name: Make | |
runs-on: ubuntu-24.04 | |
env: | |
BASE_IMAGE_NAME: silverblue | |
permissions: | |
contents: read | |
packages: write | |
id-token: write | |
strategy: | |
fail-fast: false | |
matrix: | |
image_flavor: [main, nvidia] | |
base_name: [os] | |
fedora_version: [stable, latest] | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
- name: Check just syntax | |
uses: ublue-os/just-action@v1 | |
- name: Matrix Variables | |
run: | | |
# IMAGE_NAME | |
if [[ "${{ matrix.image_flavor }}" == "main" ]]; then | |
echo "IMAGE_NAME=${{ matrix.base_name }}" >> $GITHUB_ENV | |
else | |
echo "IMAGE_NAME=${{ format('{0}-{1}', matrix.base_name, matrix.image_flavor) }}" >> $GITHUB_ENV | |
fi | |
# AKMODS_FLAVOR | |
if [[ "${{ matrix.fedora_version }}" =~ stable|gts ]]; then | |
echo "AKMODS_FLAVOR=coreos-stable" >> $GITHUB_ENV | |
else | |
echo "AKMODS_FLAVOR=main" >> $GITHUB_ENV | |
fi | |
# Env for matrix.image_flavor | |
if [[ "${{ matrix.image_flavor }}" == "nvidia" && \ | |
"${{ matrix.fedora_version }}" != "beta" ]]; then | |
echo "image_flavor=main" >> $GITHUB_ENV | |
echo "nvidia_type=nvidia" >> $GITHUB_ENV | |
elif [[ "${{ matrix.image_flavor }}" == "main" && \ | |
"${{ matrix.fedora_version }}" != "beta" ]]; then | |
echo "image_flavor=${{ matrix.image_flavor }}" >> $GITHUB_ENV | |
else | |
echo "image_flavor=${{ matrix.image_flavor }}" >> $GITHUB_ENV | |
fi | |
- name: Get Current Fedora Version | |
id: labels | |
uses: Wandalen/wretry.action@6feedb7dedadeb826de0f45ff482b53b379a7844 # v3.5.0 | |
with: | |
attempt_limit: 3 | |
attempt_delay: 15000 | |
command: | | |
set -eox pipefail | |
if [[ ${{ matrix.fedora_version }} == "stable" ]]; then | |
KERNEL_RELEASE=$(skopeo inspect docker://quay.io/fedora/fedora-coreos:stable | jq -r '.Labels["ostree.linux"]') | |
elif [[ ${{ matrix.fedora_version }} == "gts" ]]; then | |
# always get base kernel release because we use it to get Fedora release not from CoreOS | |
base_kernel_release=$(skopeo inspect docker://ghcr.io/ublue-os/silverblue-${{ env.image_flavor }}:${{ matrix.fedora_version }} | jq -r '.Labels["ostree.linux"]') | |
coreos_kernel_release=$(skopeo inspect docker://quay.io/fedora/fedora-coreos:stable | jq -r '.Labels["ostree.linux"]') | |
coreos_fedora_version=$(echo $coreos_kernel_release | grep -oP 'fc\K[0-9]+') | |
# this allows GTS to be same as CoreOS or earlier, depending on release cycle timing | |
fedora_version=$(echo $base_kernel_release | grep -oP 'fc\K[0-9]+') | |
KERNEL_RELEASE=$(skopeo inspect docker://ghcr.io/ublue-os/coreos-stable-kernel:${fedora_version} | jq -r '.Labels["ostree.linux"]') | |
else | |
base_kernel_release=$(skopeo inspect docker://ghcr.io/ublue-os/silverblue-${{ env.image_flavor }}:${{ matrix.fedora_version }} | jq -r '.Labels["ostree.linux"]') | |
base_fedora_version=$(echo $base_kernel_release | grep -oP 'fc\K[0-9]+') | |
KERNEL_RELEASE=$(skopeo inspect docker://ghcr.io/ublue-os/${{ env.AKMODS_FLAVOR }}-kernel:${base_fedora_version} | jq -r '.Labels["ostree.linux"]') | |
fi | |
fedora_version=$(echo $KERNEL_RELEASE | grep -oP 'fc\K[0-9]+') | |
echo "kernel_release=$KERNEL_RELEASE" >> $GITHUB_ENV | |
echo "fedora_version=$fedora_version" >> $GITHUB_ENV | |
ver=$(skopeo inspect docker://ghcr.io/ublue-os/${{ env.BASE_IMAGE_NAME }}-${{ env.image_flavor }}:$fedora_version | jq -r '.Labels["org.opencontainers.image.version"]') | |
if [ -z "$ver" ] || [ "null" = "$ver" ]; then | |
echo "inspected image version must not be empty or null" | |
exit 1 | |
fi | |
echo "VERSION=$ver" >> $GITHUB_ENV | |
- name: Verify Kernel Version Matches | |
uses: Wandalen/wretry.action@6feedb7dedadeb826de0f45ff482b53b379a7844 # v3.5.0 | |
with: | |
attempt_limit: 3 | |
attempt_delay: 15000 | |
command: | | |
set -x | |
akmods_version=$(skopeo inspect docker://ghcr.io/ublue-os/akmods:${{ env.AKMODS_FLAVOR }}-${{ env.fedora_version }} | jq -r '.Labels["ostree.linux"]') | |
if [[ "${akmods_version}" == "${{ env.kernel_release }}" ]]; then | |
echo "Kernel Versions Match" | |
else | |
echo "Kernel Version do Not Match" | |
exit 1 | |
fi | |
- name: Generate tags | |
id: generate-tags | |
shell: bash | |
run: | | |
# Generate a timestamp for creating an image version history | |
TIMESTAMP="$(date +%Y%m%d)" | |
FEDORA_VERSION="${{ matrix.fedora_version }}" | |
if [[ "${{ matrix.fedora_version }}" == "stable" ]]; then | |
IS_LATEST_VERSION=false | |
IS_STABLE_VERSION=true | |
IS_GTS_VERSION=false | |
IS_BETA_VERSION=false | |
IS_COREOS=true | |
elif [[ "${{ matrix.fedora_version }}" == "gts" ]]; then | |
IS_LATEST_VERSION=false | |
IS_STABLE_VERSION=true | |
IS_GTS_VERSION=true | |
IS_BETA_VERSION=false | |
IS_COREOS=false | |
elif [[ "${{ matrix.fedora_version }}" == "latest" ]]; then | |
IS_LATEST_VERSION=true | |
IS_STABLE_VERSION=true | |
IS_GTS_VERSION=false | |
IS_BETA_VERSION=false | |
IS_COREOS=false | |
elif [[ "${{ matrix.fedora_version }}" == "beta" ]]; then | |
IS_LATEST_VERSION=false | |
IS_STABLE_VERSION=false | |
IS_GTS_VERSION=false | |
IS_BETA_VERSION=true | |
IS_COREOS=false | |
fi | |
COMMIT_TAGS=() | |
BUILD_TAGS=() | |
# Have tags for tracking builds during pull request | |
SHA_SHORT="${GITHUB_SHA::7}" | |
COMMIT_TAGS+=("pr-${{ github.event.number }}-${FEDORA_VERSION}") | |
COMMIT_TAGS+=("${SHA_SHORT}-${FEDORA_VERSION}") | |
if [[ "$IS_LATEST_VERSION" == "true" ]] && \ | |
[[ "$IS_STABLE_VERSION" == "true" ]]; then | |
COMMIT_TAGS+=("pr-${{ github.event.number }}") | |
COMMIT_TAGS+=("${SHA_SHORT}") | |
fi | |
TODAY="$(date +%A)" | |
BUILD_TAGS=("${{ env.fedora_version }}" "${{ env.fedora_version }}-${TIMESTAMP}") | |
if [[ "$IS_LATEST_VERSION" == "true" ]] && \ | |
[[ "$IS_STABLE_VERSION" == "true" ]]; then | |
BUILD_TAGS+=("latest") | |
echo "DEFAULT_TAG=latest" >> $GITHUB_ENV | |
elif [[ "$IS_LATEST_VERSION" == "false" ]] && \ | |
[[ "$IS_STABLE_VERSION" == "true" ]]; then | |
BUILD_TAGS+=("stable") | |
echo "DEFAULT_TAG=stable" >> $GITHUB_ENV | |
elif [[ "$IS_GTS_VERSION" == "true" ]]; then | |
BUILD_TAGS+=("gts") | |
echo "DEFAULT_TAG=gts" >> $GITHUB_ENV | |
elif [[ "$IS_BETA_VERSION" == "true" ]]; then | |
BUILD_TAGS+=("beta") | |
echo "DEFAULT_TAG=beta" >> $GITHUB_ENV | |
elif [[ "$IS_COREOS" == "true" ]]; then | |
echo "DEFAULT_TAG=stable" >> $GITHUB_ENV | |
fi | |
alias_tags=("${BUILD_TAGS[@]}") | |
echo "Generated the following build tags: " | |
for TAG in "${BUILD_TAGS[@]}"; do | |
echo "${TAG}" | |
done | |
echo "alias_tags=${alias_tags[*]}" >> $GITHUB_OUTPUT | |
# Build metadata | |
- name: Image Metadata | |
uses: docker/metadata-action@v5 | |
id: meta | |
with: | |
images: | | |
${{ env.IMAGE_NAME }} | |
labels: | | |
org.opencontainers.image.title=${{ env.IMAGE_NAME }} | |
org.opencontainers.image.version=${{ env.VERSION }} | |
org.opencontainers.image.description=Fedora Silverblue with tweaks | |
ostree.linux=${{ env.kernel_release }} | |
- name: Define env.SHA_HEAD_SHORT | |
run: | | |
echo "SHA_HEAD_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV | |
- name: Maximize build space | |
uses: ublue-os/remove-unwanted-software@v7 | |
with: | |
remove-codeql: true | |
- name: Pull images | |
uses: Wandalen/wretry.action@6feedb7dedadeb826de0f45ff482b53b379a7844 # v3.5.0 | |
with: | |
attempt_limit: 3 | |
attempt_delay: 15000 | |
command: | | |
# pull the base image used for FROM in containerfile so | |
# we can retry on that unfortunately common failure case | |
sudo podman pull ghcr.io/ublue-os/${{ env.BASE_IMAGE_NAME }}-${{ env.image_flavor }}:${{ env.fedora_version }} | |
sudo podman pull ghcr.io/ublue-os/akmods:${{ env.AKMODS_FLAVOR }}-${{ env.fedora_version }} | |
sudo podman pull ghcr.io/ublue-os/akmods-nvidia:${{ env.AKMODS_FLAVOR }}-${{ env.fedora_version }} | |
sudo podman pull ghcr.io/ublue-os/${{ env.AKMODS_FLAVOR }}-kernel:${{ env.kernel_release }} | |
- name: Build Image | |
id: build_image | |
run: | | |
set -euox pipefail | |
BUILD_ARGS=() | |
BUILD_ARGS+=("--build-arg" "BASE_IMAGE_NAME=${{ env.BASE_IMAGE_NAME }}") | |
BUILD_ARGS+=("--build-arg" "IMAGE_NAME=${{ env.IMAGE_NAME }}") | |
BUILD_ARGS+=("--build-arg" "IMAGE_FLAVOR=${{ env.image_flavor }}") | |
BUILD_ARGS+=("--build-arg" "IMAGE_VENDOR=${{ github.repository_owner }}") | |
BUILD_ARGS+=("--build-arg" "FEDORA_MAJOR_VERSION=${{ env.fedora_version }}") | |
BUILD_ARGS+=("--build-arg" "TARGET_BASE=${{ env.TARGET_BASE }}") | |
BUILD_ARGS+=("--build-arg" "AKMODS_FLAVOR=${{ env.AKMODS_FLAVOR }}") | |
BUILD_ARGS+=("--build-arg" "NVIDIA_TYPE=${{ env.nvidia_type }}") | |
BUILD_ARGS+=("--build-arg" "KERNEL=${{ env.kernel_release }}") | |
BUILD_ARGS+=("--build-arg" "IMAGE_TAG=${{ matrix.fedora_version }}") | |
BUILD_ARGS+=("--build-arg" "SHA_HEAD_SHORT=${{ env.SHA_HEAD_SHORT }}") | |
TAG_ARGS=() | |
IFS=' ' read -r -a tags_array <<< "${{ steps.generate-tags.outputs.alias_tags }}" | |
for tag in "${tags_array[@]}"; do | |
TAG_ARGS+=("--tag" "${{ env.IMAGE_NAME }}:${tag}") | |
done | |
LABEL_ARGS=() | |
IFS=' ' read -r -a labels_array <<< "${{ steps.meta.outputs.labels }}" | |
for label in "${labels_array[@]}"; do | |
LABEL_ARGS+=("--label" "${label}") | |
done | |
sudo podman build --format docker --target base \ | |
"${BUILD_ARGS[@]}" \ | |
"${TAG_ARGS[@]}" \ | |
"${LABEL_ARGS[@]}" \ | |
. | |
sudo podman image ls | |
echo "image=${{ env.IMAGE_NAME }}" >> $GITHUB_OUTPUT | |
echo "tags=${{ steps.generate-tags.outputs.alias_tags }}" >> $GITHUB_OUTPUT | |
- name: Lowercase Registry | |
id: registry_case | |
uses: ASzc/change-string-case-action@d0603cd0a7dd490be678164909f65c7737470a7f # v6 | |
with: | |
string: ${{ env.IMAGE_REGISTRY }} | |
- name: Rechunk Image | |
id: rechunk | |
uses: hhd-dev/rechunk@v0.8.6 | |
with: | |
rechunk: ghcr.io/hhd-dev/rechunk:v0.8.6 | |
ref: ${{ steps.build_image.outputs.image }}:${{ env.DEFAULT_TAG }} | |
skip_compression: "true" | |
labels: ${{ steps.meta.outputs.labels }} | |
prev-ref: ${{ steps.registry_case.outputs.lowercase }}/${{ steps.build_image.outputs.image }}:${{ env.DEFAULT_TAG }} | |
# Overwrite the image with the chuncked image | |
- name: Load Rechunked Image | |
run: | | |
sudo podman rmi $(sudo podman image ls -qa) --force | |
IMAGE=$(sudo podman pull ${{ steps.rechunk.outputs.ref }}) | |
sudo rm -rf ${{ steps.rechunk.outputs.output }} | |
for tag in ${{ steps.build_image.outputs.tags }}; do | |
sudo podman tag $IMAGE ${{ env.IMAGE_NAME }}:${tag} | |
done | |
- name: Login to GitHub Container Registry | |
if: github.event_name != 'pull_request' | |
run: | | |
echo ${{ secrets.GITHUB_TOKEN }} | podman login ghcr.io -u ${{ github.actor }} --password-stdin | |
echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin | |
- name: Push to GHCR | |
id: push | |
if: github.event_name != 'pull_request' | |
uses: Wandalen/wretry.action@6feedb7dedadeb826de0f45ff482b53b379a7844 # v3.5.0 | |
with: | |
attempt_limit: 3 | |
attempt_delay: 15000 | |
command: | | |
set -euox pipefail | |
for tag in ${{ steps.build_image.outputs.tags }}; do | |
sudo podman push ${{ env.IMAGE_NAME }}:${tag} ${{ steps.registry_case.outputs.lowercase }}/${{ env.IMAGE_NAME }}:${tag} | |
done | |
digest=$(skopeo inspect docker://${{ steps.registry_case.outputs.lowercase }}/${{ env.IMAGE_NAME }}:${{ env.DEFAULT_TAG }} --format '{{.Digest}}') | |
echo "digest=${digest}" >> $GITHUB_OUTPUT | |
# Sign container | |
- uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3.7.0 | |
- name: Sign container image | |
if: github.event_name != 'pull_request' | |
run: | | |
cosign sign -y --key env://COSIGN_PRIVATE_KEY ${{ steps.registry_case.outputs.lowercase }}/${{ env.IMAGE_NAME }}@${TAGS} | |
env: | |
TAGS: ${{ steps.push.outputs.outputs && fromJSON(steps.push.outputs.outputs).digest }} | |
COSIGN_EXPERIMENTAL: false | |
COSIGN_PRIVATE_KEY: ${{ secrets.SIGNING_SECRET }} | |
- name: Generate file containing outputs | |
if: github.event_name != 'pull_request' | |
env: | |
DIGEST: ${{ steps.push.outputs.outputs && fromJSON(steps.push.outputs.outputs).digest }} | |
IMAGE_REGISTRY: ${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }} | |
IMAGE_NAME: ${{ env.IMAGE_NAME }} | |
IMAGE_FLAVOR: ${{ env.image_flavor }} | |
FEDORA_VERSION: ${{ matrix.fedora_version }} | |
run: echo "${IMAGE_REGISTRY}@${DIGEST}" > "${IMAGE_NAME}-${IMAGE_FLAVOR}-${FEDORA_VERSION}.txt" | |
- name: Upload artifact | |
if: github.event_name != 'pull_request' | |
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4 | |
with: | |
name: image-${{ env.IMAGE_NAME }}-${{ env.image_flavor }}-${{ matrix.fedora_version }} | |
retention-days: 1 | |
if-no-files-found: error | |
path: | | |
${{ env.IMAGE_NAME }}-${{ env.image_flavor }}-${{ matrix.fedora_version }}.txt | |
check: | |
name: Check all builds successful | |
if: ${{ !cancelled() }} | |
runs-on: ubuntu-latest | |
needs: [push-ghcr] | |
steps: | |
- name: Exit on failure | |
if: ${{ needs.push-ghcr.result == 'failure' }} | |
shell: bash | |
run: exit 1 | |
- name: Exit | |
shell: bash | |
run: exit 0 |