Skip to content

Commit 835ac89

Browse files
Merge pull request #1414 from sendbird/feature/CLNP-8355
[CLNP-8355] [ci]: add automated release workflow and update CI to Node 24
2 parents 8764631 + ecce64d commit 835ac89

19 files changed

Lines changed: 724 additions & 68 deletions

.github/workflows/build-and-test.yml

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ on:
77
push:
88
branches:
99
- main
10+
- release/**
1011
concurrency:
1112
group: build-and-test-${{ github.head_ref || github.ref_name }}
1213
cancel-in-progress: true
@@ -17,12 +18,12 @@ jobs:
1718

1819
steps:
1920
- name: Checkout code
20-
uses: actions/checkout@v4
21+
uses: actions/checkout@v6
2122

2223
- name: Setup Node.js
23-
uses: actions/setup-node@v4
24+
uses: actions/setup-node@v6
2425
with:
25-
node-version: '16.19.1'
26+
node-version: '24'
2627
cache: 'yarn'
2728

2829
- name: Install dependencies
@@ -43,4 +44,12 @@ jobs:
4344
if: ${{ success() }}
4445
timeout-minutes: 15
4546
run: |
46-
yarn test --forceExit --runInBand
47+
yarn test --forceExit --runInBand || {
48+
if [ -f "./test-results/junit-report.xml" ]; then
49+
echo "Tests failed. Retrying failed tests..."
50+
node scripts/failed-test-retry.js
51+
else
52+
echo "Tests failed and no JUnit report found."
53+
exit 1
54+
fi
55+
}

.github/workflows/coverage.yml

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
1+
name: Coverage Report
2+
3+
# Manual trigger only. To restore PR comment trigger, replace workflow_dispatch with:
4+
# on:
5+
# issue_comment:
6+
# types: [created, edited]
7+
# And add this condition to the job:
8+
# if: github.event.issue.pull_request && contains(github.event.comment.body, './coverage')
9+
110
on:
2-
issue_comment:
3-
types: [created, edited]
11+
workflow_dispatch:
412

513
jobs:
6-
coverage:
7-
runs-on: ubuntu-latest
8-
if: github.event.issue.pull_request && contains(github.event.comment.body, './coverage')
9-
steps:
10-
- uses: actions/checkout@v3
11-
- uses: ArtiomTr/jest-coverage-report-action@v2
14+
coverage:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/checkout@v6
18+
- uses: ArtiomTr/jest-coverage-report-action@v2

.github/workflows/package-publish.yml

Lines changed: 89 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
# Manual publish workflow (typically for beta/RC releases).
2+
#
3+
# IMPORTANT: npm OIDC trusted publishing allows only one publisher
4+
# configuration per package. The default is set to release-workflow.yml.
5+
# Before dispatching this workflow:
6+
# 1. Open the package on npmjs.com → Settings → "Trusted publisher"
7+
# 2. Change the workflow filename to "package-publish.yml"
8+
# 3. Run this workflow
9+
# 4. Restore the workflow filename to "release-workflow.yml"
110
name: Package build and publish
211

312
on:
@@ -19,19 +28,86 @@ on:
1928
jobs:
2029
publish:
2130
runs-on: ubuntu-latest
31+
permissions:
32+
id-token: write
33+
contents: write
34+
env:
35+
SKIP_REST: '' # Set to 'true' when npm_tag is provided
36+
VERSION: ${{ github.event.inputs.version }}
37+
NPM_TAG: ${{ github.event.inputs.npm_tag }}
38+
TAG_SUFFIX: ${{ github.event.inputs.tag_suffix }}
39+
BRANCH_NAME: ${{ github.ref_name }}
2240
steps:
23-
- uses: actions/checkout@v4
41+
- name: Validate dispatch inputs
42+
run: |
43+
# VERSION must be stable X.Y.Z. Prerelease versions are built up via
44+
# npm_tag (+ optional tag_suffix), e.g., 3.18.0 + beta + 0 => 3.18.0-beta-0.
45+
if ! printf '%s' "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
46+
echo "Invalid version: '$VERSION' (expected stable X.Y.Z; use npm_tag for prerelease)"
47+
exit 1
48+
fi
49+
if [ -n "$NPM_TAG" ]; then
50+
if ! printf '%s' "$NPM_TAG" | grep -qE '^[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*$'; then
51+
echo "Invalid npm_tag: '$NPM_TAG'"
52+
exit 1
53+
fi
54+
if [ "$NPM_TAG" = "latest" ]; then
55+
echo "npm_tag 'latest' is not allowed; leave npm_tag empty for a stable publish."
56+
exit 1
57+
fi
58+
fi
59+
if [ -n "$TAG_SUFFIX" ]; then
60+
if ! printf '%s' "$TAG_SUFFIX" | grep -qE '^[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*$'; then
61+
echo "Invalid tag_suffix: '$TAG_SUFFIX'"
62+
exit 1
63+
fi
64+
if [ -z "$NPM_TAG" ]; then
65+
echo "tag_suffix requires npm_tag. Provide npm_tag (e.g., beta) or remove tag_suffix."
66+
exit 1
67+
fi
68+
fi
69+
# npm rejects dist-tags that can be parsed as a semver version or range
70+
# (e.g. 1.0, v1.4, 1.x, 1.2.x, 1.2.3-beta). The simplest way to cover
71+
# all of these is to forbid leading digits and a leading v/V.
72+
if [ -n "$NPM_TAG" ] && printf '%s' "$NPM_TAG" | grep -qE '^([0-9]|[vV])'; then
73+
echo "npm_tag '$NPM_TAG' starts with a digit or v/V; npm rejects such dist-tags (interpreted as a semver version/range)."
74+
exit 1
75+
fi
76+
# Validate the constructed npm version against semver 2.0 (catches things like
77+
# beta.01 → 3.18.0-beta.01, which is rejected by the spec for leading zeros)
78+
candidate_version="$VERSION"
79+
if [ -n "$NPM_TAG" ]; then
80+
if [ -z "$TAG_SUFFIX" ]; then
81+
candidate_version="$VERSION-$NPM_TAG"
82+
else
83+
candidate_version="$VERSION-$NPM_TAG-$TAG_SUFFIX"
84+
fi
85+
fi
86+
semver_re='^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-(0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*))*)?$'
87+
if ! printf '%s' "$candidate_version" | grep -qE "$semver_re"; then
88+
echo "Constructed npm version '$candidate_version' is not valid semver 2.0."
89+
exit 1
90+
fi
91+
- name: Validate dispatch ref matches release branch
92+
run: |
93+
expected="release/v$VERSION"
94+
if [ "$BRANCH_NAME" != "$expected" ]; then
95+
echo "Dispatched from '$BRANCH_NAME' but version input is $VERSION."
96+
echo "Re-dispatch this workflow with the correct ref ($expected) selected in the GitHub Actions UI."
97+
exit 1
98+
fi
99+
- uses: actions/checkout@v6
24100
with:
25101
token: ${{ secrets.SDK_GH_BOT1_TOKEN }}
26102
fetch-depth: 0
27-
- uses: actions/setup-node@v4
103+
- uses: actions/setup-node@v6
28104
with:
29-
node-version: 18.x
105+
node-version: '24'
30106
cache: 'yarn'
31107
- name: Check if the release branch exists
32108
run: |
33109
set -x
34-
branch_name="release/v${{ github.event.inputs.version }}"
110+
branch_name="release/v$VERSION"
35111
if ! git ls-remote --exit-code --heads origin "$branch_name" > /dev/null; then
36112
echo "Branch $branch_name does not exist. Make sure to create the branch and create a Jira ticket with pr-comment-bot."
37113
exit 1
@@ -42,10 +118,10 @@ jobs:
42118
- name: Update version in package.json if npm_tag is provided
43119
if: ${{ github.event.inputs.npm_tag }}
44120
run: |
45-
if [ -z "${{ github.event.inputs.tag_suffix }}" ]; then
46-
npm_version="${{ github.event.inputs.version }}-${{ github.event.inputs.npm_tag }}"
121+
if [ -z "$TAG_SUFFIX" ]; then
122+
npm_version="$VERSION-$NPM_TAG"
47123
else
48-
npm_version="${{ github.event.inputs.version }}-${{ github.event.inputs.npm_tag }}-${{ github.event.inputs.tag_suffix }}"
124+
npm_version="$VERSION-$NPM_TAG-$TAG_SUFFIX"
49125
fi
50126
jq --arg npm_version "$npm_version" '.version = $npm_version' package.json > package.json.tmp && mv package.json.tmp package.json
51127
- name: Set environments
@@ -54,16 +130,15 @@ jobs:
54130
git config --global user.email "sha.sdk_deployment@sendbird.com"
55131
- name: Install and Build
56132
run: |
57-
yarn install
133+
yarn install --immutable
58134
yarn build
59135
- name: Publish to npm
60136
run: |
61137
cd ./dist
62-
echo "//registry.npmjs.org/:_authToken=${{ secrets.npm_token }}" > .npmrc
63-
if [ -z "${{ github.event.inputs.npm_tag }}" ]; then
64-
npm publish --access=public
138+
if [ -z "$NPM_TAG" ]; then
139+
npm publish --access=public --provenance
65140
else
66-
npm publish --tag ${{ github.event.inputs.npm_tag }} --access=public
141+
npm publish --tag "$NPM_TAG" --access=public --provenance
67142
echo "npm_tag is provided; Skipping the rest of the steps."
68143
echo "SKIP_REST=true" >> $GITHUB_ENV
69144
fi
@@ -99,5 +174,5 @@ jobs:
99174
- name: Tag new target and push to origin
100175
if: env.SKIP_REST != 'true'
101176
run: |
102-
git tag v${{ github.event.inputs.version }}
103-
git push origin v${{ github.event.inputs.version }}
177+
git tag "v$VERSION"
178+
git push origin "v$VERSION"

.github/workflows/pr-comment-bot.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
if : ${{ github.event.issue.pull_request}}
99
runs-on: ubuntu-latest
1010
steps:
11-
- uses: actions/checkout@v4
11+
- uses: actions/checkout@v6
1212
- uses: sendbird/release-automation-action@latest
1313
with:
1414
gh_token: ${{ secrets.SDK_GH_BOT1_TOKEN }}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
name: Prepare CHANGELOG
2+
3+
on:
4+
push:
5+
branches:
6+
- 'release/v*'
7+
paths:
8+
- 'CHANGELOG_DRAFT.md'
9+
- 'package.json'
10+
11+
concurrency:
12+
group: prepare-changelog-${{ github.ref_name }}
13+
cancel-in-progress: false
14+
15+
jobs:
16+
prepare:
17+
runs-on: ubuntu-latest
18+
permissions:
19+
contents: write
20+
21+
env:
22+
BRANCH_NAME: ${{ github.ref_name }}
23+
BOT_EMAIL: 'sha.sdk_deployment@sendbird.com'
24+
BOT_NAME: 'sendbird-sdk-deployment'
25+
26+
steps:
27+
- name: Checkout
28+
uses: actions/checkout@v6
29+
with:
30+
token: ${{ secrets.SDK_GH_BOT1_TOKEN }}
31+
fetch-depth: 2
32+
ref: ${{ github.ref_name }}
33+
34+
- name: Skip if last commit was made by the release bot
35+
id: skip-bot
36+
run: |
37+
last_author=$(git log -1 --pretty=%ae)
38+
if [ "$last_author" = "$BOT_EMAIL" ]; then
39+
echo "Last commit author is the release bot ($BOT_EMAIL); skipping."
40+
echo "skip=true" >> "$GITHUB_OUTPUT"
41+
else
42+
echo "skip=false" >> "$GITHUB_OUTPUT"
43+
fi
44+
45+
- name: Setup Node.js
46+
if: steps.skip-bot.outputs.skip != 'true'
47+
uses: actions/setup-node@v6
48+
with:
49+
node-version: '24'
50+
51+
- name: Update CHANGELOG.md
52+
if: steps.skip-bot.outputs.skip != 'true'
53+
run: |
54+
VERSION="${BRANCH_NAME#release/v}"
55+
DATE=$(date -u '+%b %d %Y' | tr '[:lower:]' '[:upper:]')
56+
export VERSION DATE
57+
node scripts/update-changelog.js
58+
59+
- name: Commit and push CHANGELOG.md
60+
if: steps.skip-bot.outputs.skip != 'true'
61+
run: |
62+
if git diff --quiet CHANGELOG.md; then
63+
echo "CHANGELOG.md unchanged; nothing to commit."
64+
exit 0
65+
fi
66+
VERSION="${BRANCH_NAME#release/v}"
67+
git config user.email "$BOT_EMAIL"
68+
git config user.name "$BOT_NAME"
69+
git add CHANGELOG.md
70+
git commit -m "chore: prepare CHANGELOG.md for v${VERSION}"
71+
git push origin "$BRANCH_NAME"

0 commit comments

Comments
 (0)