diff --git a/.github/workflows/backend-release.yml b/.github/workflows/backend-release.yml index 4efe4665..85ba4b48 100644 --- a/.github/workflows/backend-release.yml +++ b/.github/workflows/backend-release.yml @@ -1,7 +1,8 @@ name: Backend release # A version bump on main tags the commit, creates the GitHub release, then -# publishes the Docker images and the PyPI package by calling those workflows. +# publishes the backend and frontend Docker images and the PyPI package by +# calling those workflows. # The release is created with GITHUB_TOKEN, and GitHub never starts workflows # from events that token produces, so the `release: published` triggers on the # publish workflows would not fire (0.18.0 got no images that way). Releases @@ -109,6 +110,19 @@ jobs: contents: write # release-assets attaches the compose file to the release packages: write + frontend: + needs: release + if: needs.release.outputs.created == 'true' + uses: $/.github/workflows/cife.yml + with: + version: ${{ needs.release.outputs.version }} + secrets: + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} + permissions: + contents: read + packages: write + pypi: needs: release if: needs.release.outputs.created == 'true' diff --git a/.github/workflows/cife.yml b/.github/workflows/cife.yml index 1118723f..c8f629f5 100644 --- a/.github/workflows/cife.yml +++ b/.github/workflows/cife.yml @@ -1,12 +1,43 @@ name: Build and push DocsGPT-FE Docker image +# Runs for a release created by hand (the release event), or called by the +# backend-release workflow with the version it just tagged: GitHub never starts +# workflows from events GITHUB_TOKEN produces, so a bot-created release does not +# fire the release trigger on its own. + on: release: types: [published] + workflow_call: + inputs: + version: + description: Release tag to build and push (the images are tagged with it) + type: string + required: true + secrets: + DOCKER_USERNAME: + required: true + DOCKER_PASSWORD: + required: true + +permissions: + contents: read + +env: + # The tag being published: passed in by the caller, or the release's own. + RELEASE_TAG: ${{ inputs.version || github.event.release.tag_name }} jobs: build: if: github.repository == 'arc53/DocsGPT' + # Publishing jobs run in a GitHub Actions environment so the registry + # credentials can be scoped to it and protection rules (required reviewers, + # branch restrictions) applied in the repository settings. + environment: docker-hub + env: + # Public namespace the compose files pull from; the login secret only + # authenticates the push. + DOCKERHUB_NAMESPACE: arc53 strategy: matrix: include: @@ -21,92 +52,100 @@ jobs: contents: read packages: write steps: - - uses: actions/checkout@v4 - - - name: Set up QEMU # Only needed for emulation, not for native arm64 builds - if: matrix.platform == 'linux/arm64' - uses: docker/setup-qemu-action@v3 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + with: + persist-credentials: false - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 with: driver: docker-container install: true - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Login to ghcr.io - uses: docker/login-action@v3 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Image metadata (OCI labels) + id: meta + uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0 + with: + images: | + ${{ env.DOCKERHUB_NAMESPACE }}/docsgpt-fe + ghcr.io/${{ github.repository_owner }}/docsgpt-fe + labels: | + org.opencontainers.image.title=DocsGPT-FE + org.opencontainers.image.version=${{ env.RELEASE_TAG }} + - name: Build and push platform-specific images - uses: docker/build-push-action@v6 + uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 with: file: './frontend/Dockerfile' platforms: ${{ matrix.platform }} context: ./frontend push: true tags: | - ${{ secrets.DOCKER_USERNAME }}/docsgpt-fe:${{ github.event.release.tag_name }}-${{ matrix.suffix }} - ghcr.io/${{ github.repository_owner }}/docsgpt-fe:${{ github.event.release.tag_name }}-${{ matrix.suffix }} + ${{ env.DOCKERHUB_NAMESPACE }}/docsgpt-fe:${{ env.RELEASE_TAG }}-${{ matrix.suffix }} + ghcr.io/${{ github.repository_owner }}/docsgpt-fe:${{ env.RELEASE_TAG }}-${{ matrix.suffix }} + labels: ${{ steps.meta.outputs.labels }} provenance: false sbom: false - cache-from: type=registry,ref=${{ secrets.DOCKER_USERNAME }}/docsgpt-fe:latest + cache-from: type=registry,ref=${{ env.DOCKERHUB_NAMESPACE }}/docsgpt-fe:latest cache-to: type=inline manifest: if: github.repository == 'arc53/DocsGPT' + # Publishing jobs run in a GitHub Actions environment so the registry + # credentials can be scoped to it and protection rules (required reviewers, + # branch restrictions) applied in the repository settings. + environment: docker-hub + env: + # Public namespace the compose files pull from; the login secret only + # authenticates the push. + DOCKERHUB_NAMESPACE: arc53 needs: build runs-on: ubuntu-latest permissions: packages: write steps: - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 with: driver: docker-container install: true - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Login to ghcr.io - uses: docker/login-action@v3 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Create and push manifest for DockerHub + - name: Create and push multi-arch manifests + env: + TAG: ${{ env.RELEASE_TAG }} run: | set -e - docker manifest create ${{ secrets.DOCKER_USERNAME }}/docsgpt-fe:${{ github.event.release.tag_name }} \ - --amend ${{ secrets.DOCKER_USERNAME }}/docsgpt-fe:${{ github.event.release.tag_name }}-amd64 \ - --amend ${{ secrets.DOCKER_USERNAME }}/docsgpt-fe:${{ github.event.release.tag_name }}-arm64 - docker manifest push ${{ secrets.DOCKER_USERNAME }}/docsgpt-fe:${{ github.event.release.tag_name }} - docker manifest create ${{ secrets.DOCKER_USERNAME }}/docsgpt-fe:latest \ - --amend ${{ secrets.DOCKER_USERNAME }}/docsgpt-fe:${{ github.event.release.tag_name }}-amd64 \ - --amend ${{ secrets.DOCKER_USERNAME }}/docsgpt-fe:${{ github.event.release.tag_name }}-arm64 - docker manifest push ${{ secrets.DOCKER_USERNAME }}/docsgpt-fe:latest - - - name: Create and push manifest for ghcr.io - run: | - set -e - docker manifest create ghcr.io/${{ github.repository_owner }}/docsgpt-fe:${{ github.event.release.tag_name }} \ - --amend ghcr.io/${{ github.repository_owner }}/docsgpt-fe:${{ github.event.release.tag_name }}-amd64 \ - --amend ghcr.io/${{ github.repository_owner }}/docsgpt-fe:${{ github.event.release.tag_name }}-arm64 - docker manifest push ghcr.io/${{ github.repository_owner }}/docsgpt-fe:${{ github.event.release.tag_name }} - docker manifest create ghcr.io/${{ github.repository_owner }}/docsgpt-fe:latest \ - --amend ghcr.io/${{ github.repository_owner }}/docsgpt-fe:${{ github.event.release.tag_name }}-amd64 \ - --amend ghcr.io/${{ github.repository_owner }}/docsgpt-fe:${{ github.event.release.tag_name }}-arm64 - docker manifest push ghcr.io/${{ github.repository_owner }}/docsgpt-fe:latest \ No newline at end of file + for repo in "$DOCKERHUB_NAMESPACE/docsgpt-fe" "ghcr.io/${{ github.repository_owner }}/docsgpt-fe"; do + for name in "$TAG" latest; do + docker manifest create "$repo:$name" \ + --amend "$repo:$TAG-amd64" \ + --amend "$repo:$TAG-arm64" + docker manifest push "$repo:$name" + done + done