Skip to content

Commit c8e3068

Browse files
committed
docker publishing pipeline for riverproui
1 parent d947a54 commit c8e3068

5 files changed

Lines changed: 317 additions & 47 deletions

File tree

.github/workflows/ci.yaml

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,20 @@ jobs:
5151
run: go version
5252

5353
- name: Install dependencies
54-
run: |
55-
echo "::group::go get"
56-
go get -t ./...
57-
echo "::endgroup::"
54+
run: go mod download
55+
56+
- name: Install River Pro UI dependencies
57+
env:
58+
GONOSUMDB: riverqueue.com/riverpro
59+
GOPROXY: https://proxy.golang.org,https://u:${{ secrets.RIVERPRO_GO_MOD_CREDENTIAL }}@riverqueue.com/goproxy,direct
60+
working-directory: ./riverproui
61+
run: go mod download
5862

59-
- name: Install River CLI
60-
run: go install github.com/riverqueue/river/cmd/river@latest
63+
- name: Install River Pro CLI
64+
env:
65+
GONOSUMDB: riverqueue.com/riverpro
66+
GOPROXY: https://proxy.golang.org,https://u:${{ secrets.RIVERPRO_GO_MOD_CREDENTIAL }}@riverqueue.com/goproxy,direct
67+
run: go install riverqueue.com/riverpro/cmd/riverpro@latest
6168

6269
- name: Create test DB
6370
run: createdb river_test
@@ -67,7 +74,9 @@ jobs:
6774
PGPASSWORD: postgres
6875

6976
- name: Migrate test DB
70-
run: river migrate-up --database-url "$TEST_DATABASE_URL"
77+
run: |
78+
riverpro migrate-up --database-url "$TEST_DATABASE_URL" --line main
79+
riverpro migrate-up --database-url "$TEST_DATABASE_URL" --line pro
7180
7281
# ensure that there is a file in `dist` to prevent a lint error about
7382
# it during CI when there is nothing there:
@@ -77,11 +86,16 @@ jobs:
7786
- name: Test
7887
run: go test -race ./... -timeout 2m
7988

89+
- name: Test River Pro UI
90+
working-directory: ./riverproui
91+
run: go test ./... -race -timeout 2m
92+
8093
golangci:
8194
name: Go lint
8295
runs-on: ubuntu-latest
8396
env:
8497
GOLANGCI_LINT_VERSION: v2.2.1
98+
GOPROXY: https://proxy.golang.org,https://u:${{ secrets.RIVERPRO_GO_MOD_CREDENTIAL }}@riverqueue.com/goproxy,direct
8599
permissions:
86100
contents: read
87101
# allow read access to pull request. Use with `only-new-issues` option.

.github/workflows/docker.yaml

Lines changed: 232 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,27 @@ on:
99
pull_request:
1010
branches:
1111
- "master"
12+
workflow_dispatch:
13+
inputs:
14+
ref:
15+
description: "Tag to build (e.g. v0.1.0)"
16+
required: true
1217

1318
env:
1419
IMAGE_NAME: ${{ github.repository }}
1520
REGISTRY: ghcr.io
1621

1722
jobs:
18-
build:
19-
name: Build Docker image
20-
runs-on: ubuntu-latest
23+
build-riverui:
24+
name: "Build Docker image: riverui"
25+
runs-on: ${{ matrix.runner }}
2126
strategy:
2227
matrix:
23-
docker_platform:
24-
- linux/amd64
25-
- linux/arm64
26-
- linux/arm64/v8
28+
include:
29+
- docker_platform: linux/amd64
30+
runner: ubuntu-latest
31+
- docker_platform: linux/arm64
32+
runner: ubuntu-24.04-arm64
2733
outputs:
2834
tags: ${{ steps.meta.outputs.tags }}
2935
labels: ${{ steps.meta.outputs.labels }}
@@ -36,15 +42,14 @@ jobs:
3642
steps:
3743
- name: Checkout
3844
uses: actions/checkout@v4
45+
with:
46+
ref: ${{ inputs.ref || github.ref }}
3947

4048
- name: Prepare
4149
run: |
4250
platform=${{ matrix.docker_platform }}
4351
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
4452
45-
- name: Set up QEMU
46-
uses: docker/setup-qemu-action@v3
47-
4853
- name: Set up Docker Buildx
4954
uses: docker/setup-buildx-action@v3
5055

@@ -59,7 +64,7 @@ jobs:
5964
id: meta
6065
uses: docker/metadata-action@v5
6166
with:
62-
images: ghcr.io/${{ github.repository }}
67+
images: ghcr.io/${{ env.IMAGE_NAME }}
6368
labels: |
6469
org.opencontainers.image.source=https://github.com/riverqueue/riverui
6570
org.opencontainers.image.description="River UI is a web-based user interface for River, a fast and reliable background job system."
@@ -69,6 +74,7 @@ jobs:
6974
type=ref,event=pr
7075
type=semver,pattern={{version}}
7176
type=semver,pattern={{major}}.{{minor}}
77+
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }}
7278
7379
- name: Build and push to GitHub Container Registry
7480
id: build
@@ -98,30 +104,107 @@ jobs:
98104
- name: Upload digest
99105
uses: actions/upload-artifact@v4
100106
with:
101-
name: digests-${{ env.PLATFORM_PAIR }}
107+
name: digests-oss-${{ env.PLATFORM_PAIR }}
102108
path: /tmp/digests/*
103109
if-no-files-found: error
104110
retention-days: 1
105111

106-
merge:
107-
name: Merge and publish image manifests
108-
runs-on: ubuntu-latest
109-
needs:
110-
- build
112+
build-riverproui:
113+
name: "Build Docker image: riverproui"
114+
runs-on: ${{ matrix.runner }}
115+
strategy:
116+
matrix:
117+
include:
118+
- docker_platform: linux/amd64
119+
runner: ubuntu-latest
120+
- docker_platform: linux/arm64
121+
runner: ubuntu-24.04-arm64
122+
111123
permissions:
124+
attestations: write
112125
contents: read
113126
id-token: write
114127
packages: write
115128

116129
steps:
117130
- name: Checkout
118131
uses: actions/checkout@v4
132+
with:
133+
ref: ${{ inputs.ref || github.ref }}
134+
135+
- name: Prepare
136+
run: |
137+
platform=${{ matrix.docker_platform }}
138+
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
139+
140+
- name: Set TAG
141+
run: echo "TAG=${{ inputs.ref || github.ref_name }}" >> $GITHUB_ENV
142+
143+
- name: Validate TAG
144+
if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch'
145+
run: |
146+
if [[ ! "$TAG" == v* ]]; then
147+
echo "Tag must start with 'v'"
148+
exit 1
149+
fi
150+
151+
- name: Set up Docker Buildx
152+
uses: docker/setup-buildx-action@v3
153+
154+
- name: Build and push by digest
155+
id: build
156+
uses: docker/build-push-action@v6
157+
with:
158+
context: .
159+
file: Dockerfile.pro
160+
pull: true
161+
platforms: ${{ matrix.docker_platform }}
162+
labels: |
163+
org.opencontainers.image.source=https://github.com/riverqueue/riverui
164+
org.opencontainers.image.description=River UI Pro is a web-based user interface for River, with pro features.
165+
org.opencontainers.image.licenses=MPL-2.0
166+
# cache-from: type=registry,ref=riverqueue.com/riverproui:cache
167+
# cache-to: type=registry,ref=riverqueue.com/riverproui:cache,mode=max
168+
outputs: type=image,name=riverqueue.com/riverproui,push-by-digest=true,name-canonical=true,push=false,annotation-index.org.opencontainers.image.description=River UI Pro
169+
secrets: |
170+
"riverpro_credential=${{ secrets.RIVERPRO_GO_MOD_CREDENTIAL }}"
171+
172+
- name: Generate artifact attestation
173+
uses: actions/attest-build-provenance@v1
174+
with:
175+
push-to-registry: false
176+
subject-digest: ${{ steps.build.outputs.digest }}
177+
subject-name: riverqueue.com/riverproui
119178

179+
- name: Export digest
180+
run: |
181+
mkdir -p /tmp/digests
182+
digest="${{ steps.build.outputs.digest }}"
183+
touch "/tmp/digests/${digest#sha256:}"
184+
185+
- name: Upload digest
186+
uses: actions/upload-artifact@v4
187+
with:
188+
name: digests-pro-${{ env.PLATFORM_PAIR }}
189+
path: /tmp/digests/*
190+
if-no-files-found: error
191+
retention-days: 1
192+
193+
merge-riverui:
194+
name: "Merge Docker manifests: riverui"
195+
runs-on: ubuntu-latest
196+
needs:
197+
- build-riverui
198+
permissions:
199+
contents: read
200+
packages: write
201+
202+
steps:
120203
- name: Download digests
121204
uses: actions/download-artifact@v4
122205
with:
123206
path: /tmp/digests
124-
pattern: digests-*
207+
pattern: digests-oss-*
125208
merge-multiple: true
126209

127210
- name: Set up Docker Buildx
@@ -138,7 +221,7 @@ jobs:
138221
id: meta
139222
uses: docker/metadata-action@v5
140223
with:
141-
images: ghcr.io/${{ env.IMAGE_NAME }}
224+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
142225
labels: |
143226
org.opencontainers.image.source=https://github.com/riverqueue/riverui
144227
org.opencontainers.image.description="River UI is a web-based user interface for River, a fast and reliable background job system."
@@ -148,13 +231,140 @@ jobs:
148231
type=ref,event=pr
149232
type=semver,pattern={{version}}
150233
type=semver,pattern={{major}}.{{minor}}
234+
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }}
151235
152236
- name: Create manifest list and push
153237
working-directory: /tmp/digests
154238
run: |
155-
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
239+
docker buildx imagetools create \
240+
--annotation "index:org.opencontainers.image.source=https://github.com/riverqueue/riverui" \
241+
--annotation "index:org.opencontainers.image.description=River UI is a web-based user interface for River, a fast and reliable background job system." \
242+
--annotation "index:org.opencontainers.image.licenses=MPL-2.0" \
243+
$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
156244
$(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
157245
158-
- name: Inspect image
246+
merge-riverproui:
247+
name: "Merge Docker manifests: riverproui"
248+
runs-on: ubuntu-latest
249+
needs:
250+
- build-riverproui
251+
outputs:
252+
image-name: ${{ steps.meta-pro.outputs.tags }}
253+
digest: ${{ steps.merge.outputs.digest }}
254+
permissions:
255+
attestations: write
256+
contents: read
257+
id-token: write
258+
259+
steps:
260+
- name: Download digests
261+
uses: actions/download-artifact@v4
262+
with:
263+
path: /tmp/digests
264+
pattern: digests-pro-*
265+
merge-multiple: true
266+
267+
- name: Set up Docker Buildx
268+
uses: docker/setup-buildx-action@v3
269+
270+
- name: Docker meta for Pro
271+
id: meta-pro
272+
uses: docker/metadata-action@v5
273+
with:
274+
images: riverqueue.com/riverproui
275+
labels: |
276+
org.opencontainers.image.source=https://github.com/riverqueue/riverui
277+
org.opencontainers.image.description="River UI Pro is a web-based user interface for River, with pro features."
278+
org.opencontainers.image.licenses=MPL-2.0
279+
# TODO: type=ref are temporary for testing
280+
tags: |
281+
type=ref,event=branch
282+
type=ref,event=pr
283+
type=semver,pattern={{version}}
284+
type=semver,pattern={{major}}.{{minor}}
285+
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }}
286+
287+
- name: Create manifest list and export to OCI
288+
id: merge
289+
run: |
290+
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
291+
$(printf 'riverqueue.com/riverproui@sha256:%s ' /tmp/digests/*)
292+
docker buildx imagetools create --dry-run $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
293+
$(printf 'riverqueue.com/riverproui@sha256:%s ' /tmp/digests/*) > /tmp/oci
294+
echo "digest=$(sha256sum /tmp/oci | cut -d' ' -f1)" >> $GITHUB_OUTPUT
295+
296+
- name: Upload OCI artifact
297+
uses: actions/upload-artifact@v4
298+
with:
299+
name: pro-oci
300+
path: /tmp/oci
301+
retention-days: 1
302+
303+
publish-riverproui:
304+
name: "Publish Docker image: riverproui"
305+
runs-on: ubuntu-latest
306+
needs:
307+
- merge-riverproui
308+
309+
steps:
310+
- name: Checkout
311+
uses: actions/checkout@v4
312+
with:
313+
ref: ${{ inputs.ref || github.ref }}
314+
315+
- name: Download OCI artifact
316+
uses: actions/download-artifact@v4
317+
with:
318+
name: pro-oci
319+
path: /tmp/oci
320+
321+
- name: Install jq
322+
run: sudo apt-get update && sudo apt-get install -y jq
323+
324+
- name: Install AWS CLI
325+
uses: unfor19/install-aws-cli-action@v1
326+
with:
327+
version: 2
328+
verbose: false
329+
arch: amd64
330+
331+
- name: Configure AWS CLI
332+
run: |
333+
aws configure set aws_access_key_id ${{ secrets.R2_ACCESS_KEY_ID }}
334+
aws configure set aws_secret_access_key ${{ secrets.R2_SECRET_ACCESS_KEY }}
335+
aws configure set default.region auto
336+
337+
- name: Sync blobs to R2
338+
# TODO: temporary for testing
339+
# if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch'
340+
env:
341+
DOCKER_RELEASE_STORAGE_BUCKET: ${{ vars.DOCKER_RELEASE_STORAGE_BUCKET }}
342+
REPO_NAME: riverqueue.com/riverproui
343+
ENDPOINT_URL: ${{ secrets.R2_DOCKER_RELEASES_ENDPOINT_URL }}
344+
run: |
345+
aws s3 cp /tmp/oci/blobs/sha256/ s3://$DOCKER_RELEASE_STORAGE_BUCKET/$REPO_NAME/blobs/sha256/ --recursive --endpoint-url $ENDPOINT_URL
346+
347+
- name: Upload manifest by digest
348+
# TODO: temporary for testing
349+
# if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch'
350+
env:
351+
DOCKER_RELEASE_STORAGE_BUCKET: ${{ vars.DOCKER_RELEASE_STORAGE_BUCKET }}
352+
REPO_NAME: riverqueue.com/riverproui
353+
ENDPOINT_URL: ${{ secrets.R2_DOCKER_RELEASES_ENDPOINT_URL }}
354+
run: |
355+
MANIFEST_DIGEST=$(sha256sum /tmp/oci/index.json | awk '{print $1}')
356+
aws s3 cp /tmp/oci/index.json s3://$DOCKER_RELEASE_STORAGE_BUCKET/$REPO_NAME/manifests/sha256:$MANIFEST_DIGEST --content-type "application/vnd.docker.distribution.manifest.list.v2+json" --endpoint-url $ENDPOINT_URL
357+
358+
- name: Upload tagged manifests
359+
# TODO: temporary for testing
360+
# if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch'
361+
env:
362+
DOCKER_RELEASE_STORAGE_BUCKET: ${{ vars.DOCKER_RELEASE_STORAGE_BUCKET }}
363+
REPO_NAME: riverqueue.com/riverproui
364+
ENDPOINT_URL: ${{ secrets.R2_DOCKER_RELEASES_ENDPOINT_URL }}
159365
run: |
160-
docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}
366+
# Extract tags from the merge job output
367+
TAGS=$(echo '${{ needs.merge-riverproui.outputs.image-name }}' | tr ' ' '\n' | sed 's|riverqueue.com/riverproui:||' | grep -v '^$')
368+
for TAG in $TAGS; do
369+
aws s3 cp /tmp/oci/index.json s3://$DOCKER_RELEASE_STORAGE_BUCKET/$REPO_NAME/manifests/$TAG --content-type "application/vnd.docker.distribution.manifest.list.v2+json" --endpoint-url $ENDPOINT_URL
370+
done

0 commit comments

Comments
 (0)