aboutsummaryrefslogtreecommitdiff
path: root/.github/workflows/multi-arch-build.yaml
blob: 1dc485d71795b5da93fd74475521bec40fe543c6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
---

# Please see contrib/<reponame>image/README.md for details on the intentions
# of this workflow.
#
# BIG FAT WARNING:  This workflow is duplicated across containers/skopeo,
#                   containers/buildah, and containers/podman.  ANY AND
#                   ALL CHANGES MADE HERE MUST BE MANUALLY DUPLICATED
#                   TO THE OTHER REPOS.

name: build multi-arch images

on:
  # Upstream tends to be very active, with many merges per day.
  # Only run this daily via cron schedule, or manually, not by branch push.
  schedule:
    - cron:  '0 8 * * *'
  # allows to run this workflow manually from the Actions tab
  workflow_dispatch:

permissions:
  contents: read

jobs:
  multi:
    name: multi-arch image build
    env:
      REPONAME: podman # No easy way to parse this out of $GITHUB_REPOSITORY
      # Server/namespace value used to format FQIN
      REPONAME_QUAY_REGISTRY: quay.io/podman
      CONTAINERS_QUAY_REGISTRY: quay.io/containers
      # list of architectures for build
      PLATFORMS: linux/amd64,linux/s390x,linux/ppc64le,linux/arm64
      # Command to execute in container to obtain project version number
      VERSION_CMD: "podman --version"

    # build several images (upstream, testing, stable) in parallel
    strategy:
      # By default, failure of one matrix item cancels all others
      fail-fast: false
      matrix:
        # Builds are located under contrib/<reponame>image/<source> directory
        source:
          - upstream
          - testing
          - stable
    runs-on: ubuntu-latest
    # internal registry caches build for inspection before push
    services:
      registry:
        image: quay.io/libpod/registry:2
        ports:
          - 5000:5000
    steps:
      - name: Checkout
        uses: actions/checkout@629c2de402a417ea7690ca6ce3f33229e27606a5 # v2

      - name: Set up QEMU
        uses: docker/setup-qemu-action@27d0a4f181a40b142cce983c5393082c365d1480 # v1

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@94ab11c41e45d028884a99163086648e898eed25 # v1
        with:
          driver-opts: network=host
          install: true

      - name: Build and locally push image
        uses: docker/build-push-action@ac9327eae2b366085ac7f6a2d02df8aa8ead720a # v2
        with:
          context: contrib/${{ env.REPONAME }}image/${{ matrix.source }}
          file: ./contrib/${{ env.REPONAME }}image/${{ matrix.source }}/Dockerfile
          platforms: ${{ env.PLATFORMS }}
          push: true
          tags: localhost:5000/${{ env.REPONAME }}/${{ matrix.source }}

      # Simple verification that stable images work, and
      # also grab version number use in forming the FQIN.
      - name: amd64 container sniff test
        if: matrix.source == 'stable'
        id: sniff_test
        run: |
          podman pull --tls-verify=false \
                            localhost:5000/$REPONAME/${{ matrix.source }}
          VERSION_OUTPUT=$(podman run \
                           localhost:5000/$REPONAME/${{ matrix.source }} \
                           $VERSION_CMD)
          echo "$VERSION_OUTPUT"
          VERSION=$(awk -r -e "/^${REPONAME} version /"'{print $3}' <<<"$VERSION_OUTPUT")
          test -n "$VERSION"
          echo "::set-output name=version::$VERSION"

      - name: Generate image FQIN(s) to push
        id: reponame_reg
        run: |
          if [[ "${{ matrix.source }}" == 'stable' ]]; then
            # The command version in image just built
            VERSION='v${{ steps.sniff_test.outputs.version }}'
            # workaround vim syntax-highlight bug: '
            # Push both new|updated version-tag and latest-tag FQINs
            FQIN="$REPONAME_QUAY_REGISTRY/stable:$VERSION,$REPONAME_QUAY_REGISTRY/stable:latest"
          elif [[ "${{ matrix.source }}" == 'testing' ]]; then
            # Assume some contents changed, always push latest testing.
            FQIN="$REPONAME_QUAY_REGISTRY/testing:latest"
          elif [[ "${{ matrix.source }}" == 'upstream' ]]; then
            # Assume some contents changed, always push latest upstream.
            FQIN="$REPONAME_QUAY_REGISTRY/upstream:latest"
          else
            echo "::error::Unknown matrix item '${{ matrix.source }}'"
            exit 1
          fi
          echo "::warning::Pushing $FQIN"
          echo "::set-output name=fqin::${FQIN}"
          echo '::set-output name=push::true'

      # This is substantially similar to the above logic,
      # but only handles $CONTAINERS_QUAY_REGISTRY for
      # the stable "latest" and named-version tagged images.
      - name: Generate containers reg. image FQIN(s)
        if: matrix.source == 'stable'
        id: containers_reg
        run: |
          VERSION='v${{ steps.sniff_test.outputs.version }}'
          # workaround vim syntax-highlight bug: '
          # Push both new|updated version-tag and latest-tag FQINs
          FQIN="$CONTAINERS_QUAY_REGISTRY/$REPONAME:$VERSION,$CONTAINERS_QUAY_REGISTRY/$REPONAME:latest"
          echo "::warning::Pushing $FQIN"
          echo "::set-output name=fqin::${FQIN}"
          echo '::set-output name=push::true'

      - name: Define LABELS multi-line env. var. value
        run: |
          # This is a really hacky/strange workflow idiom, required
          # for setting multi-line $LABELS value for consumption in
          # a future step.  There is literally no cleaner way to do this :<
          # https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#multiline-strings
          function set_labels() {
            echo 'LABELS<<DELIMITER' >> "$GITHUB_ENV"
            for line; do
                echo "$line" | tee -a "$GITHUB_ENV"
            done
            echo "DELIMITER" >> "$GITHUB_ENV"
          }

          declare -a lines
          lines=(\
            "org.opencontainers.image.source=https://github.com/${GITHUB_REPOSITORY}.git"
            "org.opencontainers.image.revision=${GITHUB_SHA}"
            "org.opencontainers.image.created=$(date -u --iso-8601=seconds)"
          )

          # Only the 'stable' matrix source obtains $VERSION
          if [[ "${{ matrix.source }}" == "stable" ]]; then
            lines+=(\
              "org.opencontainers.image.version=${{ steps.sniff_test.outputs.version }}"
            )
          fi

          set_labels "${lines[@]}"

      # Separate steps to login and push for $REPONAME_QUAY_REGISTRY and
      # $CONTAINERS_QUAY_REGISTRY are required, because 2 sets of credentials
      # are used and namespaced within the registry.  At the same time, reuse
      # of non-shell steps is not supported by Github Actions nor are YAML
      # anchors/aliases, nor composite actions.

      # Push to $REPONAME_QUAY_REGISTRY for stable, testing. and upstream
      - name: Login to ${{ env.REPONAME_QUAY_REGISTRY }}
        uses: docker/login-action@dd4fa0671be5250ee6f50aedf4cb05514abda2c7 # v1
        if: steps.reponame_reg.outputs.push == 'true'
        with:
          registry: ${{ env.REPONAME_QUAY_REGISTRY }}
          # N/B: Secrets are not passed to workflows that are triggered
          #      by a pull request from a fork
          username: ${{ secrets.REPONAME_QUAY_USERNAME }}
          password: ${{ secrets.REPONAME_QUAY_PASSWORD }}

      - name: Push images to ${{ steps.reponame_reg.outputs.fqin }}
        uses: docker/build-push-action@ac9327eae2b366085ac7f6a2d02df8aa8ead720a # v2
        if: steps.reponame_reg.outputs.push == 'true'
        with:
          cache-from: type=registry,ref=localhost:5000/${{ env.REPONAME }}/${{ matrix.source }}
          cache-to: type=inline
          context: contrib/${{ env.REPONAME }}image/${{ matrix.source }}
          file: ./contrib/${{ env.REPONAME }}image/${{ matrix.source }}/Dockerfile
          platforms: ${{ env.PLATFORMS }}
          push: true
          tags: ${{ steps.reponame_reg.outputs.fqin }}
          labels: |
            ${{ env.LABELS }}

      # Push to $CONTAINERS_QUAY_REGISTRY only stable
      - name: Login to ${{ env.CONTAINERS_QUAY_REGISTRY }}
        if: steps.containers_reg.outputs.push == 'true'
        uses: docker/login-action@dd4fa0671be5250ee6f50aedf4cb05514abda2c7 # v1
        with:
          registry: ${{ env.CONTAINERS_QUAY_REGISTRY}}
          username: ${{ secrets.CONTAINERS_QUAY_USERNAME }}
          password: ${{ secrets.CONTAINERS_QUAY_PASSWORD }}

      - name: Push images to ${{ steps.containers_reg.outputs.fqin }}
        if: steps.containers_reg.outputs.push == 'true'
        uses: docker/build-push-action@ac9327eae2b366085ac7f6a2d02df8aa8ead720a # v2
        with:
          cache-from: type=registry,ref=localhost:5000/${{ env.REPONAME }}/${{ matrix.source }}
          cache-to: type=inline
          context: contrib/${{ env.REPONAME }}image/${{ matrix.source }}
          file: ./contrib/${{ env.REPONAME }}image/${{ matrix.source }}/Dockerfile
          platforms: ${{ env.PLATFORMS }}
          push: true
          tags: ${{ steps.containers_reg.outputs.fqin }}
          labels: |
            ${{ env.LABELS }}