Skip to content

Build

Build #428

Workflow file for this run

name: Build
on:
pull_request:
types: [synchronize, opened, reopened]
release:
types: [published]
workflow_dispatch:
inputs:
RELEASE:
description: 'AlmaLinux release'
required: true
default: '9'
type: choice
options:
- '10-kitten'
- '10'
- '9'
- 'ALL'
schedule:
# run every day at 01:00 UTC
- cron: '00 01 * * *'
env:
LATEST_MAJOR: 9
IMAGE_NAME: almalinux-bootc-rpi
VERSIONS_LIST: '"9", "10-kitten", "10"'
VARIANT_LIST: '"rpi"'
# CHAT_CHANNEL: sigcloud
jobs:
set-versions-matrix:
name: Set versions matrix
runs-on: ubuntu-24.04
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
variants: ${{ steps.set-variants.outputs.variants }}
date_stamp: ${{ steps.date-stamp.outputs.date_stamp }}
steps:
- name: Set matrix
id: set-matrix
run: |
# Format json for versions matrix
case ${{ github.event_name }} in
pull_request)
echo "matrix=$(jq -c <<< '[${{ env.VERSIONS_LIST }}]')" >> $GITHUB_OUTPUT
;;
release)
echo "matrix=$(jq -c <<< '[${{ env.VERSIONS_LIST }}]')" >> $GITHUB_OUTPUT
;;
workflow_dispatch)
if [[ "${{ inputs.RELEASE }}" == "ALL" ]]; then
echo "matrix=$(jq -c <<< '[${{ env.VERSIONS_LIST }}]')" >> $GITHUB_OUTPUT
else
echo "matrix=$(jq -c <<< '["${{ inputs.RELEASE }}"]')" >> $GITHUB_OUTPUT
fi
;;
schedule)
echo "matrix=$(jq -c <<< '[${{ env.VERSIONS_LIST }}]')" >> $GITHUB_OUTPUT
;;
esac
- name: Set variants
id: set-variants
run: |
# Format json for variants
echo "variants=$(jq -c <<< '[${{ env.VARIANT_LIST }}]')" >> $GITHUB_OUTPUT
- name: Date stamp
id: date-stamp
run: |
# date stamp
date_stamp=$(date -u '+%Y%m%d')
[ "x${date_stamp}" != "x" ] && echo "date_stamp=${date_stamp}" >> "$GITHUB_OUTPUT"
build:
name: Build image
runs-on: ${{ matrix.ARCH == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
needs: [set-versions-matrix]
strategy:
fail-fast: false
matrix:
VERSION_MAJOR: ${{ fromJSON(needs.set-versions-matrix.outputs.matrix) }}
ARCH: [arm64]
VARIANT: ${{ fromJSON(needs.set-versions-matrix.outputs.variants) }}
env:
PLATFORM: linux/${{ matrix.ARCH }}
DATE_STAMP: ${{ needs.set-versions-matrix.outputs.date_stamp }}
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/shared-steps
name: Build and Push
with:
VERSION_MAJOR: ${{ matrix.VERSION_MAJOR }}
DATE_STAMP: ${{ env.DATE_STAMP }}
IMAGE_REGISTRY: ${{ secrets.IMAGE_REGISTRY }}
VARIANT: ${{ matrix.VARIANT }}
REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
release:
if: github.event_name == 'release' && github.event.action == 'published'
name: Release
permissions:
contents: write
needs: [set-versions-matrix, build]
runs-on: ubuntu-24.04
steps:
- name: Fetch Build Outputs
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
pattern: image-*.raw.xz
merge-multiple: true
path: /tmp/artifacts
- run: |
ls -l /tmp/artifacts
- name: Upload Release Artifacts
id: upload-release-artifacts
uses: softprops/action-gh-release@v1
with:
files: /tmp/artifacts/*
push-manifest:
if: ${{ always() && contains(join(needs.*.result, ','), 'success') && github.event_name != 'pull_request' && github.event_name != 'release' }}
name: Push manifest
needs: [set-versions-matrix, build]
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
VERSION_MAJOR: ${{ fromJSON(needs.set-versions-matrix.outputs.matrix) }}
env:
DATE_STAMP: ${{ needs.set-versions-matrix.outputs.date_stamp }}
steps:
- name: Fetch Build Outputs
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
pattern: ${{ env.IMAGE_NAME }}_${{ matrix.VERSION_MAJOR }}_*
merge-multiple: true
path: /tmp/artifacts
- name: Load Outputs
id: load-outputs
run: |
if [[ ! -d /tmp/artifacts ]]; then
echo "No artifacts found, skipping manifest creation"
echo "skip=1" >> "$GITHUB_ENV"
exit
fi
ls -lR /tmp/artifacts/
jq -sc add /tmp/artifacts/*.json > merged.json
echo "DIGESTS_JSON=$(cat merged.json)" >> $GITHUB_OUTPUT
jq '.' merged.json
- name: Sanity check
if: ${{ env.skip != 1 }}
id: check
env:
DIGESTS_JSON: ${{ steps.load-outputs.outputs.DIGESTS_JSON }}
run: |
EXPECTED=1
#[[ "${{ matrix.VERSION_MAJOR }}" == "9" ]] && EXPECTED=2 || EXPECTED=3
# Ensure we have the correct number of digests
if [[ $(echo ${DIGESTS_JSON} | jq 'length') -ne $EXPECTED ]]; then
echo "Expected $EXPECTED digests, found $(echo ${DIGESTS_JSON} | jq 'length')"
exit 1
fi
# Ensure all versions match
COUNT=$(echo ${DIGESTS_JSON} | jq '[.[] | .version] | unique | length')
if [[ $COUNT -ne 1 ]]; then
echo "Versions do not match across all platforms"
echo ${DIGESTS_JSON} | jq '[.[] | .version]'
exit 1
fi
echo "id=$(echo ${DIGESTS_JSON} | jq -r '[.[] | .id] | unique | .[0]')" >> $GITHUB_OUTPUT
echo "version-id=$(echo ${DIGESTS_JSON} | jq -r '[.[] | .version] | unique | .[0]')" >> $GITHUB_OUTPUT
echo "long-version=$(echo ${DIGESTS_JSON} | jq -r '[.[] | .long_version] | unique | .[0]')" >> $GITHUB_OUTPUT
echo "vendor=$(echo ${DIGESTS_JSON} | jq -r '[.[] | .vendor] | unique | .[0]')" >> $GITHUB_OUTPUT
echo "date=$(date -u +%Y\-%m\-%d\T%H\:%M\:%S\Z)" >> $GITHUB_OUTPUT
- name: Login to registry (docker)
if: ${{ env.skip != 1 }}
uses: docker/login-action@v3
with:
registry: ${{ secrets.IMAGE_REGISTRY }}
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Image Metadata
if: ${{ env.skip != 1 }}
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5
id: metadata
with:
tags: |
type=raw,value=latest,enable=${{ matrix.VERSION_MAJOR == env.LATEST_MAJOR }}
type=raw,value=${{ matrix.VERSION_MAJOR }}
type=raw,value=${{ steps.check.outputs.version-id }},enable=${{ matrix.VERSION_MAJOR != '10-kitten' }}
type=raw,value=${{ steps.check.outputs.version-id }}-${{ env.DATE_STAMP }}
type=raw,value=${{ steps.check.outputs.long-version }}
labels: |
redhat.id=${{ steps.check.outputs.id }}
redhat.version-id=${{ steps.check.outputs.version-id }}
version=${{ steps.check.outputs.version-id }}
release=${{ steps.check.outputs.version-id }}
org.opencontainers.image.created=${{ steps.check.outputs.date }}
org.opencontainers.image.source=${{ github.repositoryUrl }}
org.opencontainers.image.title=${{ env.IMAGE_NAME }}
org.opencontainers.image.url=${{ github.event.repository.html_url }}
org.opencontainers.image.version=${{ steps.check.outputs.long-version }}
org.opencontainers.image.vendor=AlmaLinux OS Foundation
org.opencontainers.image.description=AlmaLinux Bootable Container Image
- name: Get a newer podman (from debian testing)
if: ${{ env.skip != 1 }}
run: |
set -eux
echo 'deb [trusted=yes] https://ftp.debian.org/debian/ testing main' | sudo tee /etc/apt/sources.list.d/testing.list
sudo apt update
sudo apt install -y crun/testing podman/testing
- name: Create Manifest
if: ${{ env.skip != 1 }}
id: create-manifest
run: |
IMAGE_DEST=${{ secrets.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}
podman manifest create ${IMAGE_DEST}
echo "MANIFEST=${IMAGE_DEST}" >> $GITHUB_OUTPUT
- name: Populate Manifest
if: ${{ env.skip != 1 }}
env:
MANIFEST: ${{ steps.create-manifest.outputs.MANIFEST }}
DIGESTS_JSON: ${{ steps.load-outputs.outputs.DIGESTS_JSON }}
LABELS: ${{ steps.metadata.outputs.labels }}
run: |
IMAGE_DEST=${{ secrets.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}
for platform in $(echo $DIGESTS_JSON | jq -r '. | to_entries | .[].key'); do
digest=$(echo $DIGESTS_JSON | jq -r ".[\"$platform\"].digest")
echo "Adding ${IMAGE_DEST}@$digest for $platform"
if [[ "$platform" = */v* ]]; then
podman manifest add $MANIFEST ${IMAGE_DEST}@$digest --arch ${platform%/*} --variant ${platform#*/}
else
podman manifest add $MANIFEST ${IMAGE_DEST}@$digest --arch $platform
fi
done
# Apply the labels to the manifest (separated by newlines)
while IFS= read -r label; do
echo "Applying label $label to manifest"
podman manifest annotate --index --annotation "$label" $MANIFEST
done <<< "$LABELS"
- name: Push Manifest
if: ${{ env.skip != 1 }}
id: push_manifest
env:
MANIFEST: ${{ steps.create-manifest.outputs.MANIFEST }}
TAGS: ${{ steps.metadata.outputs.tags }}
run: |
IMAGE_DEST=${{ secrets.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}
while IFS= read -r tag; do
for i in {1..5}; do
podman manifest push --all=false --digestfile=/tmp/digestfile $MANIFEST ${IMAGE_DEST}:$tag && break || sleep $((10*i))
done
[ -f /tmp/digestfile ] || exit 1
done <<< "$TAGS"
DIGEST=$(cat /tmp/digestfile)
echo "digest=$DIGEST" >> $GITHUB_OUTPUT
echo "image=${IMAGE_DEST}" >> $GITHUB_OUTPUT
echo "Pushed manifest to ${IMAGE_DEST} with digest $DIGEST"
podman manifest inspect ${IMAGE_DEST}
- name: Format output for notification
if: ${{ env.skip != 1 }}
id: format
env:
DIGESTS_JSON: ${{ steps.load-outputs.outputs.DIGESTS_JSON }}
TAGS: ${{ steps.metadata.outputs.tags }}
run: |
echo "arches=$(echo "$DIGESTS_JSON" | jq -r '[keys[] | "linux/" + .] | sort | join(", ")')" >> $GITHUB_OUTPUT
# Add two spaces before each tag (starting from the second line) so that it is formatted correctly in the notification
{
echo 'tags<<EOF'
printf "$TAGS" | awk 'NR==1{print; next} {print " " $0}'
echo EOF
} >> $GITHUB_OUTPUT
# - name: Notify AlmaLinux Chat
# if: ${{ env.skip != 1 }}
# uses: mattermost/action-mattermost-notify@master
# with:
# MATTERMOST_WEBHOOK_URL: ${{ secrets.MM_WEBHOOK_URL }}
# MATTERMOST_CHANNEL: ${{ env.CHAT_CHANNEL }}
# MATTERMOST_USERNAME: 'github'
# TEXT: |-
# **AlmaLinux OS ${{ steps.check.outputs.version-id }}** Bootc Image, build `${{ steps.check.outputs.long-version }}`, built by [GitHub Actions](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
#
# :almalinux: **${{ steps.push_manifest.outputs.image }}**
# - Platforms:
# ```
# ${{ steps.format.outputs.arches }}
# ```
# - Tags:
# ```
# ${{ steps.format.outputs.tags }}
# ```