.github/workflows/docker.yml 5.5 K raw
1
name: Docker
2
3
on:
4
  push:
5
    branches:
6
      - main
7
    tags:
8
      - '**[0-9]+.[0-9]+.[0-9]+*'
9
10
env:
11
  REGISTRY: ghcr.io
12
13
jobs:
14
  changes:
15
    name: Detect changes
16
    runs-on: ubuntu-latest
17
    outputs:
18
      apps: ${{ steps.filter.outputs.apps }}
19
      version: ${{ steps.filter.outputs.version }}
20
    steps:
21
      - uses: actions/checkout@v4
22
        with:
23
          fetch-depth: 2
24
25
      - name: Determine which apps to build
26
        id: filter
27
        run: |
28
          ALL='["backup","blobs","bookmarks","cellar","easel","feeds","jotts","kepler","library","og","posts","shrink","sipp"]'
29
30
          # Tags: per-app (app/version) or bare (version)
31
          if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
32
            TAG="${GITHUB_REF#refs/tags/}"
33
34
            if [[ "$TAG" == */* ]]; then
35
              APP="${TAG%/*}"
36
              VERSION="${TAG##*/}"
37
              echo "apps=[\"${APP}\"]" >> "$GITHUB_OUTPUT"
38
              echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
39
            else
40
              echo "apps=${ALL}" >> "$GITHUB_OUTPUT"
41
              echo "version=${TAG}" >> "$GITHUB_OUTPUT"
42
            fi
43
            exit 0
44
          fi
45
46
          changed=$(git diff --name-only HEAD~1 HEAD)
47
48
          # Workspace-level changes (shared deps, CI) rebuild all
49
          if echo "$changed" | grep -qE '^(pkg/|\.github/workflows/docker\.yml)'; then
50
            echo "apps=${ALL}" >> "$GITHUB_OUTPUT"
51
            exit 0
52
          fi
53
54
          apps=()
55
          for app in backup blobs bookmarks cellar easel feeds jotts kepler library og posts shrink sipp; do
56
            if echo "$changed" | grep -q "^apps/${app}/"; then
57
              apps+=("\"${app}\"")
58
            fi
59
          done
60
61
          if [ ${#apps[@]} -eq 0 ]; then
62
            echo 'apps=[]' >> "$GITHUB_OUTPUT"
63
          else
64
            echo "apps=[$(IFS=,; echo "${apps[*]}")]" >> "$GITHUB_OUTPUT"
65
          fi
66
67
  build:
68
    name: build (${{ matrix.app }}/${{ matrix.platform.arch }})
69
    needs: changes
70
    if: needs.changes.outputs.apps != '[]'
71
    runs-on: ${{ matrix.platform.runner }}
72
    permissions:
73
      contents: read
74
      packages: write
75
    strategy:
76
      fail-fast: false
77
      matrix:
78
        app: ${{ fromJson(needs.changes.outputs.apps) }}
79
        platform:
80
          - arch: amd64
81
            runner: ubuntu-latest
82
          - arch: arm64
83
            runner: ubuntu-24.04-arm
84
    steps:
85
      - uses: actions/checkout@v4
86
87
      - name: Set up Docker Buildx
88
        uses: docker/setup-buildx-action@v3
89
90
      - name: Log in to GHCR
91
        uses: docker/login-action@v3
92
        with:
93
          registry: ${{ env.REGISTRY }}
94
          username: ${{ github.actor }}
95
          password: ${{ secrets.GITHUB_TOKEN }}
96
97
      - name: Extract metadata
98
        id: meta
99
        uses: docker/metadata-action@v5
100
        with:
101
          images: ${{ env.REGISTRY }}/${{ github.repository }}/${{ matrix.app }}
102
103
      - name: Build and push by digest
104
        id: build
105
        uses: docker/build-push-action@v6
106
        with:
107
          context: .
108
          file: apps/${{ matrix.app }}/Dockerfile
109
          platforms: linux/${{ matrix.platform.arch }}
110
          labels: ${{ steps.meta.outputs.labels }}
111
          cache-from: type=gha,scope=${{ matrix.app }}-${{ matrix.platform.arch }}
112
          cache-to: type=gha,mode=max,scope=${{ matrix.app }}-${{ matrix.platform.arch }}
113
          outputs: type=image,name=${{ env.REGISTRY }}/${{ github.repository }}/${{ matrix.app }},push-by-digest=true,name-canonical=true,push=true
114
115
      - name: Export digest
116
        run: |
117
          mkdir -p /tmp/digests
118
          digest="${{ steps.build.outputs.digest }}"
119
          touch "/tmp/digests/${digest#sha256:}"
120
121
      - name: Upload digest
122
        uses: actions/upload-artifact@v4
123
        with:
124
          name: digests-${{ matrix.app }}-${{ matrix.platform.arch }}
125
          path: /tmp/digests/*
126
          if-no-files-found: error
127
          retention-days: 1
128
129
  merge:
130
    name: merge (${{ matrix.app }})
131
    needs: [changes, build]
132
    if: needs.changes.outputs.apps != '[]'
133
    runs-on: ubuntu-latest
134
    permissions:
135
      contents: read
136
      packages: write
137
    strategy:
138
      fail-fast: false
139
      matrix:
140
        app: ${{ fromJson(needs.changes.outputs.apps) }}
141
    steps:
142
      - name: Download digests
143
        uses: actions/download-artifact@v4
144
        with:
145
          path: /tmp/digests
146
          pattern: digests-${{ matrix.app }}-*
147
          merge-multiple: true
148
149
      - name: Set up Docker Buildx
150
        uses: docker/setup-buildx-action@v3
151
152
      - name: Log in to GHCR
153
        uses: docker/login-action@v3
154
        with:
155
          registry: ${{ env.REGISTRY }}
156
          username: ${{ github.actor }}
157
          password: ${{ secrets.GITHUB_TOKEN }}
158
159
      - name: Extract metadata
160
        id: meta
161
        uses: docker/metadata-action@v5
162
        with:
163
          images: ${{ env.REGISTRY }}/${{ github.repository }}/${{ matrix.app }}
164
          tags: |
165
            type=raw,value=${{ needs.changes.outputs.version }},enable=${{ needs.changes.outputs.version != '' }}
166
            type=raw,value=latest,enable={{is_default_branch}}
167
168
      - name: Create manifest list and push
169
        working-directory: /tmp/digests
170
        run: |
171
          docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
172
            $(printf '${{ env.REGISTRY }}/${{ github.repository }}/${{ matrix.app }}@sha256:%s ' *)
173
174
      - name: Inspect image
175
        run: |
176
          docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ github.repository }}/${{ matrix.app }}:${{ needs.changes.outputs.version != '' && needs.changes.outputs.version || 'latest' }}