From 36234032a3852c6007694e08d12f3d5ebd28bf1c Mon Sep 17 00:00:00 2001 From: Tim deBoer Date: Wed, 3 Dec 2025 10:00:05 -0500 Subject: [PATCH] chore: switch to container build The final output of the build was an OCI container, but it was purely used for packaging. This moves the Containerfile to the /build folder and does the full pnpm build using a builder image. Images published are extension-bootc-builder and extension-bootc, switching from the previous podman-desktop-extension-bootc to match what newer extensions have done and make the switch obvious. First part: leaves existing container file in root for e2e tests to run, once workflow has successfully run once we can reuse the latest builder image instead, and remove the Containerfile at root. First part of #2101. Signed-off-by: Tim deBoer --- .github/workflows/build-next.yaml | 124 ++++++++++++++++++++++++------ .github/workflows/release.yaml | 118 ++++++++++++++++++++++------ RELEASE.md | 2 +- build/Containerfile | 67 ++++++++++++++++ build/Containerfile.builder | 31 ++++++++ 5 files changed, 293 insertions(+), 49 deletions(-) create mode 100644 build/Containerfile create mode 100644 build/Containerfile.builder diff --git a/.github/workflows/build-next.yaml b/.github/workflows/build-next.yaml index c1b4a7ac..3842581f 100644 --- a/.github/workflows/build-next.yaml +++ b/.github/workflows/build-next.yaml @@ -1,5 +1,5 @@ # -# Copyright (C) 2023-2024 Red Hat, Inc. +# Copyright (C) 2023-2025 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -23,37 +23,111 @@ on: - 'main' jobs: - build: - runs-on: ubuntu-22.04 + check-builder-changes: + runs-on: ubuntu-24.04 + outputs: + builder_required: ${{ steps.check.outputs.builder_required }} + steps: + - name: Checkout Repository + uses: actions/checkout@v6 + with: + fetch-depth: 2 # Ensure we have at least one previous commit for diff check + + - name: Check for builder-related changes + id: check + run: | + if git diff --name-only HEAD^ HEAD | grep -E '^(package.json|pnpm-lock.yaml|build/Containerfile.builder|.github/workflows/build-next.yaml)$'; then + echo "builder_required=true" >> $GITHUB_OUTPUT + else + echo "builder_required=false" >> $GITHUB_OUTPUT + fi + + builder-image: + needs: check-builder-changes + if: needs.check-builder-changes.outputs.builder_required == 'true' + name: Build and publish builder OCI images only if pnpm-lock.yaml or package.json changes + runs-on: ubuntu-24.04 + steps: - uses: actions/checkout@v6 + with: + fetch-depth: 0 - - uses: pnpm/action-setup@v4 - name: Install pnpm + - name: build builder image + id: builder-image + uses: redhat-actions/buildah-build@v2 with: - run_install: false + image: extension-bootc-builder + tags: next ${{ github.sha }} + platforms: linux/amd64, linux/arm64 + containerfiles: | + build/Containerfile.builder + context: . + oci: true - - uses: actions/setup-node@v6 + - name: Log in to ghcr.io + uses: redhat-actions/podman-login@v1 with: - node-version: 22 - cache: 'pnpm' + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + registry: ghcr.io - - name: Execute pnpm - run: pnpm install + - name: publish builder to ghcr.io + id: push-to-ghcr + uses: redhat-actions/push-to-registry@v2 + with: + image: ${{ steps.builder-image.outputs.image }} + tags: ${{ steps.builder-image.outputs.tags }} + registry: ghcr.io/${{ github.repository_owner }} - - name: Run Build - run: pnpm build + - name: Generate artifact attestation + uses: actions/attest-build-provenance@v3 + with: + subject-name: ghcr.io/${{ github.repository_owner }}/extension-bootc-builder + subject-digest: ${{ steps.push-to-ghcr.outputs.digest }} + push-to-registry: true - - name: Login to ghcr.io - run: podman login --username ${{ github.repository_owner }} --password ${{ secrets.GITHUB_TOKEN }} ghcr.io + extension-image: + name: Build and publish extension OCI image + if: always() + runs-on: ubuntu-24.04 + needs: builder-image - - name: Publish Image - id: publish-image - run: | - IMAGE_NAME=ghcr.io/${{ github.repository_owner }}/podman-desktop-extension-bootc - IMAGE_NIGHTLY=${IMAGE_NAME}:nightly - IMAGE_SHA=${IMAGE_NAME}:${GITHUB_SHA} - podman build -t $IMAGE_NIGHTLY . - podman push $IMAGE_NIGHTLY - podman tag $IMAGE_NIGHTLY $IMAGE_SHA - podman push $IMAGE_SHA + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: build extension image + id: extension-image + uses: redhat-actions/buildah-build@v2 + with: + image: extension-bootc + tags: next ${{ github.sha }} + archs: amd64, arm64 + containerfiles: | + build/Containerfile + context: . + oci: true + + - name: Log in to ghcr.io + uses: redhat-actions/podman-login@v1 + with: + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + registry: ghcr.io + + - name: publish extension to ghcr.io + id: push-to-ghcr + uses: redhat-actions/push-to-registry@v2 + with: + image: ${{ steps.extension-image.outputs.image }} + tags: ${{ steps.extension-image.outputs.tags }} + registry: ghcr.io/${{ github.repository_owner }} + + - name: Generate artifact attestation + uses: actions/attest-build-provenance@v3 + with: + subject-name: ghcr.io/${{ github.repository_owner }}/extension-bootc + subject-digest: ${{ steps.push-to-ghcr.outputs.digest }} + push-to-registry: true diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 9f207a28..ca9c0ee8 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -1,5 +1,5 @@ # -# Copyright (C) 2023-2024 Red Hat, Inc. +# Copyright (C) 2023-2025 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -103,32 +103,104 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - uses: pnpm/action-setup@v4 - name: Install pnpm + builder-image: + needs: tag + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v6 with: - run_install: false + ref: ${{ needs.tag.outputs.githubTag }} - - uses: actions/setup-node@v6 + - name: build builder image + id: builder-image + uses: redhat-actions/buildah-build@v2 with: - node-version: 22 - cache: 'pnpm' + image: extension-bootc-builder + tags: latest ${{ needs.tag.outputs.bootcExtensionVersion }} + platforms: linux/amd64, linux/arm64 + containerfiles: | + build/Containerfile.builder + context: . + oci: true - - name: Execute pnpm - run: pnpm install + - name: Log in to ghcr.io + uses: redhat-actions/podman-login@v1 + with: + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + registry: ghcr.io - - name: Run Build - run: pnpm build + - name: publish builder to ghcr.io + id: push-to-ghcr + uses: redhat-actions/push-to-registry@v2 + with: + image: ${{ steps.builder-image.outputs.image }} + tags: ${{ steps.builder-image.outputs.tags }} + registry: ghcr.io/${{ github.repository_owner }} - - name: Login to ghcr.io - run: podman login --username ${{ github.repository_owner }} --password ${{ secrets.GITHUB_TOKEN }} ghcr.io + - name: Generate artifact attestation + uses: actions/attest-build-provenance@v3 + with: + subject-name: ghcr.io/${{ github.repository_owner }}/extension-bootc-builder + subject-digest: ${{ steps.push-to-ghcr.outputs.digest }} + push-to-registry: true - - name: Publish Image - id: publish-image - run: | - IMAGE_NAME=ghcr.io/${{ github.repository_owner }}/podman-desktop-extension-bootc - IMAGE_WITH_TAG=${IMAGE_NAME}:${{ steps.TAG_UTIL.outputs.bootcExtensionVersion }} - IMAGE_LATEST=${IMAGE_NAME}:latest - podman build -t $IMAGE_WITH_TAG . - podman push $IMAGE_WITH_TAG - podman tag $IMAGE_WITH_TAG $IMAGE_LATEST - podman push $IMAGE_LATEST + extension-image: + name: Build and publish extension OCI image + + runs-on: ubuntu-24.04 + needs: [builder-image, tag] + + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: build extension image + id: extension-image + uses: redhat-actions/buildah-build@v2 + with: + image: extension-bootc + tags: latest ${{ needs.tag.outputs.bootcExtensionVersion }} + archs: amd64, arm64 + containerfiles: | + build/Containerfile + context: . + oci: true + + - name: Log in to ghcr.io + uses: redhat-actions/podman-login@v1 + with: + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + registry: ghcr.io + + - name: publish extension to ghcr.io + id: push-to-ghcr + uses: redhat-actions/push-to-registry@v2 + with: + image: ${{ steps.extension-image.outputs.image }} + tags: ${{ steps.extension-image.outputs.tags }} + registry: ghcr.io/${{ github.repository_owner }} + + - name: Generate artifact attestation + uses: actions/attest-build-provenance@v3 + with: + subject-name: ghcr.io/${{ github.repository_owner }}/extension-bootc + subject-digest: ${{ steps.push-to-ghcr.outputs.digest }} + push-to-registry: true + + release: + needs: [tag, builder-image, extension-image] + name: Release + runs-on: ubuntu-24.04 + steps: + - name: id + run: echo the release id is ${{ needs.tag.outputs.releaseId}} + + - name: Publish release + uses: StuYarrow/publish-release@v1.1.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + id: ${{ needs.tag.outputs.releaseId}} diff --git a/RELEASE.md b/RELEASE.md index b843f041..12097135 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -19,7 +19,7 @@ In the below example, we will pretend that we're upgrading from `1.1.0` to `1.2. 1. Make sure that all tasks for the respective release milestone are completed / updated, then close it. https://github.com/podman-desktop/podman-desktop-extension-bootc/milestones 1. If not already created, click on `New Milestone` and create a new milestone for the NEXT release. 1. Check that https://github.com/podman-desktop/podman-desktop-extension-bootc/actions/workflows/release.yaml has been completed. -1. Ensure the image has been successfully published to https://github.com/podman-desktop/extension-bootc/pkgs/container/podman-desktop-extension-bootc +1. Ensure the image has been successfully published to https://github.com/podman-desktop/extension-bootc/pkgs/container/extension-bootc 1. There should be an automated PR that has been created. The title looks like `chore: 📢 Bump version to 1.3.0`. Rerun workflow manually if some of e2e tests are failing. 1. Wait for the PR above to be approved and merged before continuing with the steps. 1. Edit the new release https://github.com/podman-desktop/podman-desktop-extension-bootc/releases/edit/v1.2.0. diff --git a/build/Containerfile b/build/Containerfile new file mode 100644 index 00000000..8fcdee55 --- /dev/null +++ b/build/Containerfile @@ -0,0 +1,67 @@ +# +# Copyright (C) 2025 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +FROM ghcr.io/podman-desktop/extension-bootc-builder:next AS builder + +WORKDIR /opt/app-root/extension-source + +# copy source code +COPY --chown=1001:root *.js /opt/app-root/extension-source/ +COPY --chown=1001:root .gitignore /opt/app-root/extension-source/ +COPY --chown=1001:root *.json /opt/app-root/extension-source/ +COPY --chown=1001:root packages /opt/app-root/extension-source/packages +COPY --chown=1001:root .npmrc /opt/app-root/extension-source/ +COPY --chown=1001:root .gitignore /opt/app-root/extension-source/ +COPY --chown=1001:root types /opt/app-root/extension-source/types + +# refresh dependencies (if needed) +# and build the extension +RUN pnpm install && \ + pnpm build + +# copy output of the build + required files +RUN mkdir /opt/app-root/extension && \ + cp -r packages/backend/dist /opt/app-root/extension/ && \ + cp packages/backend/package.json /opt/app-root/extension/ && \ + cp packages/backend/bootable.woff2 /opt/app-root/extension/ && \ + cp packages/backend/icon.png /opt/app-root/extension/ && \ + cp -r packages/backend/media/ /opt/app-root/extension/media + +COPY LICENSE /opt/app-root/extension/ +COPY README.md /opt/app-root/extension/ + +# TEMPORARY. Permanent fix will be in the future when we can add all of this to vite script. +# We require the macadam.js binaries and library, so we will manually copy this over to the container image. +# we rely on `pnpm build` before creating the container image, so we can safely assume that the macadam.js binaries are already present in the node_modules directory +# and can copy them over to the container image. +COPY node_modules/@crc-org/macadam.js /opt/app-root/extension/node_modules/@crc-org/macadam.js +# Copy over ssh2 and it's dependencies (run jq '.dependencies' node_modules/ssh2/package.json locally to see) +COPY node_modules/ssh2 /opt/app-root/extension/node_modules/ssh2 +COPY node_modules/asn1 /opt/app-root/extension/node_modules/asn1 +COPY node_modules/bcrypt-pbkdf /opt/app-root/extension/node_modules/bcrypt-pbkdf +COPY node_modules/safer-buffer /opt/app-root/extension/node_modules/safer-buffer +COPY node_modules/tweetnacl /opt/app-root/extension/node_modules/tweetnacl + +# Copy the extension to a new image +FROM scratch + +LABEL org.opencontainers.image.title="Bootable Container Extension" \ + org.opencontainers.image.description="Podman Desktop extension for bootable OS containers (bootc) and generating disk images" \ + org.opencontainers.image.vendor="Red Hat" \ + io.podman-desktop.api.version=">= 1.18.0" + +COPY --from=builder /opt/app-root/extension /extension diff --git a/build/Containerfile.builder b/build/Containerfile.builder new file mode 100644 index 00000000..ac438593 --- /dev/null +++ b/build/Containerfile.builder @@ -0,0 +1,31 @@ +# +# Copyright (C) 2025 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +FROM registry.access.redhat.com/ubi10/nodejs-22-minimal:10.1-1764649415 + +# change home directory to be at /opt/app-root +ENV HOME=/opt/app-root + +# copy the application files to the /opt/app-root/extension-source directory +WORKDIR /opt/app-root/extension-source +RUN mkdir -p /opt/app-root/extension-source +COPY package.json pnpm-lock.yaml pnpm-workspace.yaml .npmrc /opt/app-root/extension-source/ +COPY packages/backend/package.json /opt/app-root/extension-source/packages/backend/package.json +COPY packages/frontend/package.json /opt/app-root/extension-source/packages/frontend/package.json + +RUN npm install --global pnpm@10 && \ + pnpm --frozen-lockfile install