-
Notifications
You must be signed in to change notification settings - Fork 8
344 lines (312 loc) · 14.5 KB
/
deploy-release-reusable.yaml
File metadata and controls
344 lines (312 loc) · 14.5 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
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to you under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
name: deploy-release-reusable
on:
workflow_call:
inputs:
java-version:
description: The Java compiler version
default: 17
type: string
project-id:
description: Identifier used in the distribution artifact and Subversion repository folder filenames (e.g., `logging-parent`)
required: true
type: string
outputs:
project-version:
description: The version of the project
value: ${{ jobs.deploy.outputs.project-version }}
nexus-url:
description: The URL of the Nexus repository used
value: ${{ jobs.deploy.outputs.nexus-url }}
secrets:
GPG_SECRET_KEY:
description: GPG secret key for signing artifacts
required: true
NEXUS_USERNAME:
description: Nexus staging repository username for deploying artifacts
required: true
NEXUS_PASSWORD:
description: Nexus staging repository password for deploying artifacts
required: true
SVN_USERNAME:
description: Subversion username for uploading the release distribution
required: true
SVN_PASSWORD:
description: Subversion password for uploading the release distribution
required: true
jobs:
deploy:
runs-on: ubuntu-latest
outputs:
project-version: ${{ steps.version.outputs.project-version }}
nexus-url: ${{ steps.nexus.outputs.nexus-url }}
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2
- name: Set up Java & GPG
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # 3.7.0
with:
distribution: zulu
java-version: ${{ inputs.java-version }}
server-id: apache.releases.https
server-username: NEXUS_USERNAME
server-password: NEXUS_PASSWORD
gpg-private-key: ${{ secrets.GPG_SECRET_KEY }}
#
# Sets up Mimír (https://maveniverse.eu/docs/mimir/) to cache artifacts from remote repositories
#
# Unlike the local Maven repository, Mimír cannot be used to stage locally generated artifacts or snapshots.
# Therefore, it can be reused between builds, even on different architectures.
# Since the size of the cache increases in time, as we download new dependency versions, we reset the cache
# once a month.
#
# WARNING: Currently it is not possible to reuse GitHub workflow steps, therefore, these two steps must be
# copied to multiple workflows.
# The `build-reusable` workflow uses `actions/cache`,
# while the other workflows only use `actions/cache/restore`
#
- name: Set up Mimír configuration
shell: bash
run: |
# Compute the key cache
echo MIMIR_KEY="mimir-cache-$(date +'%Y-%m')" >> $GITHUB_ENV
# Mimir currently does not support relative paths, so we need to compute the absolute path of `mimir`.
echo MAVEN_OPTS="-Dmimir.daemon.passOnBasedir=true -Dmimir.daemon.autostop=true -Dmimir.basedir=$GITHUB_WORKSPACE/.mimir" >> $GITHUB_ENV
- name: Set up Mimír cache
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # 4.2.3
with:
# Mimir is a partial mirror of Maven Central.
# Therefore, we only need to clean it from time to time to remove old versions.
#
# However, GitHub caches are immutable, and we need a unique key to update them.
# If no cache hit occurs for this key, we fall back to any other cache.
key: "${{ env.MIMIR_KEY }}-${{ hashFiles('**/pom.xml') }}"
restore-keys: |
${{ env.MIMIR_KEY }}-
path: .mimir/local
- name: Set up Git user
shell: bash
run: |
# Set up user name and email required for `git commit`
git config user.name "ASF Logging Services RM"
git config user.email private@logging.apache.org
- name: Export version
id: version
shell: bash
env:
GIT_BRANCH_NAME: ${{ github.ref_name }}
run: |
[[ "$GIT_BRANCH_NAME" =~ ^release/.+$ ]] || {
echo "was expecting a \`release/\`-prefixed Git branch name, found: \`$GIT_BRANCH_NAME\`"
exit 1
}
export PROJECT_VERSION=$(echo "$GIT_BRANCH_NAME" | sed 's/^release\///')
echo "PROJECT_VERSION=$PROJECT_VERSION" >> $GITHUB_ENV
# Export version to calling workflow
echo "project-version=$PROJECT_VERSION" >> $GITHUB_OUTPUT
- name: Set the Maven `revision` property
shell: bash
run: |
export REVISION=$(./mvnw \
--non-recursive --quiet --batch-mode \
-DforceStdout=true \
-Dexpression=revision \
help:evaluate \
| tail -n 1)
if [ "$REVISION" != "$PROJECT_VERSION" ]; then
echo "Maven \`revision\` property \`$REVISION\` doesn't match with the project version \`$PROJECT_VERSION\`, updating \`pom.xml\`..."
./mvnw \
--non-recursive --batch-mode --errors --no-transfer-progress \
-Dproperty=revision \
-DnewVersion="$PROJECT_VERSION" \
-DgenerateBackupPoms=false \
versions:set-property
git commit -S pom.xml -m "Set version to \`$PROJECT_VERSION\`"
git push -f origin
fi
- name: Set the Maven `project.build.outputTimestamp` property
shell: bash
run: |
export PROPERTY="project.build.outputTimestamp"
grep -qE '^[\t ]+<'$PROPERTY'>' pom.xml || {
echo "Failed to find the \`$PROPERTY\` Maven property!"
exit 1
}
export TIMESTAMP=$(TZ=UTC0 git show --quiet --date="format-local:%Y-%m-%dT%H:%M:%SZ" --format="%cd")
sed -r 's|^([\t ]+<'$PROPERTY'>).+(</'$PROPERTY'>)$|\1'$TIMESTAMP'\2|g' -i pom.xml
if [ -n "$(git status --porcelain)" ]; then
git commit -S pom.xml -m "Update the \`$PROPERTY\` property"
git push -f origin
fi
- name: Release changelog
shell: bash
run: |
./mvnw \
--non-recursive --batch-mode --errors --no-transfer-progress \
-P changelog-release
git add src
if [ -n "$(git status --porcelain)" ]; then
git commit -S src -m "Release changelog for version \`$PROJECT_VERSION\`"
git push -f origin
fi
- name: Upload to Nexus
id: nexus
shell: bash
env:
# `NEXUS_USERNAME` and `NEXUS_PASSWORD` are used in `~/.m2/settings.xml` created by `setup-java` action
NEXUS_USERNAME: ${{ secrets.NEXUS_USERNAME }}
NEXUS_PASSWORD: ${{ secrets.NEXUS_PASSWORD }}
# `SIGN_KEY` is used by `sign-maven-plugin`
SIGN_KEY: ${{ secrets.GPG_SECRET_KEY }}
run: |
./mvnw \
--show-version --batch-mode --errors --no-transfer-progress \
-P deploy,release
export NEXUS_URL=$(awk '/^(stagingRepository.url)/ { gsub(/(^.+=|\\)/, ""); print $1 }' target/nexus-staging/staging/*.properties)
echo "NEXUS_URL=$NEXUS_URL" >> $GITHUB_ENV
# Export repository URL to calling workflow
echo "nexus-url=$NEXUS_URL" >> $GITHUB_OUTPUT
# Node.js cache is needed for Antora
- name: Set up Node.js cache
id: nodejs-cache
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # 4.2.3
with:
# We should be calculating the cache key using `package-lock.json` instead!
# See https://stackoverflow.com/a/48524475/1278899
# For that, `package-lock.json` needs to be committed into the repository – right now it is `.gitignore`d.
# Once it is there, we should ideally switch from `npm i` to `npm ci`.
# For that, we need to configure `dependabot` to update hundreds of dependencies listed in `package-lock.json`.
# That translates to a never ending rain of `dependabot` PRs.
# I doubt if the wasted CPU cycles worth the gain.
key: "${{ runner.os }}-nodejs-cache-${{ hashFiles('node', 'node_modules') }}"
# `actions/cache` doesn't recommend caching `node_modules`.
# Though none of its recipes fit our bill, since we install Node.js using `frontend-maven-plugin`.
# See https://github.com/actions/cache/blob/main/examples.md#node---npm
# We settle for this quick-n-dirty solution for the time being.
path: |
node
node_modules
# Website build is needed to generate the release notes
- name: Build the website
shell: bash
env:
# Making Node.js cache hit visible for debugging purposes
NODEJS_CACHE_HIT: ${{ steps.nodejs-cache.outputs.cache-hit }}
run: |
export TIMESTAMP=$(./mvnw \
--non-recursive --quiet --batch-mode \
-DforceStdout=true \
-Dexpression=project.build.outputTimestamp \
help:evaluate \
| tail -n 1)
./mvnw \
--show-version --batch-mode --errors --no-transfer-progress \
site
- name: Stage distribution attachments
shell: bash
run: |
# Dump deployed artifacts to a local folder
export ALT_DEPLOYMENT_REPO_FILEPATH="target/alt-deployment-repo"
mkdir "$ALT_DEPLOYMENT_REPO_FILEPATH"
./mvnw \
--show-version --batch-mode --errors --no-transfer-progress \
-DaltDeploymentRepository=apache.releases.https::file:"$ALT_DEPLOYMENT_REPO_FILEPATH" \
deploy:deploy
# This regex needs to work for both Java (`distribution` profile) and `find` (while counting attachments)!
# Hence, we don't escape dots, etc. with backslashes, which is problematic to get working in both worlds.
export DIST_ATTACHMENT_FILEPATH_PATTERN="^$ALT_DEPLOYMENT_REPO_FILEPATH/.+-$PROJECT_VERSION"'((-tests)?.jar|-cyclonedx.xml)$'
export DIST_ATTACHMENT_COUNT=$(find "$ALT_DEPLOYMENT_REPO_FILEPATH" -type f -regextype posix-extended -regex "$DIST_ATTACHMENT_FILEPATH_PATTERN" | wc -l)
# Pass the necessary environment variables
cat >> $GITHUB_ENV << EOF
DIST_ATTACHMENT_FILEPATH_PATTERN=$DIST_ATTACHMENT_FILEPATH_PATTERN
DIST_ATTACHMENT_COUNT=$DIST_ATTACHMENT_COUNT
EOF
- name: Create the distribution
shell: bash
env:
PROJECT_ID: ${{ inputs.project-id }}
run: |
# Generate the distribution (i.e., `src.zip` and optional `bin.zip`)
./mvnw \
--show-version --batch-mode --errors --no-transfer-progress \
--non-recursive \
-P distribution \
-DattachmentFilepathPattern="$DIST_ATTACHMENT_FILEPATH_PATTERN" \
-DattachmentCount="$DIST_ATTACHMENT_COUNT"
# Rename distribution files
export DIST_FILENAME_PREFIX="apache-${PROJECT_ID}"
export DIST_FILENAME_VERSIONED_PREFIX="${DIST_FILENAME_PREFIX}-${PROJECT_VERSION}"
export DIST_FILEPATH_PREFIX="/tmp/${DIST_FILENAME_VERSIONED_PREFIX}"
export DIST_FILEPATH_SRC="${DIST_FILEPATH_PREFIX}-src.zip"
export DIST_FILEPATH_BIN="${DIST_FILEPATH_PREFIX}-bin.zip"
mv "target/src.zip" "$DIST_FILEPATH_SRC"
test -f "target/bin.zip" && mv "$_" "$DIST_FILEPATH_BIN"
# Create signature and checksum files
for DIST_FILEPATH in "$DIST_FILEPATH_SRC" "$DIST_FILEPATH_BIN"; do
if [ -f "$DIST_FILEPATH" ]; then
gpg --armor --detach-sign --yes --pinentry-mode error "$DIST_FILEPATH"
sha512sum "$DIST_FILEPATH" \
| ( read CHECKSUM FILEPATH; echo $CHECKSUM" "$(basename "$FILEPATH") ) \
> "$DIST_FILEPATH.sha512"
fi
done
# Pass the necessary environment variables
cat >> $GITHUB_ENV << EOF
DIST_FILENAME_PREFIX=$DIST_FILENAME_PREFIX
DIST_FILENAME_VERSIONED_PREFIX=$DIST_FILENAME_VERSIONED_PREFIX
DIST_FILEPATH_PREFIX=$DIST_FILEPATH_PREFIX
EOF
- name: Upload to Subversion
shell: bash
env:
PROJECT_ID: ${{ inputs.project-id }}
SVN_USERNAME: ${{ secrets.SVN_USERNAME }}
SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }}
run: |
# Install Subversion
sudo apt install --assume-yes --no-install-recommends subversion
# Find the effective Git commit ID
export COMMIT_ID=$(git rev-parse HEAD)
# Checkout the SVN repository
export SVN_DIR="/tmp/svn-repo"
svn co \
"https://dist.apache.org/repos/dist/dev/logging/$PROJECT_ID" \
"$SVN_DIR"
cd "$SVN_DIR"
# Switch to the distribution folder
[ -d "$PROJECT_VERSION" ] || {
mkdir "$PROJECT_VERSION"
svn add "$PROJECT_VERSION"
}
cd "$PROJECT_VERSION"
# Clean up old files
find . -name "${DIST_FILENAME_PREFIX}*" -type f -print0 | xargs -0 -r svn delete
# Generate emails
for EMAIL_TYPE in vote announce; do
"$GITHUB_WORKSPACE/.github/generate-email.sh" \
"$EMAIL_TYPE" "$PROJECT_VERSION" "$COMMIT_ID" "$NEXUS_URL" \
> "${DIST_FILENAME_VERSIONED_PREFIX}-email-${EMAIL_TYPE}.txt"
done
# Copy the distribution
cp "$DIST_FILEPATH_PREFIX"* .
# Add & commit changes
svn add "$DIST_FILENAME_PREFIX"*
svn commit \
--username "$SVN_USERNAME" \
--password "$SVN_PASSWORD" \
-m "Added \`${DIST_FILENAME_PREFIX}\` artifacts for release \`${PROJECT_VERSION}\`"