Skip to content

Commit

Permalink
Release Workflow: Allow triggering manually (#28138)
Browse files Browse the repository at this point in the history
Allow manual triggering of the workflow to create a new release, per [this discussion](#27488 (comment)).

The end goal is for the release manager to run the entire release process from GitHub, and to minimize manual interaction.
- ✋ Release manager starts release process manually.
- 🤖 GitHub workflow bumps version numbers in plugin files, builds Gutenberg plugin, creates release draft, and prefills it with release notes based on changelog script output.
- ✋ Release manager edits release draft, and eventually publishes it. This creates the tag.
- 🤖 (Other) GitHub workflow prepends release notes to `changelog.txt`, uploads Gutenberg plugin and updated `changelog.txt` to WP.org plugin repo.

Functionally, this is as close as possible to the previous workflow. The major difference is that `changelog.txt` is only updated _after_ tagging. This is a result of using the GitHub release draft UI to edit and revise release notes. It's not possible to include the result of those changes _before_ tagging.

Release docs are updated to reflect these changes. The previously used local release script is removed.
  • Loading branch information
ockham committed Mar 18, 2021
1 parent 3f42c28 commit 526099c
Show file tree
Hide file tree
Showing 6 changed files with 251 additions and 768 deletions.
143 changes: 130 additions & 13 deletions .github/workflows/build-plugin-zip.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,111 @@ on:
- '**.md'
push:
branches: [trunk]
tags:
- 'v*'
paths-ignore:
- '**.md'
workflow_dispatch:
inputs:
version:
description: 'rc or stable?'
required: true

jobs:
bump-version:
name: Bump version
runs-on: ubuntu-latest
if: |
github.event_name == 'workflow_dispatch' &&
github.ref == 'refs/heads/trunk' && (
github.event.inputs.version == 'rc' ||
github.event.inputs.version == 'stable'
)
outputs:
old_version: ${{ steps.get_version.outputs.old_version }}
new_version: ${{ steps.get_version.outputs.new_version }}
release_branch: ${{ steps.get_version.outputs.release_branch }}
steps:
- name: Checkout code
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4

- name: Compute old and new version
id: get_version
run: |
OLD_VERSION=$(jq --raw-output '.version' package.json)
echo "::set-output name=old_version::$(echo $OLD_VERSION)"
if [[ ${{ github.event.inputs.version }} == 'stable' ]]; then
NEW_VERSION=$(npx semver $OLD_VERSION -i patch)
else
if [[ $OLD_VERSION == *"rc"* ]]; then
NEW_VERSION=$(npx semver $OLD_VERSION -i prerelease)
else
# WordPress version guidelines: If minor is 9, bump major instead.
IFS='.' read -r -a OLD_VERSION_ARRAY <<< "$OLD_VERSION"
if [[ ${OLD_VERSION_ARRAY[1]} == "9" ]]; then
NEW_VERSION="$(npx semver $OLD_VERSION -i major)-rc.1"
else
NEW_VERSION="$(npx semver $OLD_VERSION -i minor)-rc.1"
fi
fi
fi
echo "::set-output name=new_version::$(echo $NEW_VERSION)"
IFS='.' read -r -a NEW_VERSION_ARRAY <<< "$NEW_VERSION"
RELEASE_BRANCH="release/${NEW_VERSION_ARRAY[0]}.${NEW_VERSION_ARRAY[1]}"
echo "::set-output name=release_branch::$(echo $RELEASE_BRANCH)"
- name: Configure git user name and email
run: |
git config user.name "Gutenberg Repository Automation"
git config user.email gutenberg@wordpress.org
- name: Create and switch to release branch
if: |
github.event.inputs.version == 'rc' &&
! contains( steps.get_version.outputs.old_version, 'rc' )
run: git checkout -b "${{ steps.get_version.outputs.release_branch }}"

- name: Switch to release branch
if: |
github.event.inputs.version == 'stable' ||
contains( steps.get_version.outputs.old_version, 'rc' )
run: |
git fetch --depth=1 origin "${{ steps.get_version.outputs.release_branch }}"
git checkout "${{ steps.get_version.outputs.release_branch }}"
- name: Update plugin version
env:
VERSION: ${{ steps.get_version.outputs.new_version }}
run: |
cat <<< $(jq --tab --arg version "${VERSION}" '.version = $version' package.json) > package.json
cat <<< $(jq --tab --arg version "${VERSION}" '.version = $version' package-lock.json) > package-lock.json
sed -i "s/${{ steps.get_version.outputs.old_version }}/${VERSION}/g" gutenberg.php
sed -i "s/${{ steps.get_version.outputs.old_version }}/${VERSION}/g" readme.txt
- name: Commit the version bump
run: |
git add gutenberg.php package.json package-lock.json readme.txt
git commit -m "Bump plugin version to ${{ steps.get_version.outputs.new_version }}"
git push --set-upstream origin "${{ steps.get_version.outputs.release_branch }}"
- name: Cherry-pick to trunk
run: |
git checkout trunk
TRUNK_VERSION=$(jq --raw-output '.version' package.json)
if [[ ${{ steps.get_version.outputs.old_version }} == "$TRUNK_VERSION" ]]; then
git cherry-pick "${{ steps.get_version.outputs.release_branch }}"
git push
fi
build:
name: Build Release Artifact
runs-on: ubuntu-latest
needs: bump-version
if: always()
steps:
- name: Checkout code
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
with:
ref: ${{ needs.bump-version.outputs.release_branch || github.ref }}

- name: Cache node modules
uses: actions/cache@26968a09c0ea4f3e233fdddbafd1166051a095f6 # v2.1.4
Expand Down Expand Up @@ -48,38 +141,62 @@ jobs:
name: gutenberg-plugin
path: ./gutenberg.zip

- name: Build release notes draft
if: ${{ needs.bump-version.outputs.new_version }}
env:
VERSION: ${{ needs.bump-version.outputs.new_version }}
run: |
IFS='.' read -r -a VERSION_ARRAY <<< "${VERSION}"
MILESTONE="Gutenberg ${VERSION_ARRAY[0]}.${VERSION_ARRAY[1]}"
npm run changelog -- --milestone="$MILESTONE" --unreleased > release-notes.txt
sed -ie '1,6d' release-notes.txt
if [[ ${{ needs.bump-version.outputs.new_version }} != *"rc"* ]]; then
# Include previous RCs' release notes, if any
CHANGELOG_REGEX="=\s[0-9]+\.[0-9]+\.[0-9]+(-rc\.[0-9]+)?\s="
RC_REGEX="=\s${VERSION}(-rc\.[0-9]+)?\s="
awk "/${RC_REGEX}/ {found=1;print;next} /${CHANGELOG_REGEX}/ {found=0} found" changelog.txt >> release-notes.txt
fi
- name: Upload release notes artifact
if: ${{ needs.bump-version.outputs.new_version }}
uses: actions/upload-artifact@e448a9b857ee2131e752b06002bf0e093c65e571 # v2.2.2
with:
name: release-notes
path: ./release-notes.txt

create-release:
name: Create Release Draft and Attach Asset
needs: build
needs: [bump-version, build]
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
steps:
- name: Set Release Version
id: get_release_version
run: echo ::set-output name=version::$(echo $GITHUB_REF | cut -d / -f 3 | sed s/^v// | sed 's/-rc./ RC/' )
env:
VERSION: ${{ needs.bump-version.outputs.new_version }}
run: echo ::set-output name=version::$(echo $VERSION | cut -d / -f 3 | sed 's/-rc./ RC/' )

- name: Download Plugin Zip Artifact
uses: actions/download-artifact@4a7a711286f30c025902c28b541c10e147a9b843 # v2.0.8
with:
name: gutenberg-plugin

- name: Extract Changelog for Release
run: |
unzip gutenberg.zip changelog.txt
CHANGELOG_REGEX="/=\s[0-9]+\.[0-9]+\.[0-9]+(-rc\.[0-9]+)?\s=/"
awk -i inplace "$CHANGELOG_REGEX"'{p++;next} p==2{exit} p>=1' changelog.txt
- name: Download Release Notes Artifact
uses: actions/download-artifact@4a7a711286f30c025902c28b541c10e147a9b843 # v2.0.8
with:
name: release-notes

- name: Create Release Draft
id: create_release
uses: actions/create-release@0cb9c9b65d5d1901c1f53e5e66eaf4afd303e70e # v1.1.4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
tag_name: "v${{ needs.bump-version.outputs.new_version }}"
release_name: ${{ steps.get_release_version.outputs.version }}
commitish: ${{ needs.bump-version.outputs.release_branch || github.ref }}
draft: true
prerelease: ${{ contains(github.ref, 'rc') }}
body_path: changelog.txt
prerelease: ${{ contains(needs.bump-version.outputs.new_version, 'rc') }}
body_path: release-notes.txt

- name: Upload Release Asset
id: upload-release-asset
Expand Down
109 changes: 99 additions & 10 deletions .github/workflows/upload-release-to-plugin-repo.yml
Original file line number Diff line number Diff line change
@@ -1,28 +1,111 @@
name: Update Changelog and upload Gutenberg plugin to WordPress.org plugin repo

on:
release:
types: [released]

name: Upload Gutenberg plugin to WordPress.org plugin repo
types: [published]

jobs:
get-release-branch:
name: Get release branch name
runs-on: ubuntu-latest
if: github.event.release.assets[0]
outputs:
release_branch: ${{ steps.get_release_branch.outputs.release_branch }}
steps:
- name: Compute release branch name
id: get_release_branch
env:
TAG: ${{ github.event.release.tag_name }}
run: |
IFS='.' read -r -a VERSION_ARRAY <<< "${TAG#v}"
RELEASE_BRANCH="release/${VERSION_ARRAY[0]}.${VERSION_ARRAY[1]}"
echo "::set-output name=release_branch::$(echo $RELEASE_BRANCH)"
update-changelog:
name: Update Changelog on ${{ matrix.branch }} branch
runs-on: ubuntu-latest
if: github.event.release.assets[0]
needs: get-release-branch
env:
TAG: ${{ github.event.release.tag_name }}
strategy:
matrix:
include:
- branch: trunk
label: trunk
- branch: ${{ needs.get-release-branch.outputs.release_branch }}
label: release
steps:
- name: Checkout code
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
with:
ref: ${{ matrix.branch }}

- name: Update the Changelog to include the release notes
run: |
# First, determine where to insert the new Changelog entry.
SERIES="${RELEASE_BRANCH#release/}"
SERIES_REGEX="=\s${SERIES}\.[0-9]+\s="
CUT_MARKS=$( grep -nP -m 1 "${SERIES_REGEX}" changelog.txt | cut -d: -f1 )
if [[ -z "${CUT_MARKS}" ]]; then
CHANGELOG_REGEX="=\s[0-9]+\.[0-9]+\.[0-9]+(-rc\.[0-9]+)?\s="
RC_REGEX="=\s${TAG#v}(-rc\.[0-9]+)?\s="
CUT_MARKS=$( awk "/${RC_REGEX}/ {print NR; next}; /${CHANGELOG_REGEX}/ {print NR; exit}" changelog.txt )
fi
BEFORE=$( echo "$CUT_MARKS" | head -n 1 )
AFTER=$( echo "$CUT_MARKS" | tail -n 1 )
# Okay, we have all we need to build the new Changelog.
head -n $(( "${BEFORE}" - 1 )) changelog.txt > new_changelog.txt
printf '= %s =\n\n' "${TAG#v}" >> new_changelog.txt
# Need to use a heredoc in order to preserve special characters.
cat <<- "EOF" > release_notes.txt
${{ github.event.release.body }}
EOF
# Normalize empty lines: Trim them from beginning and end of file...
awk 'NF {p=1} p' <<< "$(< release_notes.txt)" >> new_changelog.txt
# ...then add two empty lines at the end.
printf '\n\n' >> new_changelog.txt
tail -n +"${AFTER}" changelog.txt >> new_changelog.txt
mv new_changelog.txt changelog.txt
- name: Configure git user name and email
run: |
git config user.name "Gutenberg Repository Automation"
git config user.email gutenberg@wordpress.org
- name: Commit the Changelog update
run: |
git add changelog.txt
git commit -m "Update Changelog for ${TAG#v}"
git push --set-upstream origin "${{ matrix.branch }}"
- name: Upload Changelog artifact
uses: actions/upload-artifact@e448a9b857ee2131e752b06002bf0e093c65e571 # v2.2.2
with:
name: changelog ${{ matrix.label }}
path: ./changelog.txt

upload:
name: Upload Gutenberg Plugin
runs-on: ubuntu-latest
environment: wp.org plugin
if: github.event.release.assets[0]
needs: update-changelog
if: ${{ !github.event.release.prerelease && github.event.release.assets[0] }}
env:
PLUGIN_REPO_URL: 'https://plugins.svn.wordpress.org/gutenberg'
STABLE_TAG_REGEX: 'Stable tag: [0-9]\+\.[0-9]\+\.[0-9]\+\s*'
STABLE_VERSION_REGEX: '[0-9]\+\.[0-9]\+\.[0-9]\+\s*'
SVN_USERNAME: ${{ secrets.svn_username }}
SVN_PASSWORD: ${{ secrets.svn_password }}
VERSION: ${{ github.event.release.name }}
steps:
- name: Check out Gutenberg trunk from WP.org plugin repo
run: svn checkout "$PLUGIN_REPO_URL/trunk"

- name: Get previous stable tag
id: get_previous_stable_tag
run: echo ::set-output name=stable_tag::$(grep "$STABLE_TAG_REGEX" ./trunk/readme.txt)
- name: Get previous stable version
id: get_previous_stable_version
env:
STABLE_TAG_REGEX: 'Stable tag: \K${{ env.STABLE_VERSION_REGEX }}'
run: echo ::set-output name=stable_version::$(grep -oP "${STABLE_TAG_REGEX}" ./trunk/readme.txt)

- name: Delete everything
working-directory: ./trunk
Expand All @@ -39,9 +122,15 @@ jobs:
- name: Replace the stable tag placeholder with the existing stable tag on the SVN repository
env:
STABLE_TAG_PLACEHOLDER: 'Stable tag: V\.V\.V'
STABLE_TAG: ${{ steps.get_previous_stable_tag.outputs.stable_tag }}
STABLE_TAG: 'Stable tag: ${{ steps.get_previous_stable_version.outputs.stable_version }}'
run: sed -i "s/${STABLE_TAG_PLACEHOLDER}/${STABLE_TAG}/g" ./trunk/readme.txt

- name: Download Changelog Artifact
uses: actions/download-artifact@4a7a711286f30c025902c28b541c10e147a9b843 # v2.0.8
with:
name: changelog trunk
path: trunk

- name: Commit the content changes
working-directory: ./trunk
run: |
Expand All @@ -59,6 +148,6 @@ jobs:
- name: Update the plugin's stable version
working-directory: ./trunk
run: |
sed -i "s/${STABLE_TAG_REGEX}/Stable tag: ${VERSION}/g" ./readme.txt
sed -i "s/Stable tag: ${STABLE_VERSION_REGEX}/Stable tag: ${VERSION}/g" ./readme.txt
svn commit -m "Releasing version $VERSION" \
--no-auth-cache --non-interactive --username "$SVN_USERNAME" --password "$SVN_PASSWORD"
13 changes: 0 additions & 13 deletions bin/plugin/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,13 @@ const catchException = ( command ) => {
/**
* Internal dependencies
*/
const { releaseRC, releaseStable } = require( './commands/release' );
const {
publishNpmLatestDistTag,
publishNpmNextDistTag,
} = require( './commands/packages' );
const { getReleaseChangelog } = require( './commands/changelog' );
const { runPerformanceTests } = require( './commands/performance' );

program
.command( 'release-plugin-rc' )
.alias( 'rc' )
.description( 'Release an RC version of the plugin' )
.action( catchException( releaseRC ) );

program
.command( 'release-plugin-stable' )
.alias( 'stable' )
.description( 'Release a stable version of the plugin' )
.action( catchException( releaseStable ) );

program
.command( 'publish-npm-packages-latest' )
.alias( 'npm-latest' )
Expand Down
Loading

0 comments on commit 526099c

Please sign in to comment.