From a65bb3da1f7c5ed04ac3d8b5f69878c5ecee14ea Mon Sep 17 00:00:00 2001 From: renner <80410025+renner0e@users.noreply.github.com> Date: Wed, 17 Jun 2026 16:16:34 +0200 Subject: refactor: rewrite in just, saner defaults (#218) * refactor: rewrite in just, saner defaults I think it makes sense to do this as it is longterm easier to maintain, locally iterate and extend. Documents how to rebase to a local image, it pains me greatly when people iterate on github and wait forever for things to build and then to download the image for trivial things they could also quickly do locally. Rpm-ostree rechunker by default instead of opt-in legacy-rechunker, chunkah is also available if people want to use it already, if we deem it ready then we can enable it later on. They can all be opted-out of. Have a way to copy files to /{usr,etc} by default. We should sign the digest of the image instead of the tag. Co-Authored-by: a lot of sugar and bad music * docs: bump fedora-bootc version Co-authored-by: Jill Fiore * fix: formatting inconsistency Co-authored-by: Jill Fiore * docs: remove variable mentions from workflows These are now defined in the image-template.env file * fix: small nits in labels Co-authored-by: Adam Fidel --------- Co-authored-by: Jill Fiore Co-authored-by: Adam Fidel --- .github/workflows/build.yml | 193 ++++++++++++++++++++------------------------ 1 file changed, 89 insertions(+), 104 deletions(-) (limited to '.github/workflows/build.yml') diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 85a8c97..e355434 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,12 +14,7 @@ on: 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: "latest" concurrency: group: ${{ github.workflow }}-${{ github.ref || github.run_id }}-${{ inputs.brand_name}}-${{ inputs.stream_name }} @@ -36,98 +31,87 @@ jobs: 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@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 - # 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@695eb75bc387dbcd9685a8e72d23439d8686cba6 - - name: Get current date - id: date + - name: Install just + uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 #v4.0.0 + + - name: Check Just Syntax + shell: bash 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@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0 - 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: " " + just check + + - name: Image Name + id: image-name + run: | + IMAGE_NAME=$(just image_name) + + echo "IMAGE_NAME=${IMAGE_NAME}" >> $GITHUB_ENV + + - name: Default Tag + id: gen-default-tag + run: | + DEFAULT_TAG=$(just generate-default-tag) + + echo "DEFAULT_TAG=${DEFAULT_TAG}" >> $GITHUB_ENV + + - name: Prepare environment + run: | + # Lowercase the image uri https://github.com/macbre/push-to-ghcr/issues/12 + echo "IMAGE_REGISTRY=${IMAGE_REGISTRY,,}" >> ${GITHUB_ENV} + echo "IMAGE_NAME=${IMAGE_NAME,,}" >> ${GITHUB_ENV} + # This actually builds the container image - 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: ${{ steps.metadata.outputs.tags }} - labels: ${{ steps.metadata.outputs.labels }} - oci: false - - # 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: ublue-os/legacy-rechunk@a925083d9af7cb04b3e2a6e8c01bfa495f38b710 # v1.0.0 - # with: - # rechunk: 'ghcr.io/ublue-os/legacy-rechunk:v1.0.0-x86_64' - # ref: "localhost/${{ env.IMAGE_NAME }}:${{ env.DEFAULT_TAG }}" - # prev-ref: "${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.DEFAULT_TAG }}" - # skip_compression: true - # version: ${{ env.CENTOS_VERSION }} - # labels: ${{ steps.metadata.outputs.labels }} # Rechunk strips out all the labels during build, this needs to be reapplied here with newline separator - - # This is necessary so that the podman socket can find the rechunked image on its storage - # - 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 + id: build-image + run: | + sudo -E $(command -v just) build \ + ${IMAGE_NAME} \ + ${DEFAULT_TAG} + + # This is optional, this provides smaller delta updates + - name: Rechunk with rpm-ostree + id: rechunk + run: | + sudo -E $(command -v just) ostree-rechunk \ + ${IMAGE_NAME} \ + ${DEFAULT_TAG} + + # If you are feeling adventurous, use the new distro agnostic rechunker + # https://github.com/coreos/chunkah + # You can delete the Rechunk with rpm-ostree portion then if you use this + #- name: Rechunk with Chunkah + # id: rechunk + # run: | + # sudo -E $(command -v just) rechunk \ + # ${IMAGE_NAME} \ + # ${DEFAULT_TAG} + + - name: Generate Build Tags + id: gen-build-tags + run: | + alias_tags="$(just generate-build-tags \ + ${IMAGE_NAME} \ + ${DEFAULT_TAG})" + + echo "Tags for this Action..." + echo "${alias_tags}" + echo "alias_tags=${alias_tags}" >> $GITHUB_OUTPUT + + - name: Tag Image + id: tag-images + env: + ALIAS_TAGS: ${{ steps.gen-build-tags.outputs.alias_tags }} + run: | + sudo -E $(command -v just) tag-images \ + "${IMAGE_NAME}" \ + "${DEFAULT_TAG}" \ + "${ALIAS_TAGS}" # 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 @@ -140,37 +124,38 @@ jobs: 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 + id: push-image 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 }} + ALIAS_TAGS: ${{ steps.gen-build-tags.outputs.alias_tags }} + run: | + set -euox pipefail + for tag in ${ALIAS_TAGS}; do + sudo -E podman push --digestfile=/tmp/digestfile ${IMAGE_NAME}:${tag} ${IMAGE_REGISTRY}/${IMAGE_NAME}:${tag} + done + + digest=$(< /tmp/digestfile) + + 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@ba7bc0a3fef59531c69a25acd34668d6d3fe6f22 # v4.1.0 + uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2 if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) + # https://github.com/containers/container-libs/issues/388 with: cosign-release: 'v2.6.3' - name: Sign container image + id: sign-image if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) - run: | - IMAGE_FULL="${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}" - for tag in ${{ steps.metadata.outputs.tags }}; do - cosign sign -y --key env://COSIGN_PRIVATE_KEY $IMAGE_FULL:$tag - done env: - TAGS: ${{ steps.push.outputs.digest }} COSIGN_EXPERIMENTAL: false COSIGN_PRIVATE_KEY: ${{ secrets.SIGNING_SECRET }} + DIGEST: ${{ steps.push-image.outputs.digest }} + run: | + cosign sign -y --key env://COSIGN_PRIVATE_KEY ${IMAGE_REGISTRY}/${IMAGE_NAME}@${DIGEST} + -- cgit v1.2.3