-
Notifications
You must be signed in to change notification settings - Fork 179
596 lines (520 loc) · 21.2 KB
/
plugin-release.yml
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
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
# Plugin release automation
#
# Builds the plugin for release candidates and stable releases.
#
# Creates the release branch, the actual release on GitHub, and the correct tag.
#
# For new major releases, the action should be run from the `main` branch.
# For patch releases, the action should be run from the corresponding release branch (e.g. `release/1.2.0`)
name: Plugin Release
on:
workflow_dispatch:
inputs:
version:
description: 'Plugin version (e.g. 1.2.3 or 7.2.0-rc.1)'
required: true
env:
PLUGIN_VERSION: ${{ github.event.inputs.version }}
TAG_NAME: 'v${{ github.event.inputs.version }}'
IS_RC: ${{ contains(github.event.inputs.version, 'rc') }}
IS_PATCH_RELEASE: ${{ startsWith(github.ref, 'refs/heads/release/') }}
GIT_AUTHOR_EMAIL: ${{ github.actor }}@users.noreply.github.com
GIT_AUTHOR_NAME: ${{ github.actor }}
GIT_COMMITTER_EMAIL: ${{ github.actor }}@users.noreply.github.com
GIT_COMMITTER_NAME: ${{ github.actor }}
jobs:
# Perform some sanity checks at the beginning to avoid surprises.
checks:
name: Checks
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Verify semver compatibility
run: |
if [[ $PLUGIN_VERSION =~ $SEMVER_VERSION_REGEX ]]; then
echo "Given plugin version string is a valid semver version"
else
echo "Given plugin version string is not a valid semver version"
exit 1
fi
env:
SEMVER_VERSION_REGEX: ^([0-9]+)\.([0-9]+)\.([0-9]+)(-([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?(\+[0-9A-Za-z-]+)?$
- name: Verify release does not exist yet
run: |
if git describe --abbrev=0 --tags --match "$TAG_NAME" &>/dev/null; then
echo "The planned plugin version already exists!"
exit 1
fi
# - name: Ensure RC exists for stable release
# if: ${{ ! contains(github.event.inputs.version, 'rc') }}
# run: |
# VERSION_WITHOUT_SUFFIX=${PLUGIN_VERSION/-rc.*/}
# BRANCH=release/$VERSION_WITHOUT_SUFFIX
#
# if [[ -z $(git ls-remote origin $BRANCH) ]]; then
# echo "No release branch exists for this planned stable release"
# exit 1
# fi
#
# git checkout --track origin/$BRANCH
#
# if ! git describe --abbrev=0 --tags --match "$TAG_NAME-rc.*" &>/dev/null; then
# echo "No RC exists for this planned stable release"
# exit 1
# fi
- name: Ensure readme.txt contains changelog
run: |
VERSION_WITHOUT_SUFFIX=${PLUGIN_VERSION/-rc.*/}
CHANGELOG_REGEX="= $VERSION_WITHOUT_SUFFIX ="
if ! grep -q -P "$CHANGELOG_REGEX" readme.txt; then
echo "No changelog found in readme.txt"
exit 1
fi
# Get the current CDN assets version.
# If the static assets on the CDN have changed since the last release,
# bump the assets version accordingly in the `static-site` branch.
assets-version:
name: Prepare static assets
runs-on: ubuntu-latest
timeout-minutes: 60
needs: [checks]
steps:
# TODO: Define behavior for patch releases.
#
# A patch release is done from a specific release branch instead of `main`
#
# Patch releases must not necessarily copy assets from `main`.
# Given the following assets versions:
# main 1 2 3 4 <- next major release
# ^
# |
# current branch
#
# The patch release should probably get version 3.1 or similar,
# since version 4 is already used by the next major release.
#
# Right now, this is needs to be done manually for patch releases,
# otherwise the assets version is left unchanged here.
# Grab current assets version from `web-stories.php` and pass on to next steps.
# - name: Checkout
# uses: actions/checkout@v2
# with:
# ref:
# - name: Get current assets version
# id: base_assets_version
# run: |
# BASE_ASSETS_VERSION=main
# if [[ $(cat web-stories.php) =~ $ASSETS_VERSION_REGEX ]]; then
# BASE_ASSETS_VERSION=${BASH_REMATCH[1]}
# fi
# echo "::set-output name=BASE_ASSETS_VERSION::$BASE_ASSETS_VERSION"
# env:
# ASSETS_VERSION_REGEX: "https://wp.stories.google/static/([^']+)"
- name: Checkout static-site
uses: actions/checkout@v2
with:
ref: static-site
lfs: true
# Needed so the below commits will trigger a website deployment.
token: ${{ secrets.PLUGIN_RELEASE_ACCESS_TOKEN }}
# For release candidates of new major releases:
#
# 1. Get highest assets version
# 2. Compare with `main`
# 3. If they differ:
# 3.1 Set new_version = version+1
# 3.2 Copy `main` to new_version
# 3.2 Push new directory
# 4. Else, keep currently highest version
- name: Prepare assets for RC
if: ${{ contains(github.event.inputs.version, 'rc') && ! startsWith(github.ref, 'refs/heads/release/') }}
run: |
LATEST_ASSETS_VERSION=$(ls | sort -n | tail -1)
NEW_ASSETS_VERSION=$LATEST_ASSETS_VERSION
if ! diff -qr $BASE_ASSETS_VERSION $LATEST_ASSETS_VERSION &>/dev/null; then
NEW_ASSETS_VERSION=$((LATEST_ASSETS_VERSION+1))
cp -r $BASE_ASSETS_VERSION $NEW_ASSETS_VERSION
git add .
git status
git commit -m "Bump static assets for plugin release $PLUGIN_VERSION"
git pull --rebase
git push origin static-site
fi
echo "Assets version for this release: $NEW_ASSETS_VERSION"
mkdir -p assets_version
echo $NEW_ASSETS_VERSION > assets_version/assets_version.txt
working-directory: public/static
env:
BASE_ASSETS_VERSION: main
# Uploads an empty file just so we have something to download in the next step
# Essentially a no-op.
- name: Prepare assets for stable release
if: ${{ ! contains(github.event.inputs.version, 'rc') || startsWith(github.ref, 'refs/heads/release/') }}
run: |
mkdir -p assets_version
echo "" > assets_version/assets_version.txt
- name: Upload assets version
uses: actions/upload-artifact@v2
with:
name: assets-version
path: public/static/assets_version
# Generate the changelog before we do any commits.
changelog:
name: Changelog
runs-on: ubuntu-latest
timeout-minutes: 60
needs: [checks]
outputs:
release_name: ${{ steps.changelog.outputs.release_name }}
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0 # 0 indicates all history for all branches and tags.
- name: Read .nvmrc
run: echo "##[set-output name=NVMRC;]$(cat .nvmrc)"
id: nvm
- name: Setup Node
uses: actions/setup-node@v2.2.0
with:
node-version: ${{ steps.nvm.outputs.NVMRC }}
cache: npm
- name: Install dependencies
run: npm ci
env:
CI: true
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true
# For release candidates, generate changelog since last tag (stable release or previous RC)
# For stable releases, generate full changelog since last stable release.
# TODO: Implement tag logic for patch releases.
- name: Generate changelog
id: changelog
run: |
TAG_NAME_WITHOUT_SUFFIX=${TAG_NAME/-rc.*/}
if $IS_RC; then
# Get the most recent tag.
# Note: This will return v1.4.0-rc.1 as it is listed before v1.4.0
PREVIOUS_TAG=$(git tag -l --sort=-version:refname | grep --invert-match $TAG_NAME | head -1)
# If this is the first RC for this version (e.g. v1.5.0-rc.1), the previous version is v1.4.0, without suffix.
if [[ $TAG_NAME == *".rc.1" ]]; then
PREVIOUS_TAG=${PREVIOUS_TAG/-rc.*/}
fi
else
# This will return v1.4.0-rc.1 as it is listed before v1.4.0
PREVIOUS_TAG=$(git tag -l --sort=-version:refname | grep --invert-match $TAG_NAME_WITHOUT_SUFFIX | head -1)
PREVIOUS_TAG=${PREVIOUS_TAG/-rc.*/}
fi
RELEASE_NAME=${PLUGIN_VERSION/-rc./ RC}
echo "Gathering list of changes since $PREVIOUS_TAG..."
echo "Release name: $RELEASE_NAME"
CHANGELOG=$(npm run workflow:changelog --silent -- --next-version=$RELEASE_NAME --from=$PREVIOUS_TAG)
if [[ -z $CHANGELOG ]]; then
echo "Warning: Changelog is empty, probably because there were no changes since the last release."
CHANGELOG="No merged changes since last release."
fi
mkdir -p build/changelog
echo "$CHANGELOG" >> build/changelog/changelog.txt
echo "::set-output name=release_name::${RELEASE_NAME}"
env:
GITHUB_AUTH: ${{ secrets.PLUGIN_RELEASE_ACCESS_TOKEN }}
- name: Upload artifacts
uses: actions/upload-artifact@v2
with:
name: changelog
path: build/changelog
build:
name: Build new version
runs-on: ubuntu-latest
timeout-minutes: 60
needs: [assets-version]
outputs:
release_branch: ${{ steps.release_branch.outputs.release_branch }}
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0 # 0 indicates all history for all branches and tags.
token: ${{ secrets.PLUGIN_RELEASE_ACCESS_TOKEN }}
- name: Download assets version
uses: actions/download-artifact@v2
with:
name: assets-version
continue-on-error: true
- name: Retrieve assets version
id: assets_version
run: |
echo "::set-output name=ASSETS_VERSION::$(cat assets_version.txt)"
rm -rf assets_version.txt
continue-on-error: true
- name: Read .nvmrc
run: echo "##[set-output name=NVMRC;]$(cat .nvmrc)"
id: nvm
- name: Setup Node
uses: actions/setup-node@v2.2.0
with:
node-version: ${{ steps.nvm.outputs.NVMRC }}
cache: npm
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '7.4'
coverage: none
tools: composer
- name: Get Composer cache directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Setup Composer cache
uses: pat-s/always-upload-cache@v2.1.5
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-
${{ runner.os }}-
- name: Install dependencies
run: |
npm ci
composer install --prefer-dist --no-progress --no-interaction
env:
CI: true
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true
- name: Create release branch
id: release_branch
run: |
VERSION_WITHOUT_SUFFIX=${PLUGIN_VERSION/-rc.*/}
BRANCH=release/$VERSION_WITHOUT_SUFFIX
# Patch releases are already on the correct branch.
if $IS_PATCH_RELEASE; then
BRANCH=${GITHUB_REF#refs/heads/}
echo "::set-output name=release_branch::${BRANCH}"
exit 0
fi
if [[ -z $(git ls-remote origin $BRANCH) ]]; then
git checkout -b $BRANCH
else
git checkout --track origin/$BRANCH
fi
echo "::set-output name=release_branch::${BRANCH/-rc./ RC}"
- name: Update assets version
run: npm run workflow:assets-version $ASSETS_VERSION
if: ${{ env.ASSETS_VERSION }}
env:
ASSETS_VERSION: ${{ steps.assets_version.outputs.ASSETS_VERSION }}
- name: Commit assets version bump
run: |
git add web-stories.php
git status
git diff --staged --quiet && echo 'No changes to commit; exiting!' && exit 0
git commit -m "Update assets version to $ASSETS_VERSION"
git push -u origin HEAD
if: ${{ env.ASSETS_VERSION }}
env:
ASSETS_VERSION: ${{ steps.assets_version.outputs.ASSETS_VERSION }}
- name: Update plugin version
run: npm run workflow:version $PLUGIN_VERSION
- name: Commit plugin version bump
run: |
git add web-stories.php
git status
git diff --staged --quiet && echo 'No changes to commit; exiting!' && exit 1
git commit -m "Prepare release $PLUGIN_VERSION"
git push -u origin HEAD
# Only non-patch release version bumps should be cherry picked to main
# This will cherry-pick the last commit from the release branch, as
# we only want the plugin version bump, not the assets version bump.
- name: Cherry-pick to main
run: |
git checkout main
git cherry-pick $BRANCH
git pull --rebase
git push
git checkout $BRANCH
if: ${{ ! startsWith(github.ref, 'refs/heads/release/') }}
env:
BRANCH: ${{ steps.release_branch.outputs.release_branch }}
- name: Build plugin
run: npm run build:js
- name: Bundle regular version
run: npm run workflow:build-plugin -- --zip web-stories.zip
- name: Bundle development version
run: |
rm -rf assets/css/* assets/js/*
NODE_ENV=development npx webpack --config webpack.config.cjs
npm run workflow:build-plugin -- --zip web-stories-dev.zip
- name: Prepare release artifacts
run: |
mkdir -p build/release-assets
mv build/*.zip build/release-assets/
- name: Upload artifacts
uses: actions/upload-artifact@v2
with:
name: release-assets
path: build/release-assets
create-release:
name: Create Release
runs-on: ubuntu-latest
timeout-minutes: 60
needs: [build, changelog]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Download release artifacts
uses: actions/download-artifact@v2
with:
name: release-assets
path: build
- name: Download changelog
uses: actions/download-artifact@v2
with:
name: changelog
path: changelog
- name: Set branch name
id: release_branch
run: |
VERSION_WITHOUT_SUFFIX=${PLUGIN_VERSION/-rc.*/}
BRANCH=release/$VERSION_WITHOUT_SUFFIX
echo "::set-output name=RELEASE_BRANCH::${BRANCH/-rc./ RC}"
# TODO: Replace with maintained action.
- name: Create Release Draft
id: create_release
uses: actions/create-release@v1
with:
tag_name: ${{ env.TAG_NAME }}
release_name: ${{ needs.changelog.outputs.release_name }}
commitish: ${{ needs.build.outputs.release_branch || github.ref }}
draft: true
prerelease: ${{ env.IS_RC }}
body_path: changelog/changelog.txt
env:
GITHUB_TOKEN: ${{ secrets.PLUGIN_RELEASE_ACCESS_TOKEN }}
- name: Upload regular bundle
uses: actions/upload-release-asset@v1.0.2
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: build/web-stories.zip
asset_name: web-stories.zip
asset_content_type: application/zip
env:
GITHUB_TOKEN: ${{ secrets.PLUGIN_RELEASE_ACCESS_TOKEN }}
- name: Upload development bundle
uses: actions/upload-release-asset@v1.0.2
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: build/web-stories-dev.zip
asset_name: web-stories-dev.zip
asset_content_type: application/zip
env:
GITHUB_TOKEN: ${{ secrets.PLUGIN_RELEASE_ACCESS_TOKEN }}
# Done so that any triggers/webhooks will have access to the published release
# including all the release assets.
- name: Publish Release
run: |
curl \
--request PATCH \
--url https://api.github.com/repos/${{ github.repository }}/releases/${{ steps.create_release.outputs.id }} \
--header 'Authorization: token ${{ secrets.PLUGIN_RELEASE_ACCESS_TOKEN }}' \
--header "Accept: application/vnd.github.v3+json" \
--data-raw '{"draft":false}'
# Post-release version bumps for non-patch releases.
post-release:
name: Post-release version bump
needs: [create-release]
runs-on: ubuntu-latest
if: ${{ ! startsWith(github.ref, 'refs/heads/release/') }}
steps:
- name: Checkout
uses: actions/checkout@v2
with:
ref: main
token: ${{ secrets.PLUGIN_RELEASE_ACCESS_TOKEN }}
- name: Read .nvmrc
run: echo "##[set-output name=NVMRC;]$(cat .nvmrc)"
id: nvm
- name: Setup Node
uses: actions/setup-node@v2.2.0
with:
node-version: ${{ steps.nvm.outputs.NVMRC }}
cache: npm
- name: Install dependencies
run: npm ci
env:
CI: true
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true
# If we're releasing 1.6.0, bump version on main to 1.7.0-alpha.0.
- name: Update plugin version
run: npm run workflow:version -- --increment preminor --preid alpha
- name: Commit changes
run: |
git add web-stories.php
git status
git diff --staged --quiet && echo 'No changes to commit; exiting!' && exit 1
git commit -m "Post-release version bump"
git pull --rebase
git push -u origin HEAD
# Stable releases are automatically deployed to WordPress.org.
# TODO: Consider also deploying other types of releases (RC, beta), but without bumping the stable tag.
# This way we could offer users a way to beta test the plugin.
# See http://plugins.svn.wordpress.org/buddypress/tags/ and https://wordpress.org/plugins/bp-beta-tester/ for inspiration.
deploy:
name: Deploy plugin to WordPress.org
runs-on: ubuntu-latest
timeout-minutes: 60
needs: [create-release]
# This step requires additional review
# See https://docs.github.com/en/actions/reference/environments
environment: Production
if: ${{ ! contains(github.event.inputs.version, 'rc') }}
env:
PLUGIN_REPO_URL: 'https://plugins.svn.wordpress.org/web-stories'
STABLE_TAG_REGEX: 'Stable tag:\s*(.+)'
SVN_USERNAME: ${{ secrets.SVN_USERNAME }}
SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }}
steps:
- name: Download release artifacts
uses: actions/download-artifact@v2
with:
name: release-assets
path: release-assets
- name: Check out trunk folder
run: svn checkout $PLUGIN_REPO_URL svn --username "$SVN_USERNAME"
- name: Get previous stable tag
id: get_previous_stable_tag
# Returns the whole matching line.
run: echo ::set-output name=stable_tag::$(grep -P "$STABLE_TAG_REGEX" ./svn/trunk/readme.txt)
- name: Delete everything in trunk
run: find . -maxdepth 1 -not -name ".svn" -not -name "." -not -name ".." -exec rm -rf {} +
working-directory: ./svn/trunk
- name: Unzip release asset into trunk
run: |
unzip release-assets/web-stories.zip
mv web-stories/* svn/trunk
env:
PLUGIN_URL: ${{ github.event.release.assets[0].browser_download_url }}
- name: Replace stable tag placeholder with pre-existing stable tag
run: |
sed -r -i "s/${STABLE_TAG_REGEX}/${STABLE_TAG}/g" ./readme.txt
working-directory: ./svn/trunk
env:
STABLE_TAG: ${{ steps.get_previous_stable_tag.outputs.stable_tag }}
# Note: Creating the tag trigger an email confirmation that needs to be confirmed by someone with commit access.
# Making changes to trunk and creating the tag is done in the same commit.
# See https://developer.wordpress.org/plugins/wordpress-org/how-to-use-subversion/#create-tags-from-trunk
- name: Commit changes and create tag
run: |
svn st | grep '^?' | awk '{print $2}' | xargs -r svn add
svn st | grep '^!' | awk '{print $2}' | xargs -r svn rm
svn cp trunk "tags/$PLUGIN_VERSION"
svn commit -m "Committing version $PLUGIN_VERSION" \
--no-auth-cache --non-interactive --username "$SVN_USERNAME" --password "$SVN_PASSWORD"
working-directory: ./svn
# It's recommended to run this only after the tag was successfully created.
# Otherwise, if there were any errors, we risk changing this to a tag that doesn't exist.
# TODO: Move to separate workflow that can be manually triggered after email confirmation?
- name: Update stable tag
working-directory: ./svn
run: |
sed -r -i "s/${STABLE_TAG_REGEX}/Stable tag: ${PLUGIN_VERSION}/g" ./trunk/readme.txt
svn commit -m "Releasing version $PLUGIN_VERSION" \
--no-auth-cache --non-interactive --username "$SVN_USERNAME" --password "$SVN_PASSWORD"