Skip to content

Commit a08eea2

Browse files
committed
ci(ci): add infra for maintenance branches
1 parent b5903c4 commit a08eea2

10 files changed

Lines changed: 183 additions & 9 deletions

File tree

.github/workflows/dev-cleanup.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ on:
55
types: [closed]
66
branches:
77
- main
8+
- 'release/**'
89

910
env:
1011
GH_NPM_REGISTRY_TOKEN: ${{ secrets.GH_NPM_REGISTRY_TOKEN }}
@@ -25,7 +26,7 @@ jobs:
2526
- name: Checkout code
2627
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
2728
with:
28-
ref: main
29+
ref: ${{ github.event.pull_request.base.ref }}
2930

3031
- name: Setup pnpm
3132
uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4

.github/workflows/dev-publish.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ on:
99
types: [labeled, synchronize]
1010
branches:
1111
- main
12+
- 'release/**'
1213

1314
env:
1415
GH_NPM_REGISTRY_TOKEN: ${{ secrets.GH_NPM_REGISTRY_TOKEN }}
@@ -96,7 +97,7 @@ jobs:
9697
- name: Get changed packages
9798
id: changed
9899
run: |
99-
CHANGED_FILES=$(git diff --name-only origin/main...HEAD)
100+
CHANGED_FILES=$(git diff --name-only origin/${{ github.event.pull_request.base.ref }}...HEAD)
100101
PACKAGES=""
101102
102103
for pkg_dir in packages/* web-packages/*; do

.github/workflows/pr-checks.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ on:
44
pull_request:
55
branches:
66
- main
7+
- 'release/**'
78

89
env:
910
GH_NPM_REGISTRY_TOKEN: ${{ secrets.GH_NPM_REGISTRY_TOKEN }}
@@ -99,7 +100,7 @@ jobs:
99100
- name: Run Build
100101
if: matrix.check == 'Build'
101102
run: |
102-
if git diff --name-only origin/main...HEAD | grep -qE '^(pnpm-lock\.yaml|package\.json)$'; then
103+
if git diff --name-only origin/${{ github.event.pull_request.base.ref }}...HEAD | grep -qE '^(pnpm-lock\.yaml|package\.json)$'; then
103104
echo "📦 Root dependency files changed - building all packages"
104105
pnpm build
105106
else
@@ -133,7 +134,7 @@ jobs:
133134
- name: Check for lockfile changes
134135
id: lockfile_check
135136
run: |
136-
if git diff --name-only origin/main...HEAD | grep -q '^pnpm-lock\.yaml$'; then
137+
if git diff --name-only origin/${{ github.event.pull_request.base.ref }}...HEAD | grep -q '^pnpm-lock\.yaml$'; then
137138
echo "changed=true" >> $GITHUB_OUTPUT
138139
else
139140
echo "changed=false" >> $GITHUB_OUTPUT

.github/workflows/release.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ on:
44
push:
55
branches:
66
- main
7+
- 'release/**'
78

89
env:
910
GH_NPM_REGISTRY_TOKEN: ${{ secrets.GH_NPM_REGISTRY_TOKEN }}
@@ -12,11 +13,12 @@ env:
1213
DO_NOT_TRACK: 1
1314

1415
concurrency:
15-
group: ${{ github.workflow }}
16+
group: ${{ github.workflow }}-${{ github.ref }}
1617
cancel-in-progress: false
1718

1819
jobs:
1920
release:
21+
if: "!contains(github.event.head_commit.message, '[skip ci]')"
2022
name: Release and Publish
2123
runs-on: ubuntu-latest
2224
permissions:

CONTRIBUTING.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,75 @@ feat(apollo-react): add ApButton variant
344344
feat(apollo-core): add new color token for button variant
345345
```
346346

347+
## Maintenance Releases
348+
349+
Maintenance branches allow backporting fixes to older major versions after a new major version has been released. For example, releasing `@uipath/apollo-react@3.70.4` after `4.0.0` ships.
350+
351+
### Branch Naming
352+
353+
Maintenance branches are package-scoped: `release/<package-name>@<major>.x`
354+
355+
Examples: `release/apollo-react@3.x`, `release/apollo-core@5.x`
356+
357+
### When to Create a Maintenance Branch
358+
359+
Create one when you ship a new major version and need to continue supporting the previous major for existing consumers.
360+
361+
### Creating a Maintenance Branch
362+
363+
Use the helper script:
364+
365+
```bash
366+
scripts/create-maintenance-branch.sh apollo-react 3
367+
```
368+
369+
This will:
370+
1. Find the latest `@uipath/apollo-react@3.*` tag
371+
2. Create `release/apollo-react@3.x` from that tag
372+
3. Configure semantic-release on the new branch
373+
4. Print next steps
374+
375+
After running the script:
376+
1. Push the maintenance branch: `git push -u origin 'release/apollo-react@3.x'`
377+
2. On `main`, update `packages/apollo-react/.releaserc.json` to add the maintenance branch entry **before** `"main"` in the `branches` array:
378+
```json
379+
"branches": [
380+
{ "name": "release/apollo-react@3.x", "range": "3.x", "channel": "release-3.x" },
381+
"main"
382+
]
383+
```
384+
385+
### Backporting Fixes
386+
387+
Cherry-pick from `main` or create a PR targeting the maintenance branch directly:
388+
389+
```bash
390+
git checkout release/apollo-react@3.x
391+
git cherry-pick <sha>
392+
git push
393+
# → CI releases apollo-react@3.70.4 with dist-tag `release-3.x`
394+
```
395+
396+
### Installing Maintenance Releases
397+
398+
Maintenance releases publish under a dedicated npm dist-tag (not `latest`):
399+
400+
```bash
401+
# Install latest maintenance release for 3.x
402+
npm install @uipath/apollo-react@release-3.x
403+
404+
# Install a specific version
405+
npm install @uipath/apollo-react@3.70.4
406+
```
407+
408+
### Cross-Package Fixes
409+
410+
If a fix touches multiple packages (e.g., `apollo-core` and `apollo-react`), add the maintenance branch entry to each package's `.releaserc.json`. Both packages will be released from the same push.
411+
412+
### How Other Packages Behave
413+
414+
When CI runs `pnpm release` on a maintenance branch, semantic-release executes for all packages. Packages whose `.releaserc.json` doesn't list the branch simply skip with exit code 0 — no special handling needed.
415+
347416
## Package Structure
348417

349418
```

packages/apollo-core/.releaserc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
[
3131
"@semantic-release/exec",
3232
{
33-
"publishCmd": "bash ../../scripts/publish-to-registries.sh --no-git-checks --access public"
33+
"publishCmd": "bash ../../scripts/publish-to-registries.sh --no-git-checks --access public --tag ${nextRelease.channel || 'latest'}"
3434
}
3535
],
3636
[

packages/apollo-react/.releaserc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
[
3131
"@semantic-release/exec",
3232
{
33-
"publishCmd": "bash ../../scripts/publish-to-registries.sh --no-git-checks --access public"
33+
"publishCmd": "bash ../../scripts/publish-to-registries.sh --no-git-checks --access public --tag ${nextRelease.channel || 'latest'}"
3434
}
3535
],
3636
[

packages/apollo-wind/.releaserc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
[
3131
"@semantic-release/exec",
3232
{
33-
"publishCmd": "bash ../../scripts/publish-to-registries.sh --no-git-checks --access public"
33+
"publishCmd": "bash ../../scripts/publish-to-registries.sh --no-git-checks --access public --tag ${nextRelease.channel || 'latest'}"
3434
}
3535
],
3636
[
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#!/bin/bash
2+
# Create a maintenance branch for an older major version of a package.
3+
#
4+
# Usage: scripts/create-maintenance-branch.sh <package-name> <major-version>
5+
# Example: scripts/create-maintenance-branch.sh apollo-react 3
6+
#
7+
# This script:
8+
# 1. Finds the latest git tag for @uipath/<package>@<major>.*
9+
# 2. Creates release/<package>@<major>.x branch from that tag
10+
# 3. Updates the package's .releaserc.json with maintenance branch config
11+
# 4. Commits the config change
12+
# 5. Prints next steps (push, update main's .releaserc.json)
13+
14+
set -euo pipefail
15+
16+
PACKAGE="${1:?Usage: $0 <package-name> <major-version>}"
17+
MAJOR="${2:?Usage: $0 <package-name> <major-version>}"
18+
19+
if ! [[ "$MAJOR" =~ ^[0-9]+$ ]]; then
20+
echo "Error: major version must be a number, got '$MAJOR'"
21+
exit 1
22+
fi
23+
24+
TAG_PATTERN="@uipath/${PACKAGE}@${MAJOR}.*"
25+
BRANCH="release/${PACKAGE}@${MAJOR}.x"
26+
CHANNEL="release-${MAJOR}.x"
27+
28+
# Find package directory
29+
if [ -d "packages/${PACKAGE}" ]; then
30+
RELEASERC="packages/${PACKAGE}/.releaserc.json"
31+
elif [ -d "web-packages/${PACKAGE}" ]; then
32+
RELEASERC="web-packages/${PACKAGE}/.releaserc.json"
33+
else
34+
echo "Error: package '${PACKAGE}' not found in packages/ or web-packages/"
35+
exit 1
36+
fi
37+
38+
# Find latest tag for this major version
39+
LATEST_TAG=$(git tag --list "${TAG_PATTERN}" --sort=-version:refname | head -1)
40+
41+
if [ -z "$LATEST_TAG" ]; then
42+
echo "Error: no tags found matching '${TAG_PATTERN}'"
43+
echo ""
44+
echo "Available tags for @uipath/${PACKAGE}:"
45+
git tag --list "@uipath/${PACKAGE}@*" --sort=-version:refname | head -5
46+
exit 1
47+
fi
48+
49+
echo "Latest tag: ${LATEST_TAG}"
50+
echo "Branch: ${BRANCH}"
51+
echo "Channel: ${CHANNEL}"
52+
echo ""
53+
54+
# Check if branch already exists
55+
if git show-ref --verify --quiet "refs/heads/${BRANCH}" 2>/dev/null || \
56+
git show-ref --verify --quiet "refs/remotes/origin/${BRANCH}" 2>/dev/null; then
57+
echo "Error: branch '${BRANCH}' already exists"
58+
exit 1
59+
fi
60+
61+
if ! command -v jq &> /dev/null; then
62+
echo "Error: jq is required. Install with: brew install jq"
63+
exit 1
64+
fi
65+
66+
# Create branch from tag
67+
git checkout -b "${BRANCH}" "${LATEST_TAG}"
68+
69+
# Update .releaserc.json — add maintenance branch entry before "main"
70+
jq --arg name "${BRANCH}" \
71+
--arg range "${MAJOR}.x" \
72+
--arg channel "${CHANNEL}" \
73+
'.branches = [{"name": $name, "range": $range, "channel": $channel}, "main"]' \
74+
"${RELEASERC}" > "${RELEASERC}.tmp" && mv "${RELEASERC}.tmp" "${RELEASERC}"
75+
76+
echo "✓ Updated ${RELEASERC}"
77+
echo ""
78+
79+
# Commit the change
80+
git add "${RELEASERC}"
81+
git commit -m "ci(${PACKAGE}): configure maintenance branch for ${MAJOR}.x [skip ci]"
82+
83+
echo ""
84+
echo "✓ Branch '${BRANCH}' created and configured"
85+
echo ""
86+
echo "Next steps:"
87+
echo ""
88+
echo " 1. Push the branch:"
89+
echo " git push -u origin '${BRANCH}'"
90+
echo ""
91+
echo " 2. On main, update ${RELEASERC} to add this entry"
92+
echo " BEFORE \"main\" in the branches array:"
93+
echo ""
94+
echo " {\"name\": \"${BRANCH}\", \"range\": \"${MAJOR}.x\", \"channel\": \"${CHANNEL}\"}"
95+
echo ""
96+
echo " Example .releaserc.json branches on main:"
97+
echo " \"branches\": ["
98+
echo " {\"name\": \"${BRANCH}\", \"range\": \"${MAJOR}.x\", \"channel\": \"${CHANNEL}\"},"
99+
echo " \"main\""
100+
echo " ]"

web-packages/ap-chat/.releaserc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
[
3131
"@semantic-release/exec",
3232
{
33-
"publishCmd": "bash ../../scripts/publish-to-registries.sh --no-git-checks --access public"
33+
"publishCmd": "bash ../../scripts/publish-to-registries.sh --no-git-checks --access public --tag ${nextRelease.channel || 'latest'}"
3434
}
3535
],
3636
[

0 commit comments

Comments
 (0)