diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index 76107876..5615f851 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -1,141 +1,115 @@ -name: Docker Test & Publish +name: Docker on: push: - # branches: - # - "main" - tags: - - "*" - paths-ignore: - - ".github/**" - - "!.github/workflows/docker.yml" - - ".vscode/**" - - "doc/**" - - ".gitignore" - - "LICENSE" - - "README" + branches: + - "handmade" pull_request: branches: - - "main" - paths: - - "Dockerfile" - workflow_dispatch: + - "handmade" + release: + types: + - published permissions: - contents: read - packages: write + contents: read jobs: - base: - runs-on: ubuntu-latest - name: Build base image - steps: - # Configure build environment - - name: Checkout - uses: actions/checkout@v3 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + # Builds the shared base image: the whole Rust workspace compiled once. + # Every service image (currently only pushd) is derived from this so the + # workspace is built a single time per release. On non-release events this + # still runs as a compile check, but nothing is pushed. + base: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Resolve registry host and owner + id: registry + # Owner is lowercased: Docker repository names must be lowercase. + run: | + echo "host=${GITHUB_SERVER_URL#*://}" >> "$GITHUB_OUTPUT" + echo "owner=$(echo "$GITHUB_REPOSITORY_OWNER" | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_OUTPUT" + - name: Base image ref + id: base + run: echo "image=${{ steps.registry.outputs.host }}/${{ steps.registry.outputs.owner }}/handmade-revolt-base" >> "$GITHUB_OUTPUT" + - name: Login to registry + uses: docker/login-action@v3 + if: github.event_name == 'release' + with: + registry: ${{ steps.registry.outputs.host }} + username: ${{ secrets.PACKAGE_PUBLISH_USERNAME }} + password: ${{ secrets.PACKAGE_PUBLISH_TOKEN }} + - name: Build base image + uses: docker/build-push-action@v6 + with: + context: . + file: Dockerfile + push: ${{ github.event_name == 'release' }} + platforms: linux/amd64 + # Pinned to the commit so the publish job below consumes this + # exact base. + tags: | + ${{ steps.base.outputs.image }}:latest + ${{ steps.base.outputs.image }}:${{ github.sha }} - # Authenticate with GHCR - - name: Login to Github Container Registry - if: ${{ github.event_name != 'pull_request' }} - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build base image - uses: docker/build-push-action@v4 - with: - context: . - push: ${{ github.event_name != 'pull_request' }} - platforms: linux/amd64,linux/arm64 - tags: ghcr.io/${{ github.repository_owner }}/base:latest - cache-from: type=gha,scope=buildx-base-multi-arch - cache-to: type=gha,scope=buildx-base-multi-arch,mode=max - - publish: - needs: [base] - runs-on: ubuntu-latest - if: github.event_name != 'pull_request' - strategy: - matrix: - project: [delta, bonfire, autumn, january, pushd] - name: Build ${{ matrix.project }} image - steps: - # Configure build environment - - name: Checkout - uses: actions/checkout@v3 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - # Authenticate with Docker Hub and GHCR - - name: Login to DockerHub - uses: docker/login-action@v2 - with: - registry: docker.io - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Login to Github Container Registry - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - # Resolve the correct project - - uses: kanga333/variable-mapper@master - id: export - with: - key: "${{ matrix.project }}" - map: | - { - "delta": { - "path": "crates/delta", - "tag": "${{ github.repository_owner }}/server" - }, - "bonfire": { - "path": "crates/bonfire", - "tag": "${{ github.repository_owner }}/bonfire" - }, - "autumn": { - "path": "crates/services/autumn", - "tag": "${{ github.repository_owner }}/autumn" - }, - "january": { - "path": "crates/services/january", - "tag": "${{ github.repository_owner }}/january" - }, - "pushd": { - "path": "crates/daemons/pushd", - "tag": "${{ github.repository_owner }}/pushd" - }, - "crond": { - "path": "crates/daemons/crond", - "tag": "${{ github.repository_owner }}/crond" - } - } - export_to: output - - # Configure metadata - - name: Docker meta - id: meta - uses: docker/metadata-action@v4 - with: - images: | - docker.io/${{ steps.export.outputs.tag }} - ghcr.io/${{ steps.export.outputs.tag }} - - # Build crate image - - name: Publish - uses: docker/build-push-action@v4 - with: - context: . - push: true - platforms: linux/amd64,linux/arm64 - file: ${{ steps.export.outputs.path }}/Dockerfile - tags: ${{ steps.meta.outputs.tags }} - build-args: | - BASE_IMAGE=ghcr.io/${{ github.repository_owner }}/base:latest - labels: ${{ steps.meta.outputs.labels }} + # Builds individual service images from the base. Only runs on release. + publish: + needs: [base] + runs-on: ubuntu-latest + if: github.event_name == 'release' + strategy: + matrix: + # Only pushd is built. To add more services later, add + # entries here (paths/images mirror the upstream revolt layout): + # - { project: delta, path: crates/delta, image: handmade-revolt-server } + # - { project: bonfire, path: crates/bonfire, image: handmade-revolt-bonfire } + # - { project: autumn, path: crates/services/autumn, image: handmade-revolt-autumn } + # - { project: january, path: crates/services/january, image: handmade-revolt-january } + # - { project: crond, path: crates/daemons/crond, image: handmade-revolt-crond } + include: + - { project: pushd, path: crates/daemons/pushd, image: handmade-revolt-pushd } + name: Build ${{ matrix.project }} image + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Resolve registry host and owner + id: registry + # Owner is lowercased: Docker repository names must be lowercase, + # but the org (e.g. HMC) may be uppercase. + run: | + echo "host=${GITHUB_SERVER_URL#*://}" >> "$GITHUB_OUTPUT" + echo "owner=$(echo "$GITHUB_REPOSITORY_OWNER" | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_OUTPUT" + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ steps.registry.outputs.host }}/${{ steps.registry.outputs.owner }}/${{ matrix.image }} + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=raw,value=latest + env: + DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index + - name: Login to registry + uses: docker/login-action@v3 + with: + registry: ${{ steps.registry.outputs.host }} + username: ${{ secrets.PACKAGE_PUBLISH_USERNAME }} + password: ${{ secrets.PACKAGE_PUBLISH_TOKEN }} + - name: Build and publish + uses: docker/build-push-action@v6 + with: + context: . + file: ${{ matrix.path }}/Dockerfile + push: true + platforms: linux/amd64 + build-args: | + BASE_IMAGE=${{ steps.registry.outputs.host }}/${{ steps.registry.outputs.owner }}/handmade-revolt-base:${{ github.sha }} + tags: ${{ steps.meta.outputs.tags }} + annotations: ${{ steps.meta.outputs.annotations }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/crates/daemons/pushd/Dockerfile b/crates/daemons/pushd/Dockerfile index 8123002a..4c7122c8 100644 --- a/crates/daemons/pushd/Dockerfile +++ b/crates/daemons/pushd/Dockerfile @@ -1,5 +1,8 @@ # Build Stage -FROM ghcr.io/revoltchat/base:latest AS builder +# BASE_IMAGE is the compiled workspace base image. Defaults to the upstream +# revolt base, but CI overrides it with our own base built from repo. +ARG BASE_IMAGE=ghcr.io/revoltchat/base:latest +FROM ${BASE_IMAGE} AS builder FROM debian:12 AS debian # Bundle Stage