@@ -13,114 +13,200 @@ on:
1313 # GITHUB_REF: Branch or tag that received dispatch
1414 workflow_dispatch : {}
1515
16+ permissions :
17+ contents : read
18+ packages : write
19+
1620env :
1721 # Only to avoid some repetition
1822 FLAKE_REF : github:${{ github.repository }}/${{ github.ref_name }}
1923 GH_TOKEN : ${{ github.token }}
20- # We need to tell skopeo where to write the authentication token
21- REGISTRY_AUTH_FILE : ./skopeo-registry-auth-file.json
2224
2325jobs :
2426 wait-for-hydra :
2527 name : " Wait for hydra check-runs"
2628 runs-on : ubuntu-latest
29+
2730 steps :
28- - name : Waiting for ci/hydra-build:required to complete
29- run : |
30- while [[ true ]]; do
31- check_name='ci/hydra-build:required'
32- conclusion=$(gh api "repos/$GITHUB_REPOSITORY/commits/$GITHUB_SHA/check-runs?check_name=$check_name" --paginate --jq '.check_runs[].conclusion')
33- case "$conclusion" in
34- success)
35- echo "$check_name succeeded"
36- exit 0;;
37- '')
38- echo "$check_name pending. Waiting 30s..."
39- sleep 30;;
40- *)
41- echo "$check_name terminated unsuccessfully"
42- exit 1;;
43- esac
44- done
31+ - name : Waiting for ci/hydra-build:required to complete
32+ run : |
33+ while [[ true ]]; do
34+ check_name='ci/hydra-build:required'
35+ conclusion=$(gh api "repos/$GITHUB_REPOSITORY/commits/$GITHUB_SHA/check-runs?check_name=$check_name" --paginate --jq '.check_runs[].conclusion')
36+ case "$conclusion" in
37+ success)
38+ echo "$check_name succeeded"
39+ exit 0;;
40+ '')
41+ echo "$check_name pending. Waiting 30s..."
42+ sleep 30;;
43+ *)
44+ echo "$check_name terminated unsuccessfully"
45+ exit 1;;
46+ esac
47+ done
48+
49+
50+ prepare :
51+ needs : [wait-for-hydra]
52+ name : " Prepare metadata"
53+ runs-on : ubuntu-latest
54+ outputs :
55+ LATEST_TAG : ${{ steps.latest-tag.outputs.LATEST_TAG }}
56+ LOCKED_URL : ${{ steps.flake-metadata.outputs.LOCKED_URL }}
57+
58+ steps :
59+ - name : Install Nix
60+ uses : cachix/install-nix-action@v31
61+
62+ - name : Display flake metadata
63+ id : flake-metadata
64+ run : |
65+ nix flake metadata ${{ env.FLAKE_REF }}
66+ nix flake metadata ${{ env.FLAKE_REF }} --json | jq -r '"LOCKED_URL=\(.url)"' >> "$GITHUB_OUTPUT"
67+
68+ - name : Obtaining latest release tag
69+ id : latest-tag
70+ run : |
71+ LATEST_TAG=$(gh api repos/$GITHUB_REPOSITORY/releases/latest --paginate --jq '.tag_name')
72+ echo "LATEST_TAG=$LATEST_TAG" >> "$GITHUB_OUTPUT"
73+ echo "Latest release tag is: $LATEST_TAG"
74+
4575
4676 build :
47- needs : [wait-for-hydra ]
77+ needs : [prepare ]
4878 name : " Upload to ghcr.io"
4979 runs-on : ubuntu-latest
80+ strategy :
81+ matrix :
82+ arch :
83+ - name : amd64
84+ system : x86_64-linux
85+ - name : arm64
86+ system : aarch64-linux
87+ image :
88+ - name : cardano-node
89+ nix_key : dockerImage/node
90+ - name : cardano-submit-api
91+ nix_key : dockerImage/submit-api
92+ - name : cardano-tracer
93+ nix_key : dockerImage/tracer
94+
95+ steps :
96+ - name : Install Nix
97+ uses : cachix/install-nix-action@v31
98+
99+ - name : Log in to GitHub Container Registry
100+ uses : docker/login-action@v3
101+ with :
102+ registry : ghcr.io
103+ username : ${{ github.actor }}
104+ password : ${{ secrets.GITHUB_TOKEN }}
105+
106+ # NOTE We assume that hydra has already built the image, this is
107+ # reasonable since, before applying the tag, we must have already
108+ # pushed the tagged commit somewhere, and Hydra will have had the
109+ # change to build the image.
110+
111+ - name : Uploading ${{ matrix.image.name }} (${{ matrix.arch.name }})
112+ run : |
113+ echo "::group::Downloading from cache"
114+ nix build \
115+ --accept-flake-config \
116+ --print-out-paths \
117+ --builders "" \
118+ --max-jobs 0 \
119+ --out-link ./result-${{ matrix.image.name }}-${{ matrix.arch.name }} \
120+ ${{ needs.prepare.outputs.LOCKED_URL }}#packages.${{ matrix.arch.system }}.${{ matrix.image.nix_key }}
121+ echo "::endgroup::"
122+
123+ echo "::group::Uploading to registry"
124+ skopeo copy \
125+ docker-archive:./result-${{ matrix.image.name }}-${{ matrix.arch.name }} \
126+ docker://ghcr.io/intersectmbo/${{ matrix.image.name }}:$GITHUB_REF_NAME-${{ matrix.arch.name }}
127+ echo "::endgroup::"
128+
129+
130+ create-manifest :
131+ needs : [prepare, build]
132+ name : " Create Multi-Arch Manifest"
133+ runs-on : ubuntu-latest
134+
50135 steps :
51- - name : Install Nix
52- uses : input-output-hk/install-nix-action@v20
53-
54- - name : Display flake metadata
55- id : flake-metadata
56- run : |
57- nix flake metadata ${{ env.FLAKE_REF }}
58- nix flake metadata ${{ env.FLAKE_REF }} --json | jq -r '"LOCKED_URL=\(.url)"' >> "$GITHUB_OUTPUT"
59-
60- - name : Login to GitHub Container Registry
61- run : skopeo login --username ${{ github.actor }} --password ${{ secrets.GITHUB_TOKEN }} ghcr.io
62-
63- # NOTE We assume that hydra has already built the image, this is
64- # reasonable since, before applying the tag, we must have already
65- # pushed the tagged commit somewhere, and Hydra will have had the
66- # change to build the image.
67-
68- - name : Uploading intersectmbo/cardano-node
69- run : |
70- echo "::group::Downloading from cache"
71- nix build --accept-flake-config --print-out-paths --builders "" --max-jobs 0 --out-link ./result-node ${{ steps.flake-metadata.outputs.LOCKED_URL }}#dockerImage/node
72- echo "::endgroup::"
73-
74- echo "::group::Uploading to registry"
75- skopeo copy docker-archive:./result-node docker://ghcr.io/intersectmbo/cardano-node:$GITHUB_REF_NAME
76- echo "::endgroup::"
77-
78- - name : Uploading intersectmbo/cardano-submit-api
79- run : |
80- echo "::group::Downloading from cache"
81- nix build --accept-flake-config --print-out-paths --builders "" --max-jobs 0 --out-link ./result-api ${{ steps.flake-metadata.outputs.LOCKED_URL }}#dockerImage/submit-api
82- echo "::endgroup::"
83-
84- echo "::group::Uploading to registry"
85- skopeo copy docker-archive:./result-api docker://ghcr.io/intersectmbo/cardano-submit-api:$GITHUB_REF_NAME
86- echo "::endgroup::"
87-
88- - name : Uploading intersectmbo/cardano-tracer
89- run : |
90- echo "::group::Downloading from cache"
91- nix build --accept-flake-config --print-out-paths --builders "" --max-jobs 0 --out-link ./result-tracer ${{ steps.flake-metadata.outputs.LOCKED_URL }}#dockerImage/tracer
92- echo "::endgroup::"
93-
94- echo "::group::Uploading to registry"
95- skopeo copy docker-archive:./result-tracer docker://ghcr.io/intersectmbo/cardano-tracer:$GITHUB_REF_NAME
96- echo "::endgroup::"
97-
98- - name : Obtaining latest release tag
99- id : latest-tag
100- run : |
101- LATEST_TAG=$(gh api repos/$GITHUB_REPOSITORY/releases/latest --paginate --jq '.tag_name')
102- echo "LATEST_TAG=$LATEST_TAG" >> "$GITHUB_OUTPUT"
103- echo "Latest release tag is: $LATEST_TAG"
104-
105- - name : Tagging intersectmbo container latest
106- # Github releases are checked for latest tag in the first `or` operand of
107- # the if statement. However, promoted pre-releases or changed full
108- # releases do not count as a `published` event and so won't trigger
109- # this workflow. For those use cases a manual workflow must be run
110- # from the matching release tag which the second `or` operand checks
111- # for.
112- if : |
113- (github.event_name == 'release' && github.event.release.tag_name == steps.latest-tag.outputs.LATEST_TAG) ||
114- (github.event_name == 'workflow_dispatch' && github.ref == format('refs/tags/{0}', steps.latest-tag.outputs.LATEST_TAG))
115- run : |
116- echo "::group::Tagging latest for intersectmbo/cardano-node"
117- skopeo copy docker-archive:./result-node docker://ghcr.io/intersectmbo/cardano-node:latest
118- echo "::endgroup::"
119-
120- echo "::group::Tagging latest for intersectmbo/cardano-submit-api"
121- skopeo copy docker-archive:./result-api docker://ghcr.io/intersectmbo/cardano-submit-api:latest
122- echo "::endgroup::"
123-
124- echo "::group::Tagging latest for intersectmbo/cardano-tracer"
125- skopeo copy docker-archive:./result-tracer docker://ghcr.io/intersectmbo/cardano-tracer:latest
126- echo "::endgroup::"
136+ - name : Install Nix
137+ uses : cachix/install-nix-action@v31
138+
139+ # Regctl simplifies obtaining multi-arch digests
140+ - name : Install Nix Profile Commands
141+ run : nix profile install nixpkgs#regctl
142+
143+ # The docker buildx action has a tight coupling with GH runners
144+ - name : Setup Docker Buildx
145+ uses : docker/setup-buildx-action@v3
146+
147+ - name : Show buildx configuration
148+ run : docker buildx ls
149+
150+ - name : Log in to GitHub Container Registry
151+ uses : docker/login-action@v3
152+ with :
153+ registry : ghcr.io
154+ username : ${{ github.actor }}
155+ password : ${{ secrets.GITHUB_TOKEN }}
156+
157+ - name : Create Manifests
158+ run : |
159+ REPOS=(cardano-node cardano-submit-api cardano-tracer)
160+ ARCHES=(amd64 arm64)
161+
162+ for REPO in "${REPOS[@]}"; do
163+ IMAGE_REPO="ghcr.io/intersectmbo/$REPO"
164+ DIGESTS=()
165+
166+ echo "::group::Fetching digests for $REPO"
167+ for ARCH in "${ARCHES[@]}"; do
168+ DIGEST=$(skopeo inspect --no-tags "docker://$IMAGE_REPO:$GITHUB_REF_NAME-$ARCH" | jq -r .Digest)
169+ echo "$REPO $ARCH digest: $DIGEST"
170+ DIGESTS+=("$IMAGE_REPO@$DIGEST")
171+ done
172+ echo "::endgroup::"
173+
174+ echo "::group::Creating manifest for $REPO:$GITHUB_REF_NAME"
175+ docker buildx imagetools create --tag "$IMAGE_REPO:$GITHUB_REF_NAME" "${DIGESTS[@]}"
176+ echo "::endgroup::"
177+ done
178+
179+ - name : Verify multi-arch manifests
180+ run : |
181+ for REPO in cardano-node cardano-submit-api cardano-tracer; do
182+ IMAGE_REPO="ghcr.io/intersectmbo/$REPO"
183+ echo "::group::Inspecting $REPO:$GITHUB_REF_NAME"
184+
185+ DIGEST=$(regctl manifest head "$IMAGE_REPO:$GITHUB_REF_NAME")
186+ echo "$REPO multi-arch manifest digest: $DIGEST"
187+ skopeo inspect --raw "docker://$IMAGE_REPO:$GITHUB_REF_NAME" | jq
188+
189+ echo "::endgroup::"
190+ done
191+
192+ - name : Tag Containers as :latest
193+ # Github releases are checked for latest tag in the first `or` operand of
194+ # the if statement. However, promoted pre-releases or changed full
195+ # releases do not count as a `published` event and so won't trigger
196+ # this workflow. For those use cases a manual workflow must be run
197+ # from the matching release tag which the second `or` operand checks
198+ # for.
199+ if : |
200+ (github.event_name == 'release' && github.event.release.tag_name == needs.prepare.outputs.LATEST_TAG) ||
201+ (github.event_name == 'workflow_dispatch' && github.ref == format('refs/tags/{0}', needs.prepare.outputs.LATEST_TAG))
202+ run : |
203+ REPOS=(cardano-node cardano-submit-api cardano-tracer)
204+
205+ for REPO in "${REPOS[@]}"; do
206+ IMAGE_REPO="ghcr.io/intersectmbo/$REPO"
207+ DIGEST=$(regctl manifest head "$IMAGE_REPO:$GITHUB_REF_NAME")
208+
209+ echo "::group::Creating manifest for $IMAGE_REPO:latest"
210+ docker buildx imagetools create --tag "$IMAGE_REPO:latest" "$IMAGE_REPO@$DIGEST"
211+ echo "::endgroup::"
212+ done
0 commit comments