This repository was archived by the owner on Feb 21, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 13
243 lines (218 loc) · 10.7 KB
/
build.yml
File metadata and controls
243 lines (218 loc) · 10.7 KB
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
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
name: Build container image
on:
pull_request:
branches:
- main
schedule:
- cron: "0 1 * * SUN"
push:
branches:
- main
paths-ignore:
- "**/README.md"
workflow_dispatch:
env:
IMAGE_DESC: "OCI image for Homebrew"
IMAGE_KEYWORDS: "homebrew"
IMAGE_LOGO_URL: "https://avatars.githubusercontent.com/u/136393846?s=200&v=4"
IMAGE_NAME: "${{ github.event.repository.name }}"
IMAGE_REGISTRY: "ghcr.io/${{ github.repository_owner }}"
DEFAULT_TAG: "latest"
jobs:
build_push:
name: Build and push image
permissions:
contents: read
packages: write
id-token: write
timeout-minutes: 60
strategy:
fail-fast: true
matrix:
platform: ["amd64", "arm64"]
runs-on: ${{ matrix.platform == 'amd64' && 'ubuntu-24.04' || 'ubuntu-24.04-arm' }}
steps:
- name: Checkout
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- name: Build image
run: podman build -t "${IMAGE_NAME}:${DEFAULT_TAG}" -f ./Containerfile .
- name: Login to GitHub Container Registry
if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
LOGIN_USER: ${{ github.actor }}
run: |
echo "${GITHUB_TOKEN}" | podman login -u "${LOGIN_USER}" --password-stdin "ghcr.io"
echo "${GITHUB_TOKEN}" | docker login -u "${LOGIN_USER}" --password-stdin "ghcr.io"
- name: Push to GHCR
if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
id: push
env:
IMAGE_REGISTRY: ${{ env.IMAGE_REGISTRY }}
IMAGE_NAME: ${{ env.IMAGE_NAME }}
IMAGE_DIGEST: ${{ steps.load.outputs.digest }}
PLATFORM: ${{ matrix.platform }}
MAX_RETRIES: 3
run: |
set -x
for i in $(seq "${MAX_RETRIES}"); do
podman push --digestfile=/tmp/digestfile "localhost/${IMAGE_NAME}:${DEFAULT_TAG}" "${IMAGE_REGISTRY}/${IMAGE_NAME}:${DEFAULT_TAG}-${PLATFORM}" && break || sleep $((5 * i));
done
echo "remote_image_digest=$(< /tmp/digestfile)" | tee "${GITHUB_OUTPUT}"
- name: Install Cosign
uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0
if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
- name: Sign Image
if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
env:
REMOTE_IMAGE_DIGEST: ${{ steps.push.outputs.remote_image_digest }}
COSIGN_EXPERIMENTAL: false
COSIGN_PRIVATE_KEY: ${{ secrets.SIGNING_SECRET }}
run: cosign sign -y --key env://COSIGN_PRIVATE_KEY "${IMAGE_REGISTRY}/${IMAGE_NAME}@${REMOTE_IMAGE_DIGEST}"
- name: Create Job Outputs
if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
env:
IMAGE_NAME: ${{ env.IMAGE_NAME }}
PLATFORM: ${{ matrix.platform }}
DIGEST: ${{ steps.push.outputs.remote_image_digest }}
run: |
set -x
mkdir -p /tmp/outputs/digests
echo "${DIGEST}" | tee "/tmp/outputs/digests/${IMAGE_NAME}-${PLATFORM}.txt"
- name: Upload Output Artifacts
if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
with:
name: ${{ env.IMAGE_NAME }}-${{ matrix.platform }}
retention-days: 1
if-no-files-found: error
path: |
/tmp/outputs/digests/*.txt
manifest:
name: Create Manifest
runs-on: ubuntu-latest
if: always()
needs:
- build_push
container:
image: docker.io/library/alpine:latest
options: --privileged --security-opt seccomp=unconfined
permissions:
contents: read
packages: write
id-token: write
steps:
- name: Install dependencies
run: apk add bash coreutils curl docker findutils fuse-overlayfs git grep jq podman sed
# Necessary until bootc supports Cosign v3
- name: Install old cosign
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
# Thank you Bri! :3 @b-
curl --retry 3 -H "Authorization: Bearer ${GITHUB_TOKEN}" -fsSLo "/usr/bin/cosign" "https://github.com/sigstore/cosign/releases/download/v2.6.1/cosign-linux-amd64"
chmod +x /usr/bin/cosign
- name: Exit on failure
shell: bash
env:
JOBS: ${{ toJson(needs) }}
run: |
for i in $(jq -r 'to_entries[] | .value.result' <<< "${JOBS}"); do
if [ "$i" != "success" ] && [ "$i" != "skipped" ]; then
echo "Status check not okay!"
exit 1
fi
done
# This generates a timestamp like what is defined on the ArtifactHub documentation
# E.G: 2022-02-08T15:38:15Z'
# https://artifacthub.io/docs/topics/repositories/container-images/
# https://linux.die.net/man/1/date
- name: Get current date
id: date
run: echo "date=$(date -u +%Y\-%m\-%d\T%H\:%M\:%S\Z)" | tee "${GITHUB_OUTPUT}"
- name: Image Metadata
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5
id: metadata
with:
tags: |
type=raw,value=${{ env.DEFAULT_TAG }}
type=raw,value=${{ env.DEFAULT_TAG }}.{{date 'YYYYMMDD'}}
type=raw,value={{date 'YYYYMMDD'}}
type=ref,event=pr
type=sha,enable=${{ github.event_name == 'pull_request' }}
labels: |
containers.bootc=1
io.artifacthub.package.deprecated=false
io.artifacthub.package.keywords=${{ env.IMAGE_KEYWORDS }}
io.artifacthub.package.license=Apache-2.0
io.artifacthub.package.logo-url=${{ env.IMAGE_LOGO_URL }}
io.artifacthub.package.prerelease=false
io.artifacthub.package.readme-url=https://raw.githubusercontent.com/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}/${{ github.sha }}/README.md
org.opencontainers.image.created=${{ steps.date.outputs.date }}
org.opencontainers.image.description=${{ env.IMAGE_DESC }}
org.opencontainers.image.documentation=https://raw.githubusercontent.com/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}/${{ github.sha }}/README.md
org.opencontainers.image.source=https://github.com/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}/blob/${{ github.sha }}/Containerfile
org.opencontainers.image.title=${{ env.IMAGE_NAME }}
org.opencontainers.image.url=https://github.com/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}/tree/${{ github.sha }}
org.opencontainers.image.vendor=${{ github.repository_owner }}
org.opencontainers.image.version=${{ env.DEFAULT_TAG }}.{{date 'YYYYMMDD'}}
- name: Fetch Build Outputs
if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
with:
pattern: ${{ env.IMAGE_NAME }}-*
merge-multiple: true
path: /tmp/artifacts
- name: Load Outputs
if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
shell: bash
id: load-outputs
run: |
set -x
OUTCSV="$(mktemp)"
for digest_file in /tmp/artifacts/*.txt; do
# Extract the platform from the file name
PLATFORM="$(basename "${digest_file}" ".txt" | sed 's/.*-//g')"
IMAGE_NAME="$(basename "${digest_file}" ".txt" | grep -Po ".*-" | sed 's/-$//')"
DIGEST="$(< "${digest_file}")"
echo "${PLATFORM},${IMAGE_NAME},${DIGEST}" | tee -a "${OUTCSV}"
done
echo "OUTPUT_CSV=$(base32 -w 0 < "${OUTCSV}")" | tee -a "${GITHUB_OUTPUT}"
- name: Login to GitHub Container Registry
if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
env:
REGISTRY: ghcr.io
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | podman login -u "${{ github.actor }}" --password-stdin "${REGISTRY}"
echo "${{ secrets.GITHUB_TOKEN }}" | docker login -u "${{ github.actor }}" --password-stdin "${REGISTRY}"
- name: Publish manifest with unified architecture and sign
shell: bash
if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
env:
COSIGN_EXPERIMENTAL: false
COSIGN_PRIVATE_KEY: ${{ secrets.SIGNING_SECRET }}
LABELS: ${{ steps.metadata.outputs.labels }}
OUTPUT_CSV: ${{ steps.load-outputs.outputs.OUTPUT_CSV }}
TAGS: ${{ steps.metadata.outputs.tags }}
run: |
set -x
OUTPUT_CSV_FILE="$(mktemp)"
echo "${OUTPUT_CSV}" | base32 -d | tee "${OUTPUT_CSV_FILE}"
# This is insanely dumb, please PR if you have a better solution ~ @tulilirockz :3c
IMAGES=$(cat "${OUTPUT_CSV_FILE}" | while IFS=$'\n' read -r ENTRY ; do echo "${ENTRY}" | cut -d, -f2 ; done | sort | uniq | tr "\n" " " | sed 's/.$//')
for TARGET_IMAGE in ${IMAGES} ; do
TARGET_MANIFEST="${IMAGE_REGISTRY}/${TARGET_IMAGE}"
podman manifest create "${TARGET_MANIFEST}"
PLATFORMS=$(grep -F -e "${IMAGE}" "${OUTPUT_CSV_FILE}" | while IFS=$'\n' read -r ENTRY ; do echo "${ENTRY}" | cut -d, -f1 ; done | sort | uniq | tr "\n" " " | sed 's/.$//')
for TARGET_PLATFORM in ${PLATFORMS} ; do
TARGET_DIGEST="$(grep -F -e ",${TARGET_IMAGE}," "${OUTPUT_CSV_FILE}" | grep -F -e "${TARGET_PLATFORM}" | cut -d, -f3 | tr -d "\n")"
podman manifest add "${TARGET_MANIFEST}" "${TARGET_MANIFEST}@${TARGET_DIGEST}" --arch "${TARGET_PLATFORM}"
done
while IFS= read -r LABEL; do
podman manifest annotate --index --annotation "${LABEL}" "${TARGET_MANIFEST}"
done <<< "${LABELS}"
while IFS= read -r TAG; do
podman manifest push --all=false --digestfile=/tmp/digestfile "${TARGET_MANIFEST}" "${TARGET_MANIFEST}:${TAG}"
done <<< "${TAGS}"
cosign sign -y --key env://COSIGN_PRIVATE_KEY "${TARGET_MANIFEST}@$(< /tmp/digestfile)"
done