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"
110name : Package build and publish
211
312on :
1928jobs :
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
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"
0 commit comments