Build relay/main (8c18aea) #133
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
| # Build and push the chatmail-relay Docker image (ghcr.io/chatmail/docker). | |
| # | |
| # Triggers: | |
| # 1. Push/PR to this repo (Dockerfile changes) -- builds relay@main | |
| # 2. repository_dispatch from chatmail/relay -- builds the dispatched relay ref | |
| # 3. workflow_dispatch -- manual build of any relay branch/tag | |
| # | |
| # Tags: sha-<relay-7char>[distro_suffix], branch name[distro_suffix], semver release tags (Bookworm only) | |
| # PRs: build only, no push | |
| name: Build and push chatmail-relay image | |
| run-name: >- | |
| ${{ github.event_name == 'repository_dispatch' | |
| && format('Build relay/{0} ({1})', | |
| github.event.client_payload.relay_ref, | |
| github.event.client_payload.relay_sha_short) | |
| || github.event_name == 'workflow_dispatch' | |
| && format('Build relay/{0}', | |
| github.event.inputs.relay_ref || 'main') | |
| || format('Build docker/{0}', github.ref_name) }} | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| paths-ignore: | |
| - '**/README.md' | |
| - 'CHANGELOG.md' | |
| - 'LICENSE' | |
| repository_dispatch: | |
| types: [relay-updated] | |
| workflow_dispatch: | |
| inputs: | |
| relay_ref: | |
| description: 'Relay branch or tag to build (default: main)' | |
| default: 'main' | |
| relay_sha: | |
| description: 'Relay commit SHA (leave empty for HEAD of ref)' | |
| default: '' | |
| permissions: {} | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_NAME: chatmail/docker | |
| jobs: | |
| build: | |
| name: Build Docker image (debian ${{ matrix.debian_version }}) | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - debian_version: 12 | |
| distro_suffix: "" | |
| # - debian_version: 13 | |
| # distro_suffix: "-trixie" | |
| outputs: | |
| relay_sha_short: ${{ steps.meta.outputs.relay_sha_short }} | |
| relay_ref: ${{ steps.meta.outputs.relay_ref }} | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - name: Compute relay ref | |
| id: relay | |
| env: | |
| PAYLOAD_REF: ${{ github.event.client_payload.relay_ref }} | |
| PAYLOAD_SHA: ${{ github.event.client_payload.relay_sha }} | |
| INPUT_REF: ${{ github.event.inputs.relay_ref }} | |
| INPUT_SHA: ${{ github.event.inputs.relay_sha }} | |
| run: | | |
| REF="${PAYLOAD_REF:-${INPUT_REF:-main}}" | |
| SHA="${PAYLOAD_SHA:-${INPUT_SHA:-}}" | |
| echo "ref=${REF}" >> "$GITHUB_OUTPUT" | |
| echo "sha=${SHA}" >> "$GITHUB_OUTPUT" | |
| - name: Checkout relay repo as build context | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| repository: chatmail/relay | |
| ref: ${{ steps.relay.outputs.sha || steps.relay.outputs.ref }} | |
| persist-credentials: false | |
| - name: Checkout docker repo | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| path: docker | |
| persist-credentials: false | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4 | |
| - name: Login to GHCR | |
| if: github.event_name != 'pull_request' | |
| uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Compute build metadata | |
| id: meta | |
| env: | |
| RELAY_REF_INPUT: ${{ steps.relay.outputs.ref }} | |
| EVENT_NAME: ${{ github.event_name }} | |
| REF_NAME: ${{ github.ref_name }} | |
| DISTRO_SUFFIX: ${{ matrix.distro_suffix }} | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| IMAGE="${REGISTRY}/${IMAGE_NAME}" | |
| RELAY_REF="${RELAY_REF_INPUT}" | |
| # Relay SHA comes from the relay checkout at workspace root | |
| RELAY_SHA=$(git rev-parse HEAD) | |
| RELAY_SHA_SHORT="${RELAY_SHA:0:7}" | |
| BUILD_DATE=$(git log -1 --format=%cI) | |
| COMMIT_MSG=$(git log -1 --format=%s) | |
| echo "relay_sha=${RELAY_SHA}" >> "$GITHUB_OUTPUT" | |
| echo "relay_sha_short=${RELAY_SHA_SHORT}" >> "$GITHUB_OUTPUT" | |
| echo "relay_ref=${RELAY_REF}" >> "$GITHUB_OUTPUT" | |
| echo "build_date=${BUILD_DATE}" >> "$GITHUB_OUTPUT" | |
| echo "tag=sha-${RELAY_SHA_SHORT}${DISTRO_SUFFIX}" >> "$GITHUB_OUTPUT" | |
| # -- Tags -- | |
| # Always: relay SHA tag (with distro suffix) | |
| TAGS="${IMAGE}:sha-${RELAY_SHA_SHORT}${DISTRO_SUFFIX}" | |
| if [ "$EVENT_NAME" = "push" ] || \ | |
| [ "$EVENT_NAME" = "pull_request" ]; then | |
| # Docker-repo push/PR: add docker branch tag (sanitize slashes) | |
| BRANCH_TAG=$(echo "${REF_NAME}" | sed 's|/|-|g') | |
| TAGS="${TAGS}"$'\n'"${IMAGE}:${BRANCH_TAG}${DISTRO_SUFFIX}" | |
| else | |
| # Dispatch: tags based on relay ref | |
| BRANCH_TAG=$(echo "${RELAY_REF}" | sed 's|/|-|g') | |
| TAGS="${TAGS}"$'\n'"${IMAGE}:${BRANCH_TAG}${DISTRO_SUFFIX}" | |
| if [[ "${RELAY_REF}" =~ ^v?([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then | |
| MAJOR="${BASH_REMATCH[1]}" | |
| MINOR="${BASH_REMATCH[2]}" | |
| PATCH="${BASH_REMATCH[3]}" | |
| VERSION="${MAJOR}.${MINOR}.${PATCH}" | |
| TAGS="${TAGS}"$'\n'"${IMAGE}:${VERSION}${DISTRO_SUFFIX}"$'\n'"${IMAGE}:${MAJOR}.${MINOR}${DISTRO_SUFFIX}" | |
| # `latest` only for Bookworm and only if this is the highest semver published so far, | |
| # so a back-ported patch on an old minor line cannot clobber it. | |
| if [ -z "${DISTRO_SUFFIX}" ]; then | |
| HIGHEST=$(gh api \ | |
| "orgs/chatmail/packages/container/docker/versions?per_page=100" \ | |
| --jq '[.[].metadata.container.tags[] | |
| | select(test("^[0-9]+\\.[0-9]+\\.[0-9]+$"))] | |
| | sort_by(split(".") | map(tonumber)) | last // empty' \ | |
| 2>/dev/null) || true | |
| if [ -z "$HIGHEST" ] || \ | |
| [ "$(printf '%s\n%s\n' "$HIGHEST" "$VERSION" \ | |
| | sort -V | tail -1)" = "$VERSION" ]; then | |
| TAGS="${TAGS}"$'\n'"${IMAGE}:latest" | |
| fi | |
| fi | |
| fi | |
| fi | |
| echo "tags<<EOF" >> "$GITHUB_OUTPUT" | |
| echo "${TAGS}" >> "$GITHUB_OUTPUT" | |
| echo "EOF" >> "$GITHUB_OUTPUT" | |
| # -- Changes: commit list since last image (stored in custom label) -- | |
| BASE_SHA="" | |
| if [ "${RELAY_REF}" = "main" ]; then | |
| BASE_SHA=$(gh api "orgs/chatmail/packages/container/docker/versions?per_page=50" \ | |
| --jq '[.[] | |
| | select(.metadata.container.tags | any(. == "main")) | |
| | .metadata.container.tags[] | select(startswith("sha-")) | |
| | ltrimstr("sha-")] | .[0] // empty' 2>/dev/null) || true | |
| else | |
| BASE_SHA=$(gh api "repos/chatmail/relay/commits/main" --jq '.sha[:7]' 2>/dev/null) || true | |
| fi | |
| CHANGES="" | |
| if [ -n "$BASE_SHA" ] && [ "$BASE_SHA" != "$RELAY_SHA_SHORT" ]; then | |
| CHANGES=$(gh api "repos/chatmail/relay/compare/${BASE_SHA}...${RELAY_SHA}" \ | |
| --jq '.commits[] | .sha[:7] + " " + (.commit.message | split("\n")[0])' 2>/dev/null) || true | |
| fi | |
| if [ -z "$CHANGES" ]; then | |
| CHANGES="${RELAY_SHA_SHORT} ${COMMIT_MSG}" | |
| fi | |
| # Static description for GHCR package page (512 char limit, text-only) | |
| DESC="Chatmail Relay Server" | |
| { | |
| echo "labels<<EOF" | |
| echo "org.opencontainers.image.title=chatmail-relay" | |
| echo "org.opencontainers.image.description=${DESC}" | |
| echo "org.opencontainers.image.revision=${RELAY_SHA}" | |
| echo "org.opencontainers.image.source=https://github.com/chatmail/relay" | |
| echo "org.opencontainers.image.created=${BUILD_DATE}" | |
| echo "com.chatmail.source.ref=${RELAY_REF}" | |
| echo "com.chatmail.changes=${CHANGES}" | |
| echo "EOF" | |
| } >> "$GITHUB_OUTPUT" | |
| # Annotations on the OCI image index so GHCR shows the description. | |
| # "index:" prefix = top-level index object annotations. | |
| # "manifest-descriptor:" = per-entry inside the index (not what GHCR reads). | |
| # No prefix = per-platform image manifest. | |
| { | |
| echo "annotations<<EOF" | |
| echo "index:org.opencontainers.image.title=chatmail-relay" | |
| echo "index:org.opencontainers.image.description=${DESC}" | |
| echo "EOF" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Copy .dockerignore to build context | |
| run: cp docker/.dockerignore .dockerignore | |
| - name: Build and push | |
| uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7 | |
| with: | |
| context: . | |
| file: docker/chatmail_relay.dockerfile | |
| push: ${{ github.event_name != 'pull_request' }} | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| annotations: ${{ steps.meta.outputs.annotations }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| build-args: | | |
| GIT_HASH=${{ steps.meta.outputs.relay_sha }} | |
| SOURCE_REF=${{ steps.meta.outputs.relay_ref }} | |
| BUILD_DATE=${{ steps.meta.outputs.build_date }} | |
| DEBIAN_VERSION=${{ matrix.debian_version }} | |
| test_bookworm: | |
| name: Integration test (bookworm) | |
| needs: build | |
| permissions: {} | |
| # TODO: revert to @main once cmlxc docker support is merged | |
| uses: chatmail/cmlxc/.github/workflows/lxc-test.yml@j4n/docker-support | |
| with: | |
| # TODO: revert to main once cmlxc docker support is merged | |
| cmlxc_version: j4n/docker-support | |
| cmlxc_commands: | | |
| cmlxc init | |
| cmlxc docker deploy dock0 --source ghcr:sha-${{ needs.build.outputs.relay_sha_short }} | |
| RELAY_REF=${{ needs.build.outputs.relay_ref }} cmlxc test-cmdeploy dock0 | |
| # test_trixie: | |
| # name: Integration test (trixie) | |
| # needs: build | |
| # permissions: {} | |
| # # TODO: revert to @main once cmlxc docker support is merged | |
| # uses: chatmail/cmlxc/.github/workflows/lxc-test.yml@j4n/docker-support | |
| # with: | |
| # # TODO: revert to main once cmlxc docker support is merged | |
| # cmlxc_version: j4n/docker-support | |
| # cmlxc_commands: | | |
| # cmlxc init | |
| # cmlxc docker deploy dock0 --source ghcr:sha-${{ needs.build.outputs.relay_sha_short }}-trixie | |
| # RELAY_REF=${{ needs.build.outputs.relay_ref }} cmlxc test-cmdeploy dock0 |