Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions .github/workflows/prepare-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: Prepare Release

on:
workflow_dispatch:
inputs:
version:
description: "Version to release (e.g. 1.2.3)"
required: true
type: string
base_branch:
description: "Base branch for release (e.g. release/v1.x, hotfix/v1.2.x)"
required: false
default: "main"
type: string

jobs:
prepare-release:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ inputs.base_branch }}
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version-file: ".nvmrc"
cache: "npm"

- name: Install dependencies
run: npm ci

- name: Create draft release
run: gh release create v${{ inputs.version }} --draft --generate-notes
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Create release branch
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
git checkout -b "release/prep-release-${{ inputs.version }}"

- name: Set version and run build
run: |
npm run setversion ${{ inputs.version }}

- name: Commit version changes
run: |
git add .
git commit -s -m "Release ${{ inputs.version }}"
git push --set-upstream origin "release/prep-release-${{ inputs.version }}"

- name: Get release notes
id: release_notes
run: |
RELEASE_NOTES=$(gh release view v${{ inputs.version }} --json body | jq -r ".body")
echo "notes<<EOF" >> $GITHUB_OUTPUT
echo "$RELEASE_NOTES" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Create pull request
run: |
gh pr create \
--title "Release ${{ inputs.version }}" \
--body "${{ steps.release_notes.outputs.notes }}" \
--base "${{ inputs.base_branch }}"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
99 changes: 99 additions & 0 deletions .github/workflows/publish-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
name: Publish Release

on:
pull_request:
types: [closed]
branches:
- main
- "release/**"
- "hotfix/**"

jobs:
publish-release:
runs-on: ubuntu-latest
# Only run if PR was merged and branch name starts with release/prep-release-
if: github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/prep-release-')
permissions:
id-token: write # Required for OIDC
contents: write
pull-requests: write
issues: write

steps:
- name: Extract version from branch name
id: extract_version
run: |
BRANCH_NAME="${{ github.event.pull_request.head.ref }}"
VERSION=$(echo "$BRANCH_NAME" | sed 's/release\/prep-release-//')
echo "version=$VERSION" >> $GITHUB_OUTPUT

- name: Checkout base branch
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.base.ref }}
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version-file: ".nvmrc"
cache: "npm"

- name: Install dependencies
run: npm ci

- name: Get updated release notes from PR
id: pr_notes
run: |
RELEASE_NOTES=$(gh pr view ${{ github.event.pull_request.number }} --json body | jq -r ".body")
echo "notes<<EOF" >> $GITHUB_OUTPUT
echo "$RELEASE_NOTES" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Publish to npm
run: npm run release

- name: Publish GitHub release
run: |
gh release edit v${{ steps.extract_version.outputs.version }} \
--notes "${{ steps.pr_notes.outputs.notes }}" \
--draft=false
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
cleanup-canceled-release:
runs-on: ubuntu-latest
# Only run if PR was closed without merge and branch name starts with release/prep-release-
if: github.event.pull_request.merged == false && startsWith(github.event.pull_request.head.ref, 'release/prep-release-')
permissions:
contents: write
pull-requests: write

steps:
- name: Extract version from branch name
id: extract_version
run: |
BRANCH_NAME="${{ github.event.pull_request.head.ref }}"
VERSION=$(echo "$BRANCH_NAME" | sed 's/release\/prep-release-//')
echo "version=$VERSION" >> $GITHUB_OUTPUT

- name: Delete draft release
run: |
if gh release view v${{ steps.extract_version.outputs.version }} --json isDraft | jq -r ".isDraft" | grep -q "true"; then
echo "Deleting draft release v${{ steps.extract_version.outputs.version }}"
gh release delete v${{ steps.extract_version.outputs.version }} --yes
else
echo "Release v${{ steps.extract_version.outputs.version }} is not a draft, skipping deletion"
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Delete release branch
continue-on-error: true
run: |
echo "Deleting release branch ${{ github.event.pull_request.head.ref }}"
git push origin --delete ${{ github.event.pull_request.head.ref }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
82 changes: 82 additions & 0 deletions .github/workflows/update-fixed-issues.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: Update Fixed Issues

on:
release:
types: [published]

jobs:
update-fixed-issues:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write

steps:
- name: Extract version from release
id: extract_version
run: |
VERSION="${{ github.event.release.tag_name }}"
# Remove 'v' prefix if present
VERSION=$(echo "$VERSION" | sed 's/^v//')
echo "version=$VERSION" >> $GITHUB_OUTPUT

- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- name: Get release info for issue comments
id: release_info
run: |
# Get last two releases
RELEASES=$(gh api repos/${{ github.repository }}/releases --jq ".[0:2].[].name")
LATEST_RELEASE=$(echo "${RELEASES}" | head -1)
PREV_RELEASE=$(echo "${RELEASES}" | tail -1)

echo "latest=$LATEST_RELEASE" >> $GITHUB_OUTPUT
echo "previous=$PREV_RELEASE" >> $GITHUB_OUTPUT

RELEASE_URL=$(gh release view v${{ steps.extract_version.outputs.version }} --json url | jq -r ".url")
echo "release_url=$RELEASE_URL" >> $GITHUB_OUTPUT
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Comment on fixed issues
run: |
# Get PRs included in this release
START=$(gh release view ${{ steps.release_info.outputs.previous }} --json publishedAt | jq -r ".publishedAt")
END=$(gh release view ${{ steps.release_info.outputs.latest }} --json publishedAt | jq -r ".publishedAt")
PRS=$(gh pr list --search="merged:$START..$END" --json="number" | jq -r ".[].number")

# For each PR, get the issues it fixes and comment on them
echo "$PRS" | while IFS= read -r pr; do
if [[ -z "$pr" ]]; then
continue
fi

ISSUES=$(gh api graphql -F owner='${{ github.repository_owner }}' -F repo='${{ github.event.repository.name }}' -F pr=$pr -f query='
query ($owner: String!, $repo: String!, $pr: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $pr) {
closingIssuesReferences(first: 100) {
nodes {
number
}
}
}
}
}' | jq -r '.data.repository.pullRequest.closingIssuesReferences.nodes[].number')

echo "$ISSUES" | while IFS= read -r issue; do
issue=$(echo $issue | tr -d '\n')
if [[ -z "$issue" ]]; then
continue
fi
echo "Adding comment to issue $issue"
gh issue comment $issue -b "Released in [${{ steps.extract_version.outputs.version }}](${{ steps.release_info.outputs.release_url }}) 🚀"
done
done
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}