mirror of
https://github.com/actualbudget/actual.git
synced 2026-05-21 06:31:58 -05:00
split release into two branches (#7844)
* split release into two branches * update docs to match the new process * note * zizmor comment * Update check-spelling metadata * use single long lived release branch * coderabbit * jfdoming suggestions
This commit is contained in:
1
.github/actions/docs-spelling/expect.txt
vendored
1
.github/actions/docs-spelling/expect.txt
vendored
@@ -11,6 +11,7 @@ ANZ
|
||||
aql
|
||||
AUR
|
||||
Authentik
|
||||
autogen
|
||||
AVERAGEA
|
||||
BANKA
|
||||
BANKINTER
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
name: Generate release notes
|
||||
description: Generate release documentation from release note files
|
||||
|
||||
inputs:
|
||||
release-branch:
|
||||
description: 'The release/X.Y.Z branch to read release notes from'
|
||||
required: true
|
||||
notes-branch:
|
||||
description: 'The release-notes/X.Y.Z branch to write generated docs to'
|
||||
required: true
|
||||
version:
|
||||
description: 'The release version (e.g. 26.5.0)'
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
@@ -14,4 +25,7 @@ runs:
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
RELEASE_BRANCH: ${{ inputs.release-branch }}
|
||||
NOTES_BRANCH: ${{ inputs.notes-branch }}
|
||||
VERSION: ${{ inputs.version }}
|
||||
run: node packages/ci-actions/bin/release-notes-generate.mjs
|
||||
|
||||
118
.github/workflows/cut-release-branch.yml
vendored
118
.github/workflows/cut-release-branch.yml
vendored
@@ -6,10 +6,6 @@ on:
|
||||
- cron: '0 17 25 * *'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
ref:
|
||||
description: 'Commit or branch to release'
|
||||
required: true
|
||||
default: 'master'
|
||||
version:
|
||||
description: 'Version number for the release (optional)'
|
||||
required: false
|
||||
@@ -31,8 +27,9 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
ref: ${{ github.event.inputs.ref || 'master' }}
|
||||
persist-credentials: false
|
||||
ref: master
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.ACTIONS_UPDATE_TOKEN }}
|
||||
|
||||
- name: Set up environment
|
||||
uses: ./.github/actions/setup
|
||||
@@ -41,41 +38,25 @@ jobs:
|
||||
cache: 'false'
|
||||
download-translations: 'false'
|
||||
|
||||
- name: Bump package versions
|
||||
id: bump_package_versions
|
||||
- name: Determine target version
|
||||
id: version
|
||||
shell: bash
|
||||
env:
|
||||
INPUT_VERSION: ${{ github.event.inputs.version }}
|
||||
run: |
|
||||
declare -A packages=(
|
||||
[web]="desktop-client"
|
||||
[electron]="desktop-electron"
|
||||
[sync]="sync-server"
|
||||
[api]="api"
|
||||
[cli]="cli"
|
||||
[core]="loot-core"
|
||||
)
|
||||
declare -A new_versions
|
||||
args=(--package-json ./packages/desktop-client/package.json --type auto)
|
||||
if [[ -n "$INPUT_VERSION" ]]; then
|
||||
args+=(--version "$INPUT_VERSION")
|
||||
fi
|
||||
yarn workspace @actual-app/ci-actions tsx bin/get-next-package-version.ts "${args[@]}"
|
||||
|
||||
for key in "${!packages[@]}"; do
|
||||
pkg="${packages[$key]}"
|
||||
|
||||
if [[ -n "$INPUT_VERSION" ]]; then
|
||||
version=$(yarn workspace @actual-app/ci-actions tsx bin/get-next-package-version.ts \
|
||||
--package-json "./packages/$pkg/package.json" \
|
||||
--version "$INPUT_VERSION" \
|
||||
--update)
|
||||
else
|
||||
version=$(yarn workspace @actual-app/ci-actions tsx bin/get-next-package-version.ts \
|
||||
--package-json "./packages/$pkg/package.json" \
|
||||
--type auto \
|
||||
--update)
|
||||
fi
|
||||
|
||||
new_versions[$key]="$version"
|
||||
done
|
||||
|
||||
echo "version=${new_versions[web]}" >> "$GITHUB_OUTPUT"
|
||||
- name: Determine previous tag
|
||||
id: prev_tag
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.ACTIONS_UPDATE_TOKEN || github.token }}
|
||||
run: |
|
||||
prev_tag=$(gh api "repos/${GITHUB_REPOSITORY}/releases/latest" --jq '.tag_name' 2>/dev/null) || prev_tag=""
|
||||
echo "tag=${prev_tag:-master}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Compute release date
|
||||
id: release_date
|
||||
@@ -90,15 +71,72 @@ jobs:
|
||||
echo "date=$(date -d '+1 month' '+%Y-%m-01')" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Create release branch and PR
|
||||
- name: Validate target version
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.ACTIONS_UPDATE_TOKEN }}
|
||||
VERSION: ${{ steps.version.outputs.version }}
|
||||
TYPE: ${{ steps.version.outputs.type }}
|
||||
shell: bash
|
||||
run: |
|
||||
if gh api "repos/${GITHUB_REPOSITORY}/branches/release" --silent >/dev/null 2>&1; then
|
||||
current_version=$(gh api "repos/${GITHUB_REPOSITORY}/contents/packages/desktop-client/package.json?ref=release" --jq '.content' | base64 -d | jq -r .version)
|
||||
latest=$(printf '%s\n%s\n' "$VERSION" "$current_version" | sort -V | tail -1)
|
||||
if [[ "$latest" != "$VERSION" || "$current_version" == "$VERSION" ]]; then
|
||||
echo "::error::Target version $VERSION is not newer than current release version $current_version"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Type: $TYPE (target=$VERSION, current=${current_version:-none})"
|
||||
|
||||
- name: Apply version bumps
|
||||
shell: bash
|
||||
env:
|
||||
VERSION: ${{ steps.version.outputs.version }}
|
||||
run: |
|
||||
for pkg in desktop-client desktop-electron sync-server api cli loot-core; do
|
||||
yarn workspace @actual-app/ci-actions tsx bin/get-next-package-version.ts \
|
||||
--package-json "./packages/$pkg/package.json" \
|
||||
--version "$VERSION" \
|
||||
--update
|
||||
done
|
||||
|
||||
- name: Open release-notes branch and PR
|
||||
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
|
||||
with:
|
||||
token: ${{ secrets.ACTIONS_UPDATE_TOKEN }}
|
||||
commit-message: '🔖 (${{ steps.bump_package_versions.outputs.version }})'
|
||||
title: '🔖 (${{ steps.bump_package_versions.outputs.version }})'
|
||||
commit-message: '🔖 (${{ steps.version.outputs.version }})'
|
||||
title: '🔖 (${{ steps.version.outputs.version }})'
|
||||
body: |
|
||||
Generated by [cut-release-branch.yml](../tree/master/.github/workflows/cut-release-branch.yml)
|
||||
|
||||
Release branch: [`release`](../compare/${{ steps.prev_tag.outputs.tag }}...release)
|
||||
|
||||
<!-- release-date:${{ steps.release_date.outputs.date }} -->
|
||||
branch: 'release/${{ steps.bump_package_versions.outputs.version }}'
|
||||
branch: 'release-notes/${{ steps.version.outputs.version }}'
|
||||
base: master
|
||||
|
||||
- name: Update release branch
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.ACTIONS_UPDATE_TOKEN }}
|
||||
VERSION: ${{ steps.version.outputs.version }}
|
||||
TYPE: ${{ steps.version.outputs.type }}
|
||||
shell: bash
|
||||
run: |
|
||||
git config user.name 'github-actions[bot]'
|
||||
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
|
||||
|
||||
if gh api "repos/${GITHUB_REPOSITORY}/branches/release" --silent >/dev/null 2>&1; then
|
||||
git fetch origin release
|
||||
git checkout release
|
||||
|
||||
if [[ "$TYPE" == "monthly" ]]; then
|
||||
git fetch origin master
|
||||
git merge --no-edit -X theirs origin/master
|
||||
git diff --exit-code origin/master
|
||||
fi
|
||||
fi
|
||||
|
||||
git fetch origin "release-notes/$VERSION"
|
||||
git cherry-pick FETCH_HEAD
|
||||
git push origin HEAD:refs/heads/release
|
||||
|
||||
44
.github/workflows/release-notes.yml
vendored
44
.github/workflows/release-notes.yml
vendored
@@ -2,6 +2,9 @@ name: Release notes
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- release
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -12,7 +15,11 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
release-notes:
|
||||
check-release-notes:
|
||||
if: >-
|
||||
github.event_name == 'pull_request'
|
||||
&& github.head_ref != 'release'
|
||||
&& startsWith(github.head_ref, 'release-notes/') == false
|
||||
runs-on: ubuntu-latest
|
||||
environment: pr-automation
|
||||
steps:
|
||||
@@ -37,9 +44,7 @@ jobs:
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.ACTIONS_UPDATE_TOKEN || github.token }}
|
||||
# Need to be able to commit release notes after generation
|
||||
persist-credentials: true
|
||||
persist-credentials: false
|
||||
|
||||
- name: Get changed files
|
||||
if: steps.bot-check.outputs.skip != 'true'
|
||||
@@ -59,13 +64,34 @@ jobs:
|
||||
- name: Check release notes
|
||||
if: >-
|
||||
steps.bot-check.outputs.skip != 'true'
|
||||
&& startsWith(github.head_ref, 'release/') == false
|
||||
&& steps.changed-files.outputs.only_docs != 'true'
|
||||
uses: ./.github/actions/release-notes/check
|
||||
|
||||
generate-release-notes:
|
||||
if: github.event_name == 'push'
|
||||
runs-on: ubuntu-latest
|
||||
environment: release
|
||||
steps:
|
||||
- name: Resolve version
|
||||
id: version
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.ACTIONS_UPDATE_TOKEN || github.token }}
|
||||
run: |
|
||||
version=$(gh api "repos/${GITHUB_REPOSITORY}/contents/packages/desktop-client/package.json?ref=release" --jq '.content' | base64 -d | jq -r .version)
|
||||
echo "version=$version" >> "$GITHUB_OUTPUT"
|
||||
echo "notes_branch=release-notes/$version" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Checkout release-notes branch
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
ref: ${{ steps.version.outputs.notes_branch }}
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.ACTIONS_UPDATE_TOKEN || github.token }}
|
||||
persist-credentials: true
|
||||
|
||||
- name: Generate release notes
|
||||
if: >-
|
||||
steps.bot-check.outputs.skip != 'true'
|
||||
&& startsWith(github.head_ref, 'release/') == true
|
||||
&& github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name
|
||||
uses: ./.github/actions/release-notes/generate
|
||||
with:
|
||||
release-branch: release
|
||||
notes-branch: ${{ steps.version.outputs.notes_branch }}
|
||||
version: ${{ steps.version.outputs.version }}
|
||||
|
||||
@@ -80,6 +80,18 @@ try {
|
||||
|
||||
process.stdout.write(newVersion);
|
||||
|
||||
if (process.env.GITHUB_OUTPUT) {
|
||||
const resolvedType = newVersion.includes('-nightly.')
|
||||
? 'nightly'
|
||||
: newVersion.split('.')[2] === '0'
|
||||
? 'monthly'
|
||||
: 'hotfix';
|
||||
fs.appendFileSync(
|
||||
process.env.GITHUB_OUTPUT,
|
||||
`version=${newVersion}\ntype=${resolvedType}\n`,
|
||||
);
|
||||
}
|
||||
|
||||
if (values.update) {
|
||||
packageJson.version = newVersion;
|
||||
fs.writeFileSync(
|
||||
|
||||
@@ -15,6 +15,16 @@ const exec = promisify(childProcess.exec);
|
||||
|
||||
const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/');
|
||||
|
||||
const releaseBranch = process.env.RELEASE_BRANCH;
|
||||
const notesBranch = process.env.NOTES_BRANCH;
|
||||
const version = process.env.VERSION;
|
||||
|
||||
if (!releaseBranch || !notesBranch || !version) {
|
||||
throw new Error(
|
||||
'RELEASE_BRANCH, NOTES_BRANCH, and VERSION env vars are required',
|
||||
);
|
||||
}
|
||||
|
||||
const apiResult = await fetch('https://api.github.com/graphql', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@@ -44,24 +54,38 @@ const apiResult = await fetch('https://api.github.com/graphql', {
|
||||
variables: {
|
||||
name: repo,
|
||||
owner,
|
||||
headRefName: process.env.GITHUB_HEAD_REF || process.env.GITHUB_REF_NAME,
|
||||
headRefName: notesBranch,
|
||||
},
|
||||
}),
|
||||
}).then(res => res.json());
|
||||
|
||||
await collapsedLog('API Response', apiResult);
|
||||
|
||||
const prData = apiResult.data.repository.pullRequests.edges[0].node;
|
||||
|
||||
const version = prData.headRefName.split('/')[1].replace(/^v/, '');
|
||||
const slug = version.replace(/\./g, '-');
|
||||
const author = process.env.GITHUB_ACTOR || 'TODO';
|
||||
const commitMessage = `Generate release notes for v${version}`;
|
||||
const prData = apiResult.data.repository.pullRequests.edges[0]?.node;
|
||||
if (!prData) {
|
||||
console.error(`No PR found for branch ${notesBranch}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const releaseDateMatch = (prData.body || '').match(
|
||||
/<!-- release-date:(\d{4}-\d{2}-\d{2}) -->/,
|
||||
);
|
||||
const releaseDate = releaseDateMatch ? releaseDateMatch[1] : 'TODO';
|
||||
if (!releaseDateMatch) {
|
||||
console.error(
|
||||
`PR for ${notesBranch} body missing <!-- release-date:YYYY-MM-DD --> marker`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
const releaseDate = releaseDateMatch[1];
|
||||
|
||||
const author = process.env.GITHUB_ACTOR;
|
||||
if (!author) {
|
||||
console.error('::error::GITHUB_ACTOR env var is not set');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const slug = version.replace(/\./g, '-');
|
||||
const commitMessage = `Generate release notes for v${version}`;
|
||||
|
||||
const botName = 'github-actions[bot]';
|
||||
const botEmail = '41898282+github-actions[bot]@users.noreply.github.com';
|
||||
@@ -72,17 +96,8 @@ await exec(`git config user.email '${botEmail}'`);
|
||||
const AUTOGEN_MARKER = '<!-- release-notes:auto-generated -->';
|
||||
|
||||
await group('Prepare branch', async () => {
|
||||
if (process.env.GITHUB_HEAD_REF) {
|
||||
await exec(`git fetch origin ${process.env.GITHUB_HEAD_REF}`, {
|
||||
stdio: 'inherit',
|
||||
});
|
||||
await exec(`git checkout ${process.env.GITHUB_HEAD_REF}`, {
|
||||
stdio: 'inherit',
|
||||
});
|
||||
}
|
||||
|
||||
// recover deleted release note files from previous generation commits
|
||||
const baseRef = process.env.GITHUB_BASE_REF || 'master';
|
||||
const baseRef = 'master';
|
||||
await exec(`git fetch origin ${baseRef}`, { stdio: 'inherit' });
|
||||
const { stdout: mergeBase } = await exec(
|
||||
`git merge-base HEAD origin/${baseRef}`,
|
||||
@@ -110,6 +125,11 @@ await group('Prepare branch', async () => {
|
||||
await fs.unlink(patchPath).catch(() => undefined);
|
||||
}
|
||||
}
|
||||
|
||||
await exec(`git fetch origin ${releaseBranch}`, { stdio: 'inherit' });
|
||||
await exec(`git checkout origin/${releaseBranch} -- upcoming-release-notes`, {
|
||||
stdio: 'inherit',
|
||||
});
|
||||
});
|
||||
|
||||
const { notesByCategory, files } = await parseReleaseNotes(
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
## General information
|
||||
|
||||
In the open-source version of Actual, there are 4 NPM packages:
|
||||
In the open-source version of Actual, there are 5 NPM packages:
|
||||
|
||||
- [@actual-app/core](https://www.npmjs.com/package/@actual-app/core): The shared core library (loot-core) used by the other packages. Platform-agnostic business logic, database operations, and calculations.
|
||||
- [@actual-app/api](https://www.npmjs.com/package/@actual-app/api): The API for the underlying functionality. This includes the entire backend of Actual, meant to be used with Node.
|
||||
- [@actual-app/web](https://www.npmjs.com/package/@actual-app/web): A web build that will serve the app with a web frontend. This includes both the frontend and backend of Actual. It includes the backend as well because it's built to be used as a Web Worker.
|
||||
- [@actual-app/sync-server](https://www.npmjs.com/package/@actual-app/sync-server): The entire sync-server and underlying web client in one package. This includes the Server CLI, meant to be used with Node.
|
||||
@@ -24,28 +25,33 @@ For example:
|
||||
- `v23.3.2` - another bugfix launched later in the month of March;
|
||||
- `v23.4.0` - first release launched on 9th of April, 2023;
|
||||
|
||||
### Release branch
|
||||
### Release branches
|
||||
|
||||
A release branch and PR are automatically cut at 17:00 UTC on the 25th of each month. To cut one manually, run [this GitHub Action](https://github.com/actualbudget/actual/actions/workflows/cut-release-branch.yml).
|
||||
There are two branches involved in every release:
|
||||
|
||||
The release notes workflow automatically generates a blog post and updates `docs/releases.md` from the files in `upcoming-release-notes/`. This runs each time the release PR is updated, so there is no need to manually copy notes into the docs.
|
||||
- `release`: the single long-lived branch where release tags live. This is the branch we actually base the release on, and where commits are cherry-picked to if we want them included.
|
||||
- `release-notes/X.Y.Z`: the branch that is used for the release PR. It holds the generated docs pages. It is deleted once a version ships.
|
||||
|
||||
Fixes that need to be included in the release should be cherry-picked onto the release branch manually.
|
||||
Splitting them avoids merge conflicts between cherry-picks on the release branch and the version-bump/docs commits that need to be merged back to `master`.
|
||||
|
||||
Monthly cuts run automatically at 17:00 UTC on the 25th of each month. To cut a release manually (monthly or patch), run the [Cut release workflow](https://github.com/actualbudget/actual/actions/workflows/cut-release-branch.yml).
|
||||
|
||||
Changes that need to be included in the release after the cut has been made should be cherry-picked onto `release`. Each cherry-pick triggers regeneration of the release notes on `release-notes/X.Y.Z`. Human edits to frontmatter (release highlights, author, etc.) on `release-notes/X.Y.Z` are preserved across regenerations as long as they are above the autogen marker.
|
||||
|
||||
## Release process
|
||||
|
||||
### Stabilize the release
|
||||
|
||||
- [ ] Fix spelling in the generated release notes as needed.
|
||||
- [ ] Fix spelling and add highlights in the generated release notes as needed (edit `release-notes/X.Y.Z` directly).
|
||||
- [ ] Share the release PR in the release channel on Discord.
|
||||
- [ ] Wait until at least 2 other maintainers have approved the release.
|
||||
|
||||
### Merge and tag the release
|
||||
|
||||
- [ ] Merge the release PR to master.
|
||||
- [ ] Create the tag on the **release branch** and push it. When the tag is pushed, it triggers the Docker stable image, all NPM packages and the Desktop app to be built and published.
|
||||
- [ ] Merge the `release-notes/X.Y.Z` PR to master.
|
||||
- [ ] Create the tag on the **`release` branch** and push it. When the tag is pushed, it triggers the Docker stable image, all NPM packages and the Desktop app to be built and published.
|
||||
```bash
|
||||
git checkout release/vX.Y.Z
|
||||
git checkout release
|
||||
git tag vX.Y.Z
|
||||
git push {remote} vX.Y.Z
|
||||
```
|
||||
@@ -71,43 +77,15 @@ Finally, a draft GitHub release should be automatically created; confirm [on the
|
||||
|
||||
## Cutting a patch release
|
||||
|
||||
Patch releases (e.g. `v26.5.1`) ship a small, targeted set of fixes on top of an existing release. Unlike monthly releases, the release branch is built by cherry-picking specific commits from `master` onto the previous release tag, so unrelated in-progress work on `master` is not pulled in.
|
||||
Patch releases (e.g. `26.6.1`) ship a small, targeted set of fixes on top of the latest release. Because `release` is a single long-lived branch, a patch is just a version bump and cherry-picks on top of the previous release, with no new branch to create.
|
||||
|
||||
### Build the release branch
|
||||
### Cut the patch
|
||||
|
||||
- [ ] Identify the commits on `master` that should be included in the patch release and note their commit hashes.
|
||||
- [ ] Check out the previous release tag and create a new release branch from it:
|
||||
```bash
|
||||
git checkout v26.5.0
|
||||
git checkout -b release/v26.5.1
|
||||
```
|
||||
- [ ] Cherry-pick each commit onto the new branch, in the same order they were merged to `master`:
|
||||
```bash
|
||||
git cherry-pick <commit-sha>
|
||||
```
|
||||
- [ ] Push the release branch. This is the branch that will be tagged later — **do not tag it yet**:
|
||||
```bash
|
||||
git push -u {remote} release/v26.5.1
|
||||
```
|
||||
Run the [Cut release workflow](https://github.com/actualbudget/actual/actions/workflows/cut-release-branch.yml) manually with:
|
||||
|
||||
### Open the release PR against master
|
||||
- `version`: the patch version (e.g. `26.6.1`).
|
||||
- `release-date`: when the patch is expected to ship (optional).
|
||||
|
||||
The release branch is what gets tagged, but the version bump, release notes cleanup, and blog post still need to land on `master` so future releases pick them up.
|
||||
This creates `release-notes/26.6.1`. It's worth noting that the release branch after a prior releases have no `upcoming-release-notes/*.md` files in them, so the initial release-notes run generates an empty blog, content will fill in once changes are cherry-picked in to the `release` branch.
|
||||
|
||||
- [ ] Check out `master` and create a new branch from it (e.g. `release-notes/v26.5.1`).
|
||||
- [ ] In this branch:
|
||||
- Bump the version in the relevant `package.json` files.
|
||||
- Delete the `upcoming-release-notes/*.md` files that correspond to the cherry-picked commits.
|
||||
- Add a new blog post under `packages/docs/blog/` (see [`2026-02-22-release-26-2-1.md`](https://github.com/actualbudget/actual/blob/master/packages/docs/blog/2026-02-22-release-26-2-1.md) for an example).
|
||||
- [ ] Commit the changes and open a PR against `master`. Include a link to the previously pushed release branch (e.g. `release/v26.5.1`) in the PR description so reviewers can see exactly what is shipping.
|
||||
|
||||
### Tag the release
|
||||
|
||||
- [ ] Once the PR has been approved and merged, tag the **release branch** (not `master`) and push the tag:
|
||||
```bash
|
||||
git checkout release/v26.5.1
|
||||
git tag v26.5.1
|
||||
git push {remote} v26.5.1
|
||||
```
|
||||
|
||||
From here the rest of the release pipeline (NPM, Docker, Desktop, GitHub draft release) runs automatically. Follow the [Verify the release](#verify-the-release) and [Finalize the release](#finalize-the-release) steps above to complete the rollout.
|
||||
The rest of the release process remains the same as a major release. Cherry-pick the appropriate changes into the `release` branch. Follow the steps to get the `release-notes/X.Y.Z` branch ready, then follow the merging and tagging steps outlined above.
|
||||
|
||||
6
upcoming-release-notes/7844.md
Normal file
6
upcoming-release-notes/7844.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: Maintenance
|
||||
authors: [matt-fidd]
|
||||
---
|
||||
|
||||
Split the release process into two branches
|
||||
Reference in New Issue
Block a user