# Build and publish per-channel container images to GHCR. # # WHY this exists: pilot dev workstations sit behind an inspecting proxy # (Zscaler) that resets npm's many small fetches mid-install, so building the # image FROM SOURCE on a pilot box is unreliable. These runners # (arc-runner-set) install npm cleanly - the CI `frontend` job already proves # it - so we build the image ONCE here and pilots pull the finished image. # A single image pull is one resumable HTTPS stream, far more robust through # the proxy than hundreds of npm requests. # # Channels are mapped to how THIS repo actually ships, which is not how the # branch this came from ships. Upstream, main is a release branch and dev-be is # the trunk. Here main IS the trunk - it runs hundreds of commits past the last # release - and releases are tags (ADR-007). Publishing main as :stable would # put unreleased work behind a word that promises the opposite, to sites that # have no way to know: # # tag v* -> ghcr.io//shopdb-flask:stable (badge off) the release # main -> ghcr.io//shopdb-flask:edge (DEV badge) the trunk # # The image also carries a short-SHA tag for traceability and rollback. # # Automatic publishing is OFF until someone confirms the GHCR package exists # under this owner and decides who may pull it. Re-enable by uncommenting the # push: block below; workflow_dispatch works meanwhile. name: publish-images on: # push: # tags: # - 'v*' # branches: # - main # Manual rebuild/publish of the current ref's channel image. workflow_dispatch: # One in-flight publish per branch; a newer push supersedes an older one. concurrency: group: publish-images-${{ github.ref }} cancel-in-progress: true jobs: build-and-push: runs-on: arc-runner-set permissions: contents: read packages: write steps: - uses: actions/checkout@v5 # Lowercase the owner: GHCR repository paths must be lowercase, but # github.repository_owner can carry uppercase (e.g. ge-aero is fine, but # this keeps the workflow correct for any owner casing). - name: Resolve image name and channel tag id: meta run: | owner="$(echo '${{ github.repository_owner }}' | tr '[:upper:]' '[:lower:]')" image="ghcr.io/${owner}/shopdb-flask" # A tag is a release, anything else is the trunk. Deliberately not # keyed on the branch name: a release here is a tag, so keying on # "main" would label the trunk stable. if [ "${{ github.ref_type }}" = "tag" ]; then channel="stable" else channel="edge" fi echo "image=${image}" >> "$GITHUB_OUTPUT" echo "channel=${channel}" >> "$GITHUB_OUTPUT" echo "sha=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT" - name: Log in to GHCR uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Set up Buildx uses: docker/setup-buildx-action@v3 - name: Build and push channel image uses: docker/build-push-action@v6 with: context: . push: true tags: | ${{ steps.meta.outputs.image }}:${{ steps.meta.outputs.channel }} ${{ steps.meta.outputs.image }}:${{ steps.meta.outputs.channel }}-${{ steps.meta.outputs.sha }} # Reuse the channel tag as a cache source/target so subsequent builds # only redo layers that actually changed. cache-from: type=registry,ref=${{ steps.meta.outputs.image }}:${{ steps.meta.outputs.channel }} cache-to: type=inline