-
Notifications
You must be signed in to change notification settings - Fork 60.5k
199 lines (177 loc) · 8.14 KB
/
Copy pathbuild-v3-nightly.yml
File metadata and controls
199 lines (177 loc) · 8.14 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
# Builds and publishes nightly Docker images for the v3 (3.x) branch.
#
# Produces n8nio/n8n:v3-nightly and a timestamped n8nio/n8n:v3-nightly-<date>
# (plus the matching runners images) so v3 can be trialed in docker/kubernetes
# before release. Reuses the shared docker-build-push.yml pipeline, pointing it
# at the 3.x branch via the `ref` input.
#
# On Mondays the same manifests are additionally retagged v3-rc / v3-rc-<date>, so
# there is a weekly, self-consistent set to run a stack against.
#
# Lives on master so the schedule fires (scheduled runs only trigger on the
# default branch), but builds the 3.x branch's code.
name: 'Build: v3 Nightly Docker Images'
on:
schedule:
# 08:00 UTC — after the master→3.x sync (06:00) so the image reflects the latest sync
- cron: '0 8 * * *'
workflow_dispatch:
inputs:
force_rc:
description: 'Also tag this build as a release candidate (normally Mondays only)'
required: false
type: boolean
default: false
jobs:
prepare:
name: Compute date tag
if: github.repository == 'n8n-io/n8n'
runs-on: ubuntu-latest
permissions: {}
outputs:
date_tag: ${{ steps.date.outputs.date }}
day_of_week: ${{ steps.date.outputs.day_of_week }}
steps:
- name: Compute date tag
id: date
# Both values read the same UTC clock, so they can't disagree across a day boundary.
run: |
echo "date=$(date -u +%Y%m%d)" >> "$GITHUB_OUTPUT"
echo "day_of_week=$(date -u +%u)" >> "$GITHUB_OUTPUT"
build:
name: Build and push v3-nightly images
needs: prepare
# No permissions/secrets caps here on purpose: this mirrors the proven
# release-publish.yml caller so docker-build-push.yml runs with the permissions
# (its own per-job blocks + repo defaults) and org secrets it already relies on.
# Capping here risks starving its sub-jobs (SLSA/attestation/scan/push).
uses: ./.github/workflows/docker-build-push.yml # zizmor: ignore[excessive-permissions,secrets-inherit]
with:
ref: '3.x'
n8n_version: 'v3-nightly'
release_type: 'nightly'
date_tag: ${{ needs.prepare.outputs.date_tag }}
push_enabled: true
secrets: inherit
# On Mondays (or on demand via force_rc), promote the whole set (n8n + both runners
# images) to v3-rc so a stack pulling `v3-rc` gets images that were built from the same
# 3.x commit. Pure retag of manifests the build already pushed — nothing is rebuilt.
#
# RCs can be published several times a day: each publish claims the next free rolling
# number for today (v3-rc-<date>.1, .2, …) as its immutable reference, and also moves
# the floating v3-rc and v3-rc-<date> tags onto it.
tag_release_candidate:
name: Tag release candidate
needs: [prepare, build]
if: ${{ needs.prepare.outputs.day_of_week == '1' || inputs.force_rc }}
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
# Serialize promotion only (not the build) so two runs can't claim the same number.
concurrency:
group: v3-rc-tagging
cancel-in-progress: false
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Login to Docker registries
uses: ./.github/actions/docker-registry-login
with:
login-ghcr: true
login-dockerhub: true
dockerhub-username: ${{ secrets.DOCKER_USERNAME }}
dockerhub-password: ${{ secrets.DOCKER_PASSWORD }}
- name: Claim rolling RC number for today
id: rc
env:
RC_VERSION: v3-rc
DATE_TAG: ${{ needs.prepare.outputs.date_tag }}
N8N_IMAGE: ${{ needs.build.outputs.n8n_image }}
MAX_PER_DAY: '50'
run: |
set -euo pipefail
# The n8n GHCR repo is the single source of truth for the counter; all images
# then share the number, so one RC is always one consistent set.
tag_exists() {
local ref=$1 out
if out=$(docker buildx imagetools inspect "$ref" --raw 2>&1); then
return 0
fi
# Only a genuine absence frees the number. Auth/network/rate-limit failures
# must not be read as "free" — that would overwrite an immutable tag.
if grep -qiE 'not found|manifest unknown|no such manifest|MANIFEST_UNKNOWN|404' <<<"$out"; then
return 1
fi
echo "::error::Cannot determine whether ${ref} exists: ${out}"
exit 1
}
RC_NUMBER=''
for n in $(seq 1 "$MAX_PER_DAY"); do
if ! tag_exists "${N8N_IMAGE}:${RC_VERSION}-${DATE_TAG}.${n}"; then
RC_NUMBER=$n
break
fi
echo "${RC_VERSION}-${DATE_TAG}.${n} already published"
done
if [[ -z "$RC_NUMBER" ]]; then
echo "::error::Already published ${MAX_PER_DAY} release candidates for ${DATE_TAG}"
exit 1
fi
echo "Claiming ${RC_VERSION}-${DATE_TAG}.${RC_NUMBER}"
echo "number=${RC_NUMBER}" >> "$GITHUB_OUTPUT"
- name: Promote nightly manifests to release candidate
env:
NIGHTLY_VERSION: v3-nightly
RC_VERSION: v3-rc
DATE_TAG: ${{ needs.prepare.outputs.date_tag }}
RC_NUMBER: ${{ steps.rc.outputs.number }}
DOCKER_BASE: ${{ secrets.DOCKER_USERNAME }}
N8N_IMAGE: ${{ needs.build.outputs.n8n_image }}
N8N_DIGEST: ${{ needs.build.outputs.n8n_digest }}
RUNNERS_IMAGE: ${{ needs.build.outputs.runners_image }}
RUNNERS_DIGEST: ${{ needs.build.outputs.runners_digest }}
DISTROLESS_IMAGE: ${{ needs.build.outputs.runners_distroless_image }}
DISTROLESS_DIGEST: ${{ needs.build.outputs.runners_distroless_digest }}
run: |
set -euo pipefail
# Each image gets three tags: the numbered one is the immutable reference for this
# publish; v3-rc and v3-rc-<date> float onto the newest RC overall / of the day.
RC_ROLLING="${RC_VERSION}-${DATE_TAG}.${RC_NUMBER}"
# Retag one image as RC on both registries. GHCR is sourced by digest (immutable,
# can't drift); Docker Hub is sourced by its dated tag because `imagetools create`
# only retags within a repository — it can't pull GHCR blobs into Docker Hub.
promote() {
local ghcr_repo=$1 digest=$2 docker_repo=$3 suffix=$4
if [[ -z "$ghcr_repo" || -z "$digest" ]]; then
echo "::error::Missing image/digest for ${docker_repo}${suffix} - nightly manifest not published"
return 1
fi
echo "Promoting ${ghcr_repo}@${digest} -> ${RC_ROLLING}${suffix}"
docker buildx imagetools create \
--tag "${ghcr_repo}:${RC_ROLLING}${suffix}" \
--tag "${ghcr_repo}:${RC_VERSION}${suffix}" \
--tag "${ghcr_repo}:${RC_VERSION}-${DATE_TAG}${suffix}" \
"${ghcr_repo}@${digest}"
docker buildx imagetools create \
--tag "${docker_repo}:${RC_ROLLING}${suffix}" \
--tag "${docker_repo}:${RC_VERSION}${suffix}" \
--tag "${docker_repo}:${RC_VERSION}-${DATE_TAG}${suffix}" \
"${docker_repo}:${NIGHTLY_VERSION}-${DATE_TAG}${suffix}"
{
echo "- \`${ghcr_repo}:${RC_ROLLING}${suffix}\`"
echo "- \`${docker_repo}:${RC_ROLLING}${suffix}\`"
} >> "$GITHUB_STEP_SUMMARY"
}
{
echo "## v3 release candidate \`${RC_ROLLING}\`"
echo ""
echo "Immutable references (\`${RC_VERSION}\` and \`${RC_VERSION}-${DATE_TAG}\` now point here too):"
} >> "$GITHUB_STEP_SUMMARY"
promote "$N8N_IMAGE" "$N8N_DIGEST" "${DOCKER_BASE}/n8n" ""
promote "$RUNNERS_IMAGE" "$RUNNERS_DIGEST" "${DOCKER_BASE}/runners" ""
promote "$DISTROLESS_IMAGE" "$DISTROLESS_DIGEST" "${DOCKER_BASE}/runners" "-distroless"