Merge pull request #169 from Wolfvin/fix/issue-163-iterative-walk-kee… #3
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: Docker Build & Publish (GHCR) | |
| # Phase 2 of issue #54 — container image distribution. | |
| # | |
| # Builds two images on every relevant trigger: | |
| # 1. minimal -> ghcr.io/wolfvin/codelens:latest, :v<tag>, :sha-<sha> | |
| # 2. maximal -> ghcr.io/wolfvin/codelens:maximal-latest, :maximal-v<tag> | |
| # | |
| # Both are built multi-arch (linux/amd64 + linux/arm64) via docker buildx + | |
| # QEMU. Images are pushed to GitHub Container Registry (GHCR) using the | |
| # auto-provisioned GITHUB_TOKEN (no extra secret needed). | |
| # | |
| # Triggers: | |
| # - push to main touching Dockerfile / Dockerfile.maximal / .dockerignore / | |
| # the workflow itself -> :latest + :sha-<sha> | |
| # - tag push matching v* (release) -> :v<tag> + :latest | |
| # - workflow_dispatch (manual) -> :latest + :sha-<sha> | |
| # | |
| # The workflow is a no-op on forks (guard at job level) so contributors can | |
| # fork-test without leaking images to the upstream GHCR namespace. | |
| on: | |
| push: | |
| branches: | |
| - main | |
| paths: | |
| - 'Dockerfile' | |
| - 'Dockerfile.maximal' | |
| - '.dockerignore' | |
| - '.github/workflows/docker-publish.yml' | |
| - 'scripts/**' | |
| - 'pyproject.toml' | |
| tags: | |
| - 'v*' | |
| workflow_dispatch: | |
| inputs: | |
| dry_run: | |
| description: 'Build but do not push to GHCR' | |
| required: false | |
| default: 'false' | |
| type: choice | |
| options: ['false', 'true'] | |
| permissions: | |
| contents: read | |
| packages: write # needed to push to GHCR (ghcr.io/wolfvin/*) | |
| jobs: | |
| build-and-push: | |
| name: Build & Push ${{ matrix.variant }} | |
| runs-on: ubuntu-latest | |
| if: github.repository == 'Wolfvin/CodeLens' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - variant: minimal | |
| dockerfile: Dockerfile | |
| image_suffix: '' | |
| tag_latest: latest | |
| - variant: maximal | |
| dockerfile: Dockerfile.maximal | |
| image_suffix: -maximal | |
| tag_latest: maximal-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Set up QEMU (for cross-arch emulation) | |
| uses: docker/setup-qemu-action@v3 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to GHCR | |
| if: github.event_name != 'workflow_dispatch' || inputs.dry_run != 'true' | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Extract metadata for image tags | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ghcr.io/wolfvin/codelens${{ matrix.image_suffix }} | |
| # Produces: | |
| # - On main push: type=sha,prefix=sha-,format=short + type=raw,value=${{ matrix.tag_latest }} | |
| # - On tag v*: type=semver,pattern=v{{version}} + type=semver,pattern=v{{major}}.{{minor}} | |
| # + type=raw,value=${{ matrix.tag_latest }} | |
| tags: | | |
| type=raw,value=${{ matrix.tag_latest }},enable={{is_default_branch}} | |
| type=sha,prefix=sha-,format=short | |
| type=semver,pattern=v{{version}} | |
| type=semver,pattern=v{{major}}.{{minor}} | |
| labels: | | |
| org.opencontainers.image.title=CodeLens (${{ matrix.variant }}) | |
| org.opencontainers.image.source=https://github.com/Wolfvin/CodeLens | |
| org.opencontainers.image.licenses=MIT | |
| - name: Build & push ${{ matrix.variant }} image | |
| id: build | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| file: ${{ matrix.dockerfile }} | |
| platforms: linux/amd64,linux/arm64 | |
| push: ${{ github.event_name != 'workflow_dispatch' || inputs.dry_run != 'true' }} | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha,scope=${{ matrix.variant }} | |
| cache-to: type=gha,mode=max,scope=${{ matrix.variant }} | |
| build-args: | | |
| PYTHON_VERSION=3.11 | |
| # No provenance file for now — Phase 5 (release signing) will add | |
| # SBOM + SLSA via Cosign. Keeping this job focused on image build. | |
| - name: Smoke-test the built image (minimal only, amd64) | |
| # Quick sanity check that the CLI loads and the command registry | |
| # builds. Skipped for maximal (heavier, slower) and for dry-run | |
| # (image not pushed, but buildx can load locally for smoke test). | |
| if: matrix.variant == 'minimal' && github.event_name != 'pull_request' | |
| run: | | |
| # Build a local single-arch copy for smoke testing (does not push). | |
| docker buildx build \ | |
| --platform linux/amd64 \ | |
| --load \ | |
| -t codelens:smoke \ | |
| -f Dockerfile \ | |
| . | |
| echo "--- codelens --command-count ---" | |
| docker run --rm codelens:smoke --command-count | |
| echo "--- codelens --help (first 20 lines) ---" | |
| docker run --rm codelens:smoke --help 2>&1 | head -20 | |
| - name: Job summary | |
| if: always() | |
| run: | | |
| echo "## Docker Build Summary — ${{ matrix.variant }}" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY | |
| echo "|---|---|" >> $GITHUB_STEP_SUMMARY | |
| echo "| Variant | \`${{ matrix.variant }}\` |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Dockerfile | \`${{ matrix.dockerfile }}\` |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Platforms | linux/amd64, linux/arm64 |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Image | \`ghcr.io/wolfvin/codelens${{ matrix.image_suffix }}\` |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Tags | \`${{ steps.meta.outputs.tags }}\` |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Pushed | ${{ steps.build.outputs.pushed }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Digest | \`${{ steps.build.outputs.digest }}\` |" >> $GITHUB_STEP_SUMMARY |