fix(ublue-builder): ensure that skipped architectures do not fail on CI #35
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
name: Build ublue-builder | |
on: | |
workflow_dispatch: # allow manually triggering builds | |
pull_request: | |
branches: | |
- main | |
paths: | |
- 'ublue-builder/*' | |
push: | |
branches: | |
- main | |
paths: | |
- 'ublue-builder/*' | |
schedule: | |
- cron: '0 0 * * TUE' | |
env: | |
IMAGE_NAME: ublue-builder | |
IMAGE_DESC: "Builder image for Universal Blue package building" | |
IMAGE_REGISTRY: "ghcr.io/${{ github.repository_owner }}" | |
DEFAULT_TAG: "latest" | |
PLATFORMS: "amd64,arm64" | |
jobs: | |
generate_matrix: | |
runs-on: ubuntu-latest | |
outputs: | |
matrix: ${{ steps.set-matrix.outputs.matrix }} | |
steps: | |
- name: Set matrix | |
id: set-matrix | |
run: | | |
# turn the comma separated string into a list | |
platforms=() | |
IFS=',' read -r -a platforms <<< "${{ env.PLATFORMS }}" | |
MATRIX="{\"include\":[]}" | |
for platform in "${platforms[@]}"; do | |
MATRIX=$(echo $MATRIX | jq ".include += [{\"platform\": \"$platform\"}]") | |
done | |
echo "matrix=$(echo $MATRIX | jq -c '.')" >> $GITHUB_OUTPUT | |
build_push: | |
name: Build and push image | |
runs-on: ${{ matrix.platform == 'amd64' && 'ubuntu-24.04' || 'ubuntu-24.04-arm' }} | |
timeout-minutes: 30 | |
needs: generate_matrix | |
permissions: | |
contents: read | |
packages: write | |
id-token: write | |
strategy: | |
fail-fast: false | |
matrix: ${{fromJson(needs.generate_matrix.outputs.matrix)}} | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
- name: Install dependencies | |
if: matrix.platform == 'arm64' | |
run: | | |
sudo apt update -y | |
sudo apt install -y \ | |
podman | |
- name: Build Image | |
id: build_image | |
uses: redhat-actions/buildah-build@v2 | |
with: | |
containerfiles: | | |
./${{ env.IMAGE_NAME }}/Containerfile | |
context: ${{ env.IMAGE_NAME }} | |
image: ${{ env.IMAGE_NAME }} | |
tags: ${{ env.DEFAULT_TAG }} | |
labels: ${{ steps.meta.outputs.labels }} | |
oci: true | |
- name: Login to GHCR | |
if: github.event_name != 'pull_request' | |
run: | | |
echo ${{ secrets.GITHUB_TOKEN }} | podman login -u ${{ github.actor }} --password-stdin ghcr.io | |
echo ${{ secrets.GITHUB_TOKEN }} | docker login -u ${{ github.actor }} --password-stdin ghcr.io | |
- name: Push to GHCR | |
if: github.event_name != 'pull_request' | |
id: push | |
env: | |
IMAGE_REGISTRY: ${{ env.IMAGE_REGISTRY }} | |
IMAGE_NAME: ${{ env.IMAGE_NAME }} | |
IMAGE_DIGEST: ${{ steps.build_image.outputs.digest }} | |
PLATFORM: ${{ matrix.platform }} | |
run: | | |
set -x | |
podman tag localhost/${IMAGE_NAME}:${DEFAULT_TAG} ${{ env.IMAGE_REGISTRY }}/${IMAGE_NAME}:${DEFAULT_TAG} | |
podman tag ${{ env.IMAGE_REGISTRY }}/${IMAGE_NAME}:${DEFAULT_TAG} $IMAGE_REGISTRY/$IMAGE_NAME:$DEFAULT_TAG-$PLATFORM | |
for i in {1..3}; do | |
podman push --digestfile=/tmp/digestfile $IMAGE_REGISTRY/$IMAGE_NAME:$DEFAULT_TAG-$PLATFORM && break || sleep $((5 * i)); | |
done | |
REMOTE_IMAGE_DIGEST=$(cat /tmp/digestfile) | |
echo "remote_image_digest=$REMOTE_IMAGE_DIGEST" >> $GITHUB_OUTPUT | |
cat /tmp/digestfile | |
- name: Install Cosign | |
uses: sigstore/cosign-installer@c56c2d3e59e4281cc41dea2217323ba5694b171e # v3.8.0 | |
if: github.event_name != 'pull_request' | |
- name: Sign Image | |
if: github.event_name != 'pull_request' | |
run: | | |
IMAGE_FULL="${{ env.IMAGE_REGISTRY }}/${IMAGE_NAME}" | |
cosign sign -y --key env://COSIGN_PRIVATE_KEY ${IMAGE_FULL}@${{ steps.push.outputs.remote_image_digest }} | |
env: | |
TAGS: ${{ steps.push.outputs.digest }} | |
COSIGN_EXPERIMENTAL: false | |
COSIGN_PRIVATE_KEY: ${{ secrets.SIGNING_SECRET }} | |
- name: Create Job Outputs | |
if: github.event_name != 'pull_request' | |
env: | |
IMAGE_NAME: ${{ env.IMAGE_NAME }} | |
PLATFORM: ${{ matrix.platform }} | |
DIGEST: ${{ steps.push.outputs.remote_image_digest }} | |
run: | | |
mkdir -p /tmp/outputs/digests | |
echo "${DIGEST}" > /tmp/outputs/digests/${IMAGE_NAME}-${PLATFORM}.txt | |
- name: Upload Output Artifacts | |
if: github.event_name != 'pull_request' | |
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4 | |
with: | |
name: ${{ env.IMAGE_NAME }}-${{ matrix.platform }} | |
retention-days: 1 | |
if-no-files-found: error | |
path: | | |
/tmp/outputs/digests/*.txt | |
manifest: | |
name: Create shared manifest | |
runs-on: ubuntu-latest | |
if: always() | |
needs: | |
- generate_matrix | |
- build_push | |
container: | |
image: quay.io/fedora/fedora:41 | |
options: --privileged --security-opt seccomp=unconfined | |
permissions: | |
contents: read | |
packages: write | |
id-token: write | |
outputs: | |
image: ${{ steps.push_manifest.outputs.IMAGE }} | |
digest: ${{ steps.push_manifest.outputs.DIGEST }} | |
steps: | |
- name: Install dependencies | |
run: | | |
dnf install -y \ | |
jq \ | |
git | |
dnf copr enable -y rhcontainerbot/podman-next | |
dnf install -y podman | |
- name: Exit on failure | |
env: | |
JOBS: ${{ toJson(needs) }} | |
run: | | |
echo "Job status:" | |
echo $JOBS | jq -r 'to_entries[] | " - \(.key): \(.value.result)"' | |
for i in $(echo $JOBS | jq -r 'to_entries[] | .value.result'); do | |
if [ "$i" != "success" ] && [ "$i" != "skipped" ]; then | |
echo "" | |
echo "Status check not okay!" | |
exit 1 | |
fi | |
done | |
- name: Get current date | |
id: date | |
run: | | |
# Should generate 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 | |
- name: Image Metadata | |
uses: docker/metadata-action@369eb591f429131d6889c46b94e711f089e6ca96 # v5 | |
id: metadata | |
with: | |
tags: | | |
type=raw,value=latest | |
type=ref,event=pr | |
labels: | | |
io.artifacthub.package.readme-url=https://raw.githubusercontent.com/${{ 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://raw.githubusercontent.com/${{ 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=${{ env.DEFAULT_TAG }} | |
io.artifacthub.package.deprecated=false | |
io.artifacthub.package.keywords=ublue,universal-blue,copr,fedora | |
io.artifacthub.package.license=Apache-2.0 | |
io.artifacthub.package.logo-url=https://avatars.githubusercontent.com/u/120078124?s=200&v=4 | |
io.artifacthub.package.maintainers=[{\"name\":\"tulilirockz\",\"email\":\"tulilirockz@outlook.com\"}] | |
- name: Fetch Build Outputs | |
if: github.event_name != 'pull_request' | |
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4 | |
with: | |
pattern: ${{ env.IMAGE_NAME }}-* | |
merge-multiple: true | |
path: /tmp/artifacts | |
- name: Load Outputs | |
if: github.event_name != 'pull_request' | |
id: load-outputs | |
run: | | |
set -x | |
DIGESTS_JSON=$(jq -n '{}') | |
for digest_file in /tmp/artifacts/*.txt; do | |
# Extract the platform from the file name | |
PLATFORM=$(basename $digest_file | rev | cut -d'-' -f1 | rev | cut -d'.' -f1) | |
DIGEST=$(cat $digest_file) | |
# Add the platform and digest to the JSON object | |
DIGESTS_JSON=$(echo "$DIGESTS_JSON" | jq --arg key "$PLATFORM" --arg value "$DIGEST" '. + {($key): $value}') | |
done | |
echo "DIGESTS_JSON=$(echo $DIGESTS_JSON | jq -c '.')" >> $GITHUB_OUTPUT | |
- name: Create Manifest | |
if: github.event_name != 'pull_request' | |
id: create-manifest | |
run: | | |
podman manifest create ${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }} | |
echo "MANIFEST=${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}" >> $GITHUB_OUTPUT | |
- name: Populate Manifest | |
if: github.event_name != 'pull_request' | |
env: | |
MANIFEST: ${{ steps.create-manifest.outputs.MANIFEST }} | |
DIGESTS_JSON: ${{ steps.load-outputs.outputs.DIGESTS_JSON }} | |
LABELS: ${{ steps.metadata.outputs.labels }} | |
run: | | |
set -x | |
DIGESTS=$(echo "$DIGESTS_JSON" | jq -c '.') | |
# turn the comma separated string into a list | |
platforms=() | |
IFS=',' read -r -a platforms <<< "${{ env.PLATFORMS }}" | |
for platform in ${platforms[@]}; do | |
digest=$(echo $DIGESTS | jq -r ".$platform") | |
echo "Adding ${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}@$digest for $platform" | |
podman manifest add $MANIFEST ${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}@$digest --arch $platform | |
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: Login to GHCR | |
if: github.event_name != 'pull_request' | |
run: echo ${{ secrets.GITHUB_TOKEN }} | podman login -u ${{ github.actor }} --password-stdin ghcr.io | |
- name: Push Manifest | |
if: github.event_name != 'pull_request' | |
id: push_manifest | |
env: | |
MANIFEST: ${{ steps.create-manifest.outputs.MANIFEST }} | |
TAGS: ${{ steps.metadata.outputs.tags }} | |
IMAGE_REGISTRY: ${{ env.IMAGE_REGISTRY }} | |
IMAGE_NAME: ${{ env.IMAGE_NAME }} | |
run: | | |
set -x | |
while IFS= read -r tag; do | |
podman manifest push --all=false --digestfile=/tmp/digestfile $MANIFEST $IMAGE_REGISTRY/$IMAGE_NAME:$tag | |
done <<< "$TAGS" | |
DIGEST=$(cat /tmp/digestfile) | |
echo "DIGEST=$DIGEST" >> $GITHUB_OUTPUT | |
echo "IMAGE=$IMAGE_REGISTRY/$IMAGE_NAME" >> $GITHUB_OUTPUT | |
# Cosign throws errors when ran inside the Fedora container for one reason or another | |
# so we move this to another step in order to run on Ubuntu | |
sign: | |
needs: manifest | |
if: github.event_name != 'pull_request' | |
runs-on: ubuntu-latest | |
permissions: | |
contents: read | |
packages: write | |
id-token: write | |
steps: | |
- name: Login to GHCR | |
run: | | |
echo ${{ secrets.GITHUB_TOKEN }} | docker login -u ${{ github.actor }} --password-stdin ghcr.io | |
echo ${{ secrets.GITHUB_TOKEN }} | podman login -u ${{ github.actor }} --password-stdin ghcr.io | |
- name: Install Cosign | |
uses: sigstore/cosign-installer@c56c2d3e59e4281cc41dea2217323ba5694b171e # v3.8.0 | |
- name: Sign Manifest | |
run: | | |
cosign sign -y --key env://COSIGN_PRIVATE_KEY $IMAGE@$DIGEST | |
env: | |
DIGEST: ${{ needs.manifest.outputs.digest }} | |
IMAGE: ${{ needs.manifest.outputs.image }} | |
COSIGN_EXPERIMENTAL: false | |
COSIGN_PRIVATE_KEY: ${{ secrets.SIGNING_SECRET }} |