Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an action and a GitHub workflow to get release notes via GitHub and prepare release content. #16

Merged
merged 10 commits into from
Jun 23, 2022
81 changes: 81 additions & 0 deletions .github/workflows/github-actions-prepare-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: GitHub Actions - Prepare New Release

on:
push:
branches:
- release/actions

jobs:
CheckCreatedBranch:
name: Check Created Branch
runs-on: ubuntu-latest
steps:
- name: Check created release branch
uses: actions/github-script@v6
with:
script: |
if ( ! context.payload.created ) {
await github.rest.actions.cancelWorkflowRun( {
...context.repo,
run_id: context.runId,
} );
}

PrepareRelease:
name: Prepare Release
runs-on: ubuntu-latest
needs: CheckCreatedBranch
steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Prepare node
uses: ./packages/js/github-actions/actions/prepare-node
with:
node-version: 14
cache-dependency-path: ./packages/js/github-actions/package-lock.json
install-deps: "no"

# The checkout revision of this repo itself doesn't have the built actions,
# so it needs to build them before using it locally.
- name: Build actions
run: |
cd ./packages/js/github-actions
npm ci --ignore-scripts
npm run build
cd -

- name: Get release notes
id: get-notes
uses: ./packages/js/github-actions/actions/get-release-notes
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
package-dir: packages/js/github-actions
config-path: packages/js/github-actions/release-notes-config.yml
tag-template: "actions-v{version}"
minor-keywords: feature, update, enhancement

- name: Prepare release commits
# Use the github-actions bot account to commit.
# https://api.github.com/users/github-actions%5Bbot%5D
run: |
cd ./packages/js/github-actions
TODAY=$(date '+%Y-%m-%d')
NEXT_VER="${{ steps.get-notes.outputs.next-version }}"
CHANGELOG="${{ steps.get-notes.outputs.release-changelog }}"
CHANGELOG=$(echo "$CHANGELOG" | sed -E 's/\.? by @[^ ]+ in (https:\/\/github\.com\/.+)/. (\1)/')
Copy link
Member

@tomalec tomalec Jun 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚧 If we remove the PR authors and links, I think we should also remove the

## New Contributors

section. (See https://github.com/woorelease-bugs/initial-release/releases/new?tag=1.0.1 fro an example)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The outputs.release-changelog output only contains the part of "## What's Changed" heading and its entries. So other contents won't be included. I added output logs in the get-release-notes action by dd0226a. It should be easier to know the actual values of outputs and to use them.

image

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, ok, now I got it.
/## What's Changed\n([\d\D]+?)(?=\n\n)/i catches all the things before the double line break => before

##New Constributors

sed -i "/# Changelog/r"<(
printf "\n## ${TODAY} (${NEXT_VER})\n${CHANGELOG}\n"
) CHANGELOG.md
jq ".version=\"${NEXT_VER}\"" package.json > package.json.tmp
mv package.json.tmp package.json
jq ".version=\"${NEXT_VER}\"" package-lock.json > package-lock.json.tmp
mv package-lock.json.tmp package-lock.json
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
git add CHANGELOG.md
git add package.json
git add package-lock.json
cd -
git commit -q -m "Update changelog and package version for the ${{ steps.get-notes.outputs.next-tag }} release of GitHub actions."
git push
1 change: 1 addition & 0 deletions packages/js/github-actions/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Changelog
19 changes: 12 additions & 7 deletions packages/js/github-actions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Custom GitHub actions that help to composite GitHub workflows across the repos m

## Actions list

- [`get-release-notes`](actions/get-release-notes) - Get release notes via GitHub, infer the next version and tag
- [`prepare-mysql`](actions/prepare-mysql) - Enable MySQL, handle authentication compatibility
- [`prepare-node`](actions/prepare-node) - Set up Node.js with a specific version, load npm cache, install Node dependencies
- [`prepare-php`](actions/prepare-php) - Set up PHP with a specific version and tools, load Composer cache, install Composer dependencies
Expand Down Expand Up @@ -94,32 +95,36 @@ gitGraph
branch release/actions order: 1
commit id: "Changelog"
commit id: "Bump version"
checkout trunk
merge release/actions
branch tmp/release-build order: 0
commit id: "Release build" type: HIGHLIGHT tag: "actions-v1.2.3"
checkout trunk
commit
merge release/actions

```

## Release

### Official release

1. Find the latest version tag of GitHub actions in this repo. For example, `actions-v1.4.7`.
1. Create a new release with a new version tag that increases numerically in the format `actions-vX.Y.Z`.
1. Create the specific branch `release/actions` onto the target revision on `trunk` branch.
1. The ["GitHub Actions - Prepare New Release" workflow](https://github.com/woocommerce/grow/actions/workflows/github-actions-prepare-release.yml) will continue to prepend changelog to [CHANGELOG.md](CHANGELOG.md), update versions to [package.json](package.json) and [package-lock.json](package-lock.json), and then commit the changes to `release/actions` branch.
1. Create a release PR from `release/actions` branch with `trunk` as the base branch.
1. Check if the new changelog content and updated version are correct.
- For a patch version like fixing bugs, increases the Z number. For example, `actions-v1.4.8`.
- For a minor version like adding new features, increases the Y number and reset the Z to 0. For example, `actions-v1.5.0`.
- For a major version like having incompatible changes, increases the X number and reset the Y and Z to 0. For example, `actions-v2.0.0`.
1. Create a new release with a new version tag.
1. Check if the ["GitHub Actions - Release" workflow](https://github.com/woocommerce/grow/actions/workflows/github-actions-release.yml) is run successfully.
1. After publishing the new release, the "GitHub Actions - Release" workflow of the GitHub Actions in this repo will continue the creating and committing the release build. And then update the references of the corresponding major and minor version tags onto the new release. For example:
- When the new release version is `actions-v1.4.8`, it should update the references of `actions-v1` and `actions-v1.4` onto `actions-v1.4.8`.
- When the new release version is `actions-v1.5.0`, it should update the reference of `actions-v1` and create `actions-v1.5` tag onto `actions-v1.5.0`.
- When the new release version is `actions-v2.0.0`, it should create `actions-v2` and `actions-v2.0` tags onto `actions-v2.0.0`.
1. Check if the ["GitHub Actions - Release" workflow](https://github.com/woocommerce/grow/actions/workflows/github-actions-release.yml) is run successfully.
1. Merge the release PR.

### Testing release

1. Basically use the same processing as the [Official release](#official-release) above, :warning: **but the format of version tag should be `actions-vX.Y.Z-pre`**.
1. Create a new release with a **prerelease version tag**. For example `actions-vX.Y.Z-pre`.
1. Check if the ["GitHub Actions - Release" workflow](https://github.com/woocommerce/grow/actions/workflows/github-actions-release.yml) is run successfully.
1. Delete the testing releases and tags once they are no longer in use.

<p align="center">
Expand Down
163 changes: 163 additions & 0 deletions packages/js/github-actions/actions/get-release-notes/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
# Get release notes via GitHub API in GitHub Actions

This action provides the following functionality for GitHub Actions users:

- Get release notes via GitHub
- Based on package.json, infer the next release version and tag by matching keywords to release notes

## Usage

See [action.yml](action.yml)

#### Basic:

```yaml
on:
push:
branches:
- release/my-tool

EchoRelease:
name: Echo Release
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Get release notes
id: get-notes
uses: ./packages/js/github-actions/actions/get-release-notes
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
tag-template: "v{version}"

- name: Echo release notes
run: |
echo "${{ steps.get-notes.outputs.release-notes }}"
echo "${{ steps.get-notes.outputs.release-changelog }}"
```

#### Matching version level keywords to infer the next version and tag:

Create a [configuration for the changelog categories](https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes#configuring-automatically-generated-release-notes) at `.github/release.yml` in the repository. For example:

```yaml
# .github/release.yml

changelog:
categories:
# Major level
- title: Major Changes
- major
- title: Breaking Changes
labels:
- breaking

# Minor level
- title: Exciting New Features
labels:
- feature
- title: Improvements
labels:
- improvement

# Patch level
- title: Other Changes
labels:
- "*"
```

Matching the `title` by keywords in each level:

```yaml
# A GitHub workflow

on:
push:
branches:
- release/my-tool

jobs:
EchoRelease:
name: Echo Release
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Get release notes
id: get-notes
uses: ./packages/js/github-actions/actions/get-release-notes
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
tag-template: "v{version}"
major-keywords: major changes, breaking
minor-keywords: new Features, improvement

- name: Echo release notes
run: |
echo "${{ steps.get-notes.outputs.release-notes }}"
echo "${{ steps.get-notes.outputs.release-changelog }}"
echo "${{ steps.get-notes.outputs.next-version }}"
echo "${{ steps.get-notes.outputs.next-tag }}"
```

Once any of changelog headings (`###` syntax in Markdown) in release notes has a single word starting with the same keyword, the level is matched. If both major and minor cannot be matched, it falls back to patch level. The matched level will be used to determine the next version number.

#### Prepare release commits:

```yaml
on:
push:
branches:
- release/my-tool

jobs:
CheckCreatedBranch:
name: Check Created Branch
runs-on: ubuntu-latest
steps:
- name: Check created release branch
uses: actions/github-script@v6
with:
script: |
if ( ! context.payload.created ) {
await github.rest.actions.cancelWorkflowRun( {
...context.repo,
run_id: context.runId,
} );
}

PrepareRelease:
name: Prepare Release
runs-on: ubuntu-latest
needs: CheckCreatedBranch
steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Get release notes
id: get-notes
uses: ./packages/js/github-actions/actions/get-release-notes
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
tag-template: "v{version}"

- name: Prepare release commits
run: |
TODAY=$(date '+%Y-%m-%d')
NEXT_VER="${{ steps.get-notes.outputs.next-version }}"
CHANGELOG="${{ steps.get-notes.outputs.release-changelog }}"
printf "## ${TODAY} (${NEXT_VER})\n${CHANGELOG}\n\n%s\n" "$(cat CHANGELOG.md)" > CHANGELOG.md
jq ".version=\"${NEXT_VER}\"" package.json > package.json.tmp
mv package.json.tmp package.json
jq ".version=\"${NEXT_VER}\"" package-lock.json > package-lock.json.tmp
mv package-lock.json.tmp package-lock.json
git config user.name github-actions
git config user.email [email protected]
git add CHANGELOG.md
git add package.json
git add package-lock.json
git commit -q -m "Update changelog and package version for the ${{ steps.get-notes.outputs.next-tag }} release."
git push
```
67 changes: 67 additions & 0 deletions packages/js/github-actions/actions/get-release-notes/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Get release notes
description: Get release notes via GitHub, infer the next version and tag.

inputs:
repo-token:
description: The GITHUB_TOKEN secret.
required: true

package-dir:
description: >
The directory path of package.json. This action uses the version in package.json
to generate a version tag name with the input tag-template, and check whether that
tag exists to be used as the previous tag. The previous tag is the starting point of
a range for getting the release notes.
default: ""

tag-template:
description: >
The template to generate a tag name with a version.
For example, with a version 1.4.7,
"v{version}" gets 'v1.4.7' and "my-tool-v{version}" gets 'my-tool-v1.4.7'.
default: "{version}"

tag:
description: The tag name for the release. This can be an existing tag or leave it empty by default.
default: ""

target-commitish:
description: >
Specifies the commitish value that will be the target for the release's tag.
If the input tag does not reference an existing tag, the default empty value
will be replaced with the branch that triggers this action. If the input tag
already exists, leave it empty by default.
default: ""

config-path:
description: >
Specifies a path to a file in the repository containing the config used for
generating the release notes. If unspecified, the config file located in the
repository at '.github/release.yml' will be used. If that is not present,
the default config of GitHub will be used.
default: ""

major-keywords:
description: Comma-separated keywords for matching the major level. For example, "breaking, major changes".
default: "breaking"

minor-keywords:
description: Comma-separated keywords for matching the minor level. For example, "new features, improvements".
default: "feature, enhancement"

outputs:
release-notes:
description: The content of release notes.

release-changelog:
description: The changelog part in release notes.

next-version:
description: The next version inferred via the release notes. For example, 2.0.0, 1.5.0 or 1.4.8.

next-tag:
description: The next tag name inferred via the release notes. For example, 2.0.0, v1.5.0 or my-tool-v1.4.8.

runs:
using: node16
main: get-release-notes.js
Loading