-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ci: Refactor release workflow (#174)
* ci: Refactor release workflow * Fix `check-downstream-compiles` * Support manual release on `workflow_dispatch` * Fix token * Switch to `ci-workflows` `main` * Update changelog config
- Loading branch information
1 parent
68a48fb
commit f346b37
Showing
4 changed files
with
146 additions
and
150 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
{ | ||
"template": "#{{CHANGELOG}}", | ||
"categories": [ | ||
{ | ||
"title": "## 🚀 Features", | ||
"labels": [ | ||
"feat" | ||
] | ||
}, | ||
{ | ||
"title": "## 🐛 Fixes", | ||
"labels": [ | ||
"fix" | ||
] | ||
}, | ||
{ | ||
"title": "## ⚡️ Performance", | ||
"labels": [ | ||
"perf" | ||
] | ||
}, | ||
{ | ||
"title": "## 🧪 Tests", | ||
"labels": [ | ||
"test" | ||
] | ||
}, | ||
{ | ||
"title": "## 📝 Docs", | ||
"labels": [ | ||
"docs" | ||
] | ||
}, | ||
{ | ||
"title": "## 🤖 CI", | ||
"labels": [ | ||
"automated-issue", | ||
"ci" | ||
] | ||
}, | ||
{ | ||
"title": "## Other", | ||
"labels": [] | ||
} | ||
], | ||
"label_extractor": [ | ||
{ | ||
"pattern": "^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test){1}(\\([\\w\\-\\.]+\\))?(!)?: ([\\w ])+([\\s\\S]*)", | ||
"target": "$1" | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,126 +1,65 @@ | ||
name: Bump Version | ||
# Workflow to create a new release PR, with one of the following two scenarios: | ||
# | ||
# - Major release | ||
# - Pushes a new `release/<tag-prefix>-v<version>` branch based on latest `major.minor` version, e.g. `release/sphinx-v1.0` | ||
# - Creates a new `release-pr-<tag-prefix>-v<version>` branch from the release, then bumps the version with the `version` input | ||
# - Opens a release PR from `release-pr-<tag-prefix>-v<version>` to `release/<tag-prefix>-v<version>` | ||
# - Minor release | ||
# - Pushes a new `release/<tag-prefix>-v<version>` branch based on the latest compatible major release | ||
# - Creates a new `release-pr-<tag-prefix>-v<version` branch from the release, then bumps the version with the `version` input | ||
# - Opens a release PR from `release-pr-<tag-prefix>-v<version` to `release/<tag-prefix>-v<version>` | ||
# - Patch release | ||
# - Pushes a new `patch/<tag-prefix>-v<version>` branch based on `release/<tag-prefix>-v<version>`, then bumps the verision with the `version` input | ||
# - Errors if the `release/<tag-prefix>-v<version>` branch doesn't exist | ||
# - Opens a release PR from `patch/<tag-prefix>-v<version>` to `release/<tag-prefix>-v<version>` | ||
# | ||
# When the PR is merged, the caller can then trigger a release from `ci-workflows/actions/tag-release` | ||
# NOTE: To get a rich changelog based on each commit prefix, merge without squashing. Otherwise, the changelog will only show the release PR | ||
# The PR branch can then be safely deleted, while the release branch should have a branch protection rule for historical preservation | ||
# | ||
# The `ci-workflows` release PR action can be found at https://github.com/argumentcomputer/ci-workflows/blob/main/.github/actions/release-pr/action.yml | ||
name: Create release PR | ||
on: | ||
workflow_dispatch: | ||
inputs: | ||
type: | ||
description: 'release or hotfix' | ||
release-type: | ||
description: 'Semver release type' | ||
required: true | ||
default: 'major' | ||
type: choice | ||
options: | ||
- release | ||
- hotfix | ||
required: true | ||
default: 'release' | ||
# NOTE: For a `release` branch, only specify the `major.minor` version. This branch will be persistent across patches, | ||
# so any patch number specified in this case will be dropped. For a hotfix, specify the full `major.minor.patch` version | ||
- major | ||
- minor | ||
- patch | ||
version: | ||
description: 'Version' | ||
description: '`<major>.<minor>.<patch>` version, e.g. `1.0.0`' | ||
required: true | ||
type: string | ||
|
||
jobs: | ||
release: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Git config | ||
run: | | ||
git config --global user.name "github-actions[bot]" | ||
git config --global user.email "github-actions[bot]@users.noreply.github.com" | ||
git config --global url."https://${{ secrets.REPO_TOKEN }}@github.com/".insteadOf ssh://[email protected] | ||
git config --global url."https://${{ secrets.REPO_TOKEN }}@github.com".insteadOf https://github.com | ||
- name: Checkout code | ||
uses: actions/checkout@v4 | ||
|
||
- name: Install Rust | ||
uses: dtolnay/rust-toolchain@stable | ||
|
||
- name: Install `tq-rs` | ||
run: cargo install tq-rs | ||
|
||
# The `release/1.0` branch is always truncated, so that patch version merges still are valid Semver | ||
# However, when we make the initial `release/1.0` version bump, we include the full `1.0.0` in `Cargo.toml` | ||
# and the release for clarity | ||
- name: Set branches | ||
run: | | ||
BASE_VERSION_SHORT=$(echo "${{ inputs.version }}" | cut -d'.' -f1-2) | ||
BASE_VERSION="${BASE_VERSION_SHORT}.0" | ||
if [[ "${{ inputs.type }}" == "hotfix" ]]; then | ||
VERSION=${{ inputs.version }} | ||
BASE_BRANCH="release/v$BASE_VERSION_SHORT" | ||
PR_BRANCH="${{ inputs.type }}/v${{ inputs.version }}" | ||
git checkout $PR_BRANCH | ||
else | ||
VERSION=$BASE_VERSION | ||
BASE_BRANCH="dev" | ||
PR_BRANCH="release/v$BASE_VERSION_SHORT" | ||
git checkout -b $PR_BRANCH | ||
fi | ||
echo "BASE_BRANCH=$BASE_BRANCH" | tee -a $GITHUB_ENV | ||
echo "PR_BRANCH=$PR_BRANCH" | tee -a $GITHUB_ENV | ||
echo "PR_DESCRIPTION=chore: Release $VERSION" | tee -a $GITHUB_ENV | ||
echo "VERSION=$VERSION" | tee -a $GITHUB_ENV | ||
# Regex from https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string | ||
- name: Validate version | ||
run: | | ||
echo "Validating version ${{ env.VERSION }}..." | ||
D='0|[1-9][0-9]*' | ||
PW='[0-9]*[a-zA-Z-][0-9a-zA-Z-]*' | ||
MW='[0-9a-zA-Z-]+' | ||
if [[ "${{ env.VERSION }}" =~ ^($D)\.($D)\.($D)(-(($D|$PW)(\.($D|$PW))*))?(\+($MW(\.$MW)*))?$ ]]; then | ||
echo "Version ${{ env.VERSION }} is valid." | ||
else | ||
echo "Version is not valid SemVer. Aborting..." | ||
exit 1 | ||
fi | ||
- name: Update version in Cargo.toml | ||
run: | | ||
members=$(tq workspace.members -f Cargo.toml | jq -r '.[]') | ||
bump_version() { | ||
cd "$1" | ||
OLD_VERSION=$(grep -oP 'version = "\K[^"]+' Cargo.toml | head -n1) | ||
if [[ "${{ env.VERSION }}" > "$OLD_VERSION" ]]; then | ||
sed -i "s/version = \"$OLD_VERSION\"/version = \"${{ env.VERSION }}\"/" Cargo.toml | ||
else | ||
echo "New version is not greater than the current version for $1. Aborting..." | ||
exit 1 | ||
fi | ||
cd ${{ github.workspace }} | ||
} | ||
while IFS= read -r path; do | ||
if [[ "$path" == *"/*" ]]; then | ||
for dir in "${path%/*}"/*; do | ||
if [ -d "$dir" ] && [ -f "$dir/Cargo.toml" ]; then | ||
bump_version "$dir" | ||
fi | ||
done | ||
else | ||
bump_version "$path" | ||
fi | ||
done <<< "$members" | ||
- name: Commit changes | ||
run: | | ||
git add . | ||
git commit -m "${{ env.PR_DESCRIPTION }}" | ||
git push origin ${{ env.PR_BRANCH }} | ||
# Note: Can't use `peter-evans/create-pull-request` because for hotfixes we need to make the PR with an existing branch | ||
# The former always creates a new one for single-commit PRs, thus overwriting the actual hotfix | ||
- name: Create PR | ||
run: | | ||
cat << 'EOF' > body.md | ||
This is an automated release PR for the patched version of `${{ env.VERSION }}`. | ||
On merge, this will trigger the [release publish workflow](${{ github.server_url }}/${{ github.repository }}/actions/workflows/tag-release.yml), which will upload a new GitHub release with tag `v${{ env.VERSION }}`. | ||
[Workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) | ||
EOF | ||
gh pr create --title "${{ env.PR_DESCRIPTION }}" --body-file ./body.md --head ${{ env.PR_BRANCH }} --base ${{ env.BASE_BRANCH }} | ||
env: | ||
GH_TOKEN: ${{ github.token }} | ||
git config --global user.name "argument-ci[bot]" | ||
git config --global user.email "argument-ci[bot]@users.noreply.github.com" | ||
- uses: actions/checkout@v4 | ||
with: | ||
fetch-depth: 0 | ||
- uses: actions/checkout@v4 | ||
with: | ||
repository: argumentcomputer/ci-workflows | ||
path: ci-workflows | ||
- uses: tibdex/github-app-token@v2 | ||
id: generate-token | ||
with: | ||
app_id: ${{ secrets.TOKEN_APP_ID }} | ||
private_key: ${{ secrets.TOKEN_APP_PRIVATE_KEY }} | ||
- name: Open release PR | ||
uses: ./ci-workflows/.github/actions/release-pr | ||
with: | ||
tag-prefix: sphinx | ||
release-type: ${{ inputs.release-type }} | ||
version: ${{ inputs.version }} | ||
token: ${{ steps.generate-token.outputs.token }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,61 +1,63 @@ | ||
name: Tag release | ||
# Workflow to create a new tag release when a release branch is merged | ||
# | ||
# The `ci-workflows` tag release action can be found at https://github.com/argumentcomputer/ci-workflows/blob/main/.github/actions/tag-release/action.yml | ||
name: Create tag release | ||
|
||
on: | ||
pull_request: | ||
types: [ closed ] | ||
branches: | ||
- dev | ||
- release/* | ||
workflow_dispatch: | ||
inputs: | ||
release-branch: | ||
description: 'Branch to release' | ||
type: 'string' | ||
required: true | ||
version: | ||
description: 'SemVer release version, e.g. `1.0.0`' | ||
type: 'string' | ||
required: true | ||
|
||
jobs: | ||
# Creates a new tag if a release branch is merged | ||
tag-bump: | ||
tag-release: | ||
if: | | ||
github.event.pull_request.merged == true && | ||
((startsWith(github.event.pull_request.head.ref, 'release/') && github.event.pull_request.base.ref == 'dev') || | ||
(startsWith(github.event.pull_request.head.ref, 'hotfix/') && startsWith(github.event.pull_request.base.ref, 'release/'))) | ||
(github.event.pull_request.merged == true && | ||
(startsWith(github.event.pull_request.head.ref, 'release-pr') || | ||
startsWith(github.event.pull_request.head.ref, 'patch/'))) || | ||
github.event_name == 'workflow_dispatch' | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Git config | ||
run: | | ||
git config --global user.name "github-actions[bot]" | ||
git config --global user.email "github-actions[bot]@users.noreply.github.com" | ||
git config --global url."https://${{ secrets.REPO_TOKEN }}@github.com/".insteadOf ssh://[email protected] | ||
git config --global url."https://${{ secrets.REPO_TOKEN }}@github.com".insteadOf https://github.com | ||
- name: Checkout code | ||
uses: actions/checkout@v4 | ||
with: | ||
fetch-depth: 0 | ||
|
||
- name: Get version | ||
id: get-version | ||
- uses: actions/checkout@v4 | ||
with: | ||
repository: argumentcomputer/ci-workflows | ||
path: ci-workflows | ||
- name: Get branch and version info | ||
run: | | ||
VERSION=$(echo "${{ github.event.pull_request.head.ref }}" | cut -d'/' -f 2) | ||
RELEASE_BRANCH="${{ startsWith(github.event.pull_request.head.ref, 'release/') && github.event.pull_request.head.ref || github.event.pull_request.base.ref }}" | ||
if [[ "${{ startsWith(github.event.pull_request.head.ref, 'release/') }}" == "true" ]]; then | ||
VERSION="${VERSION}.0" | ||
if [[ "${{ github.event_name }}" == "pull_request" ]]; then | ||
RELEASE_BRANCH=${{ github.event.pull_request.base.ref }} | ||
# Get tag and version from PR title | ||
TAG=$(echo '${{ github.event.pull_request.title }}' | awk '/Release/ {print $NF}' | tr -d '`') | ||
VERSION="${TAG#*-v}" | ||
else | ||
RELEASE_BRANCH=${{ inputs.release-branch }} | ||
VERSION=${{ inputs.version }} | ||
fi | ||
git tag -a $VERSION -m "$VERSION" origin/$RELEASE_BRANCH | ||
git push origin $VERSION --follow-tags | ||
echo "version=$VERSION" | tee -a "$GITHUB_OUTPUT" | ||
echo "RELEASE_BRANCH=$RELEASE_BRANCH" | tee -a "$GITHUB_ENV" | ||
- name: Build Changelog | ||
id: github_release | ||
uses: mikepenz/release-changelog-builder-action@v5 | ||
with: | ||
toTag: ${{ steps.get-version.outputs.version }} | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
|
||
- name: Create Release | ||
uses: ncipollo/release-action@v1 | ||
echo "RELEASE_BRANCH=$RELEASE_BRANCH" | tee -a $GITHUB_ENV | ||
echo "VERSION=$VERSION" | tee -a $GITHUB_ENV | ||
- name: Publish release | ||
uses: ./ci-workflows/.github/actions/tag-release | ||
with: | ||
body: ${{ steps.github_release.outputs.changelog }} | ||
tag: ${{ steps.get-version.outputs.version }} | ||
commit: ${{ env.RELEASE_BRANCH }} | ||
allowUpdates: true | ||
release-branch: ${{ env.RELEASE_BRANCH }} | ||
version: ${{ env.VERSION }} | ||
tag-prefix: sphinx | ||
changelog-config-file: ${{ github.workspace }}/.github/changelog-config.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters