Skip to content

Merge pull request #169 from Wolfvin/fix/issue-163-iterative-walk-kee… #3

Merge pull request #169 from Wolfvin/fix/issue-163-iterative-walk-kee…

Merge pull request #169 from Wolfvin/fix/issue-163-iterative-walk-kee… #3

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