From 2058480226752926303b785f94a712b2978a8ec3 Mon Sep 17 00:00:00 2001 From: phantom <137958098+phantomcortex@users.noreply.github.com> Date: Mon, 20 Oct 2025 12:22:39 -0600 Subject: [PATCH] Official rechunker build working rechunker ready for merge. --- .github/workflows/build.yml | 220 +++++++++++++++++++++++------------- 1 file changed, 139 insertions(+), 81 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 05544de..16798e7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,26 +5,35 @@ on: branches: - main schedule: - - cron: '05 8 */4 * *' # 2:05am Mountain time every 4 days - #push: - # branches: - # - main - # paths-ignore: - # - '**/README.md' - # - '**/claude.md' - # - 'repo_files/**' + - cron: '05 8 */5 * *' # 2:05am Mountain time every 5 days + push: + branches: + - main + paths-ignore: + - '.github/**' + - '**/README.md' + - '**/claude.md' + - 'repo_files/**' + - 'system_files/**' # modifcations to custom system files are usually small don't warrent a full rebuild + workflow_dispatch: - + inputs: + fresh-rechunk: + description: 'Clear rechunk history (forces full redownload for users)' + type: boolean + default: false env: - IMAGE_DESC: "My Customized Universal Blue Image" + IMAGE_DESC: "My Customized Bazzite 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_LOGO_URL: "https://avatars.githubusercontent.com/u/120078124?s=200&v=4" 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" +# TODO: optimize build (if possible) + concurrency: - group: ${{ github.workflow }}-${{ github.ref || github.run_id }}-${{ inputs.brand_name}}-${{ inputs.stream_name }} + group: ${{ github.workflow }}-${{ github.ref || github.run_id }} cancel-in-progress: true jobs: @@ -38,36 +47,21 @@ jobs: id-token: write steps: + # These stage versions are pinned by https://github.com/renovatebot/renovate + - name: Checkout + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4 + - 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 # v4 - - # 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 - uses: ublue-os/container-storage-action@main - - 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 @@ -98,58 +92,110 @@ jobs: containers.bootc=1 sep-tags: " " sep-annotations: " " - - - name: Build Image + + - name: Maximize build space + uses: jlumbroso/free-disk-space@v1.3.1 + with: + android: true + dotnet: true + haskell: true + large-packages: true + docker-images: false + swap-storage: true + + - name: Build image (rootful) id: build_image - uses: redhat-actions/buildah-build@7a95fa7ee0f02d552a32753e7414641a04307056 # v2 + run: | + # Builds image in root store as root, to be picked up by Rechunker + sudo buildah bud \ + --format docker \ + --tag "localhost/${IMAGE_NAME}:${{ env.DEFAULT_TAG }}" \ + --file Containerfile \ + . + + - name: Remove source images + run: | + images=$(sudo podman images -n --sort repository --format '{{.ID}} {{.Repository}}' | grep -v localhost | awk '{print $1}') + if [ -n "${images}" ]; then + for image in ${images}; do + echo "Removing image: $image" + sudo podman rmi --force "$image" + done + else + echo "No images to remove." + fi + + + - name: Run Rechunker + id: rechunk + uses: hhd-dev/rechunk@v1.2.3 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: hhd-dev/rechunk@f153348d8100c1f504dec435460a0d7baf11a9d2 # v1.1.1 -# with: -# rechunk: 'ghcr.io/hhd-dev/rechunk:v1.0.1' -# 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 }} # leaving labels as is might work? -# 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 - - # 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 + rechunk: "ghcr.io/hhd-dev/rechunk:v1.2.3" + ref: "localhost/${{ env.IMAGE_NAME }}:${{ env.DEFAULT_TAG }}" + prev-ref: "${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.DEFAULT_TAG }}" + skip_compression: false + max-layers: 110 + labels: ${{ steps.metadata.outputs.labels }} # Rechunk strips out all the labels during build, this needs to be reapplied here with newline separator + + - name: Remove Rechunker image + run: | + image=$(sudo podman images -n --sort repository --format '{{.ID}} {{.Repository}}' | grep rechunk | awk '{print $1}') + if [ -n "${image}" ]; then + sudo podman rmi --force "$image" + else + echo "No image to remove" + fi + + - name: Rechunk output + run: | + if [[ "${STEPS_RECHUNK_CONCLUSION}" == "success" ]]; then + echo "=== Rechunk Changelog ===" + if [ -f "${STEPS_RECHUNK_OUTPUTS_CHANGELOG}" ]; then + cat "${STEPS_RECHUNK_OUTPUTS_CHANGELOG}" + fi + echo "" + echo "=== Rechunk Manifest ===" + if [ -f "${STEPS_RECHUNK_OUTPUTS_MANIFEST}" ]; then + cat "${STEPS_RECHUNK_OUTPUTS_MANIFEST}" + fi + else + echo "Rechunk conclusion: ${STEPS_RECHUNK_CONCLUSION}" + fi + env: + STEPS_RECHUNK_CONCLUSION: ${{ steps.rechunk.conclusion }} + STEPS_RECHUNK_OUTPUTS_CHANGELOG: ${{ steps.rechunk.outputs.changelog }} + STEPS_RECHUNK_OUTPUTS_MANIFEST: ${{ steps.rechunk.outputs.manifest }} + + - name: Load in podman and tag + run: | + IMAGE=$(podman pull ${STEPS_RECHUNK_OUTPUTS_REF}) + sudo rm -rf ${STEPS_RECHUNK_OUTPUTS_LOCATION} + for tag in ${STEPS_METADATA_OUTPUTS_TAGS}; do + podman tag $IMAGE ${IMAGE_NAME}:$tag + done + env: + STEPS_RECHUNK_OUTPUTS_REF: ${{ steps.rechunk.outputs.ref }} + STEPS_RECHUNK_OUTPUTS_LOCATION: ${{ steps.rechunk.outputs.location }} + STEPS_METADATA_OUTPUTS_TAGS: ${{ steps.metadata.outputs.tags }} + IMAGE_NAME: ${{ env.IMAGE_NAME }} + - 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) + uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3 + if: github.event_name != 'pull_request' with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Lowercase Registry + id: registry_case + uses: ASzc/change-string-case-action@v6 + with: + string: ${{ env.IMAGE_REGISTRY }} + - 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) + if: github.event_name != 'pull_request' id: push env: REGISTRY_USER: ${{ github.actor }} @@ -160,23 +206,35 @@ jobs: tags: ${{ steps.metadata.outputs.tags }} username: ${{ env.REGISTRY_USER }} password: ${{ env.REGISTRY_PASSWORD }} + extra-args: | + --compression-format=gzip + --compression-level=9 # 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@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0 - if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) + uses: sigstore/cosign-installer@d7543c93d881b35a8faa02e8e3605f69b7a1ce62 # v3.10.0 + if: github.event_name != 'pull_request' - name: Sign container image - if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) + id: sign_container_image + if: github.event_name != 'pull_request' 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 + echo "${STEPS_PUSH_OUTPUTS_REGISTRY_PATHS}" + IMAGE_FULL="${STEPS_REGISTRY_CASE_OUTPUTS_LOWERCASE}/${IMAGE_NAME}" + cosign sign -y --key env://COSIGN_PRIVATE_KEY $IMAGE_FULL@"${STEPS_PUSH_OUTPUTS_DIGEST}" env: - TAGS: ${{ steps.push.outputs.digest }} COSIGN_EXPERIMENTAL: false COSIGN_PRIVATE_KEY: ${{ secrets.SIGNING_SECRET }} + STEPS_PUSH_OUTPUTS_REGISTRY_PATHS: ${{ steps.push.outputs.registry-paths }} + STEPS_REGISTRY_CASE_OUTPUTS_LOWERCASE: ${{ steps.registry_case.outputs.lowercase }} + STEPS_PUSH_OUTPUTS_DIGEST: ${{ steps.push.outputs.digest }} + + - name: Create changelog annotation + id: changelog + continue-on-error: true + run: | + CHANGELOG=$(.github/workflows/shared/changelog.py distinctionos -) + echo "$CHANGELOG" >> $GITHUB_STEP_SUMMARY