This repository was archived by the owner on Feb 21, 2026. It is now read-only.
Build container image #65
This file contains hidden or 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 container image | |
| on: | |
| pull_request: | |
| branches: | |
| - main | |
| schedule: | |
| - cron: '05 10 * * *' # 10:05am UTC everyday | |
| push: | |
| branches: | |
| - main | |
| paths-ignore: | |
| - '**/README.md' | |
| workflow_dispatch: | |
| env: | |
| IMAGE_DESC: "My Customized Universal Blue Image" | |
| IMAGE_KEYWORDS: "bootc,ublue,universal-blue" | |
| IMAGE_LOGO_URL: "https://avatars.githubusercontent.com/u/120078124?s=200&v=4" # Put your own image here for a fancy profile on https://artifacthub.io/! | |
| IMAGE_NAME: "${{ github.event.repository.name }}" # output image name, usually same as repo name | |
| IMAGE_REGISTRY: "ghcr.io/${{ github.repository_owner }}" # do not edit | |
| DEFAULT_TAG: "stable" | |
| 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: | |
| - name: Prepare environment | |
| run: | | |
| # Lowercase the image uri | |
| echo "IMAGE_REGISTRY=${IMAGE_REGISTRY,,}" >> ${GITHUB_ENV} | |
| echo "IMAGE_NAME=${IMAGE_NAME,,}" >> ${GITHUB_ENV} | |
| # These stage versions are pinned by https://github.com/renovatebot/renovate | |
| - name: Checkout | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 | |
| # 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@517622d6452028f266b7ba4cc9a123b5f58a6b53 # v7 | |
| # with: | |
| # remove-codeql: true | |
| - name: Mount BTRFS for podman storage | |
| id: container-storage-action | |
| uses: ublue-os/container-storage-action@911baca08baf30c8654933e9e9723cb399892140 # main | |
| # Fallback to the remove-unwanted-software-action if github doesn't allocate enough space | |
| # See: https://github.com/ublue-os/container-storage-action/pull/11 | |
| continue-on-error: true | |
| with: | |
| target-dir: /var/lib/containers | |
| mount-opts: compress-force=zstd:2 | |
| - 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@c1e51972afc2121e065aed6d45c65596fe445f3f # v5 | |
| id: metadata | |
| with: | |
| # This generates all the tags for your image, you can add custom tags here too! | |
| # Default tags are "$DEFAULT_TAG" and "$DEFAULT_TAG.$date". | |
| tags: | | |
| type=raw,value=${{ env.DEFAULT_TAG }} | |
| type=raw,value=${{ env.DEFAULT_TAG }}.{{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://raw.githubusercontent.com/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}/${{ github.sha }}/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 }}/${{ github.sha }}/README.md | |
| org.opencontainers.image.source=https://github.com/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}/blob/${{ github.sha }}/Containerfile | |
| org.opencontainers.image.title=${{ env.IMAGE_NAME }} | |
| org.opencontainers.image.url=https://github.com/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}/tree/${{ github.sha }} | |
| org.opencontainers.image.vendor=${{ github.repository_owner }} | |
| org.opencontainers.image.version=${{ env.DEFAULT_TAG }}.{{date 'YYYYMMDD'}} | |
| io.artifacthub.package.deprecated=false | |
| io.artifacthub.package.keywords=${{ env.IMAGE_KEYWORDS }} | |
| io.artifacthub.package.license=Apache-2.0 | |
| io.artifacthub.package.logo-url=${{ env.IMAGE_LOGO_URL }} | |
| io.artifacthub.package.prerelease=false | |
| containers.bootc=1 | |
| sep-tags: " " | |
| sep-annotations: " " | |
| - name: Build Image | |
| id: build_image | |
| uses: redhat-actions/buildah-build@7a95fa7ee0f02d552a32753e7414641a04307056 # v2 | |
| with: | |
| containerfiles: | | |
| ./Containerfile | |
| # Postfix image name with -custom to make it a little more descriptive | |
| # Syntax: https://docs.github.com/en/actions/learn-github-actions/expressions#format | |
| image: ${{ env.IMAGE_NAME }} | |
| tags: ${{ env.DEFAULT_TAG }} | |
| labels: ${{ steps.metadata.outputs.labels }} | |
| oci: false | |
| # Rechunk (OPTIONAL): Rechunker optimizes container image layers for better resumability and fixes some distribution errors. | |
| # It doesn't make downloads faster but provides more reliable image distribution. | |
| # To enable rechunking: | |
| # 1. Uncomment the "Run Rechunker" step below | |
| # 2. Uncomment the "Load in podman and tag" step below | |
| # 3. Comment out or remove the "Tag for registry" step that follows this section | |
| # Documentation: https://github.com/hhd-dev/rechunk | |
| # - name: Run Rechunker | |
| # id: rechunk | |
| # uses: hhd-dev/rechunk@5fbe1d3a639615d2548d83bc888360de6267b1a2 # v1.2.4 | |
| # with: | |
| # rechunk: 'ghcr.io/hhd-dev/rechunk:v1.2.4' | |
| # ref: "${{ env.IMAGE_NAME }}:${{ env.DEFAULT_TAG }}" | |
| # prev-ref: "${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.DEFAULT_TAG }}" | |
| # version: "${{ env.DEFAULT_TAG }}" | |
| # labels: | | |
| # io.artifacthub.package.readme-url=https://raw.githubusercontent.com/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}/${{ github.sha }}/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 }}/${{ github.sha }}/README.md | |
| # org.opencontainers.image.source=https://github.com/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}/blob/${{ github.sha }}/Containerfile | |
| # org.opencontainers.image.title=${{ env.IMAGE_NAME }} | |
| # org.opencontainers.image.url=https://github.com/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}/tree/${{ github.sha }} | |
| # org.opencontainers.image.vendor=${{ github.repository_owner }} | |
| # org.opencontainers.image.version=${{ env.DEFAULT_TAG }}.{{date 'YYYYMMDD'}} | |
| # io.artifacthub.package.deprecated=false | |
| # io.artifacthub.package.keywords=${{ env.IMAGE_KEYWORDS }} | |
| # io.artifacthub.package.license=Apache-2.0 | |
| # io.artifacthub.package.logo-url=${{ env.IMAGE_LOGO_URL }} | |
| # io.artifacthub.package.prerelease=false | |
| # containers.bootc=1 | |
| # - name: Load in podman and tag | |
| # run: | | |
| # IMAGE=$(podman pull ${{ steps.rechunk.outputs.ref }}) | |
| # sudo rm -rf ${{ steps.rechunk.outputs.output }} | |
| # for tag in ${{ steps.metadata.outputs.tags }}; do | |
| # podman tag $IMAGE ${{ env.IMAGE_NAME }}:$tag | |
| # done | |
| # Tag for registry (remove this step if using rechunker above) | |
| - name: Tag for registry | |
| run: | | |
| for tag in ${{ steps.metadata.outputs.tags }}; do | |
| podman tag ${{ env.IMAGE_NAME }}:${{ env.DEFAULT_TAG }} ${{ env.IMAGE_NAME }}:$tag | |
| done | |
| # SBOM (OPTIONAL): Software Bill of Materials generation using Syft | |
| # Creates a detailed inventory of all software components in the image for supply chain security. | |
| # To enable: | |
| # 1. Uncomment the "Setup Syft" step below | |
| # 2. Uncomment the "Generate SBOM" step below | |
| # 3. If using image signing, also uncomment the "Add SBOM Attestation" step further down | |
| # Documentation: https://github.com/anchore/syft | |
| # - name: Setup Syft | |
| # id: setup-syft | |
| # uses: anchore/sbom-action/download-syft@8e94d75ddd33f69f691467e42275782e4bfefe84 # v0.20.9 | |
| # with: | |
| # syft-version: v1.20.0 | |
| # | |
| # - name: Generate SBOM | |
| # id: generate-sbom | |
| # env: | |
| # IMAGE: ${{ env.IMAGE_NAME }} | |
| # DEFAULT_TAG: ${{ env.DEFAULT_TAG }} | |
| # SYFT_CMD: ${{ steps.setup-syft.outputs.cmd }} | |
| # run: | | |
| # OUTPUT_PATH="$(mktemp -d)/sbom.json" | |
| # export SYFT_PARALLELISM=$(($(nproc)*2)) | |
| # $SYFT_CMD ${IMAGE}:${DEFAULT_TAG} -o spdx-json=${OUTPUT_PATH} | |
| # echo "OUTPUT_PATH=${OUTPUT_PATH}" >> $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@5e57cd118135c172c3672efd75eb46360885c0ef # 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 }} | |
| - name: Push To GHCR | |
| uses: redhat-actions/push-to-registry@5ed88d269cf581ea9ef6dd6806d01562096bee9c # v2 | |
| if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) | |
| id: push | |
| env: | |
| REGISTRY_USER: ${{ github.actor }} | |
| REGISTRY_PASSWORD: ${{ github.token }} | |
| with: | |
| registry: ${{ env.IMAGE_REGISTRY }} | |
| image: ${{ env.IMAGE_NAME }} | |
| tags: ${{ steps.metadata.outputs.tags }} | |
| username: ${{ env.REGISTRY_USER }} | |
| password: ${{ env.REGISTRY_PASSWORD }} |