[CLNP-8355] [ci]: add automated release workflow and update CI to Node 24#1414
Conversation
✅ Deploy Preview for sendbird-uikit-react ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0fd80e71ef
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
… workflow to merge before publish
…flow shell commands Prevent potential shell injection by using env variables for github.ref_name and github.event.repository.name. Improve rollback step to check existence before reinstalling dependencies instead of silently swallowing errors. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…n release workflow Use python3 import check instead of command -v for requests package detection. Change contents permission from read to write for git tag push. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bfdf72b909
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| git fetch origin main | ||
| git switch main | ||
| git pull origin main | ||
|
|
||
| - name: Publish to npm | ||
| run: | | ||
| cd ./dist | ||
| npm publish --access=public --provenance |
There was a problem hiding this comment.
Rebuild dist after pulling main before npm publish
The workflow builds dist before merging/pulling main and then publishes without rebuilding, so the published tarball can come from the pre-merge release-branch contents rather than the commit that gets tagged/released on main. This mismatch is possible whenever main has moved or merge resolution changes files, and it can ship artifacts that do not match the Git tag/source of record.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
merge 후 yarn install --immutable && yarn build로 rebuild 스텝을 추가했습니다. 이제 publish되는 tarball이 main merge 후 코드와 일치합니다. (dbf4b11e)
| ['jest-junit', { | ||
| outputDirectory: './test-results', | ||
| outputName: 'junit-report.xml', | ||
| }], |
There was a problem hiding this comment.
Configure jest-junit to emit file paths for retry logic
scripts/failed-test-retry.js only retries failures when each failed <testsuite> includes a file attribute, but the new reporter config does not enable that output. As a result, on failed test runs the retry step often finds zero failed files and exits, so the flaky-test retry path never actually works even though CI now depends on this report.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
addFileAttribute: 'true' 추가하여 JUnit 리포트에 file 속성이 출력되도록 수정했습니다. 이제 failed-test-retry.js가 실패 테스트 파일을 정상적으로 파싱합니다. (dbf4b11e)
Rebuild dist after merging to main so the published tarball matches the tagged commit. Add addFileAttribute to jest-junit config so the retry script can locate failed test files. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
| @@ -0,0 +1,5 @@ | |||
| ### Features | |||
There was a problem hiding this comment.
github에서 release tag 생성에 필요해서 추가 하신거 같은데, 최종 chagelog.md로 update는 언제 하게 되나요?
There was a problem hiding this comment.
prepare-changelog 워크플로우를 추가해서 자동화했습니다. release 브랜치 push 시 CHANGELOG_DRAFT.md 내용이 CHANGELOG.md에 자동으로 prepend되고, 실제 릴리즈 시점에 release-workflow가 날짜를 확정합니다. 개발자는 CHANGELOG_DRAFT.md만 작성하면 됩니다.
감사합니다!
- Add prepare-changelog.yml: prepends/replaces section in CHANGELOG.md when CHANGELOG_DRAFT.md or package.json changes on release/v* branches. Skips on bot's own commits (author email check) and empty draft templates. - Add scripts/update-changelog.js: idempotent prepend/replace logic that handles multi-major-version eras (e.g., # Changelog - v3 / v4) and preserves the blank line after the H1 header. - Update release-workflow.yml: add "Finalize CHANGELOG.md date" step on release branch before merge so the date in CHANGELOG.md matches the actual release day, not the last manual edit. - CHANGELOG.md: add blank line after header for readability. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CHANGELOG_DRAFT.md is no longer reset to template after release, so the exact-template comparison would never trigger after the first release. PR review remains the safety net for stale draft content. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- release-workflow: remove continue-on-error from "Finalize CHANGELOG.md
date" step. Silent failure would let npm publish/tag/release proceed
with a stale date, defeating the purpose of the step. Fail-fast keeps
CHANGELOG.md and release artifacts in sync.
- package-publish: move workflow_dispatch inputs (version, npm_tag,
tag_suffix) to job-level env and add semver/charset validation. Replace
remaining ${{ github.event.inputs.* }} interpolations in run blocks
with quoted "$VAR" references to prevent shell injection. Also move
NPM_TOKEN secret into env to match the same pattern.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pre-release gate that runs after Extract release version and before Finalize CHANGELOG.md date. Fails the release if: - CHANGELOG.md does not have v$VERSION as its most recent entry (means prepare-changelog never ran on the release branch). - CHANGELOG_DRAFT.md is byte-identical to the previous release's section body in CHANGELOG.md (means the developer forgot to update the draft and the previous release notes would be re-published). This catches stale-draft scenarios that would otherwise rely solely on PR review to notice. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a third failure case to check-changelog-draft.js: if the draft is byte-identical to the placeholder template (### Features / - Added ... / ### Fixes / - Fixed a bug where ...), fail the release before publishing. Without this gate, an accidentally reset/empty draft would have published placeholder copy to npm, the GitHub Release page, and Jira. Also drops a redundant `.replace(/\s+$/, '').trim()` chain in favor of just `.trim()`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two safety gates added to release-workflow: - Validate branch is a release branch: reject dispatch from non-release branches (main, feature/*, etc.) or non-semver release branches. workflow_dispatch lets admins pick any ref, and downstream steps assume release/vX.Y.Z without an internal guard. Now we fail fast with a clear error instead of relying on extract_version.py behavior. - Wait for required checks on release branch: after Finalize pushes a new commit, build-and-test re-runs and the commit's check is pending. Without waiting, the immediate Merge step could either fail (strict branch protection) or merge an unverified commit (if the bot bypasses protection). Use `gh pr checks --watch --required` so we explicitly wait for required checks to pass; 30min timeout caps stuck states. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
After the Finalize step pushes a commit, GitHub takes a few seconds to register the build-and-test workflow run. Without this delay, `gh pr checks --watch --required` could observe no checks on the latest commit and exit 0 immediately, defeating the wait. A 15s sleep covers the registration window; if Finalize made no commit, the existing check status is already terminal and watch returns quickly anyway. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adopts the approach from #1413 directly so that both release-workflow.yml (already OIDC) and package-publish.yml authenticate the same way: - Add permissions: id-token: write, contents: read at job level - Drop NPM_TOKEN env and the .npmrc auth setup - Add --provenance to both npm publish commands so the published tarballs carry GitHub Actions provenance attestations - Add an "Update npm to latest" step because OIDC trusted publishing requires npm 11+ and Node 18 ships with an older bundled npm The hardening already in this branch (input validation step, env-based version/npm_tag/tag_suffix references, `set -x` in branch existence check) is preserved. PR 1413 can be closed since this commit supersedes its package-publish.yml changes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Match release-workflow.yml's `contents: write` so both workflows declare the same permission set. Functionally either works since git operations use the bot token, but consistency makes future audits simpler. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two prerequisites for npm Trusted Publishing flagged in code review: 1. Bump package-publish.yml Node version 18.x → 24 npm Trusted Publishing requires npm CLI 11.5.1+ and Node 22.14.0+. Node 18 with `npm install -g npm@latest` is still unsupported because the Node version itself is too old. Aligning with release-workflow.yml which already uses Node 24. 2. Correct repository.url in package template scripts/post_build.js generates dist/package.json from scripts/package.template.json, so the template's repository.url is what npm registry sees. Both the template and the root package.json pointed at sendbird-uikit-react-sources.git while origin is sendbird-uikit-react.git. npm Trusted Publishing verifies that repository.url matches the publishing GitHub repo, so the mismatch would fail OIDC validation. Updated both files to the correct repo and switched to https URL form per npm convention. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
npm OIDC Trusted Publishing supports only one publisher configuration per package. The default is release-workflow.yml (automated production releases). Running package-publish.yml requires temporarily switching the npm Trusted Publisher's workflow filename, then restoring it. Add an explicit comment at the top of package-publish.yml describing this operational requirement so the dependency is visible to anyone about to dispatch the workflow. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The new automation introduced in this PR (release-workflow.yml + prepare-changelog.yml + check-changelog-draft.js) supersedes the manual process described in RELEASE_GUIDE.md. The remaining internal release narrative (Jira ticket flow, Slack channel, bot account, pr-comment-bot) is operational detail that does not belong in a public OSS repository. Removed files: - RELEASE_GUIDE.md (no other file references it) - screenshots/workflow-guide.png (only referenced by RELEASE_GUIDE.md) Internal release procedure now lives only in the workspace-level HOW_TO_RELEASE.md kept alongside other Sendbird internal docs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
workflow_dispatch lets the operator pick any ref. Previously, dispatching from main with version=3.18.0 would still pass the existing branch existence check (release/v3.18.0 exists on origin) and then build dist from main and publish it as v3.18.0. Now we fail fast if github.ref_name does not equal release/v$VERSION, so the published artifact always comes from the matching release branch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Match build-and-test.yml and release-workflow.yml which already pin deps with --immutable. Plain `yarn install` would silently update the lockfile during a manual publish, so the published artifact could diverge from what was committed and reviewed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two input combos previously slipped through validation: 1. version=X.Y.Z-pre with no npm_tag → publishes to the default 'latest' dist-tag, so a prerelease becomes what `npm install pkg` resolves to. 2. tag_suffix without npm_tag → "Update version in package.json" step is gated on npm_tag, so tag_suffix is silently ignored and the publish proceeds as a stable release. Add a combo check after the per-input regex validation: when npm_tag is empty, version must not contain '-' and tag_suffix must be empty. Operators who really want a prerelease publish must explicitly provide npm_tag (beta, rc, etc.). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…tag=latest Two further input combos that bypassed the previous combo check: - version=X.Y.Z-pre with npm_tag=anything would still publish, but the resulting npm version (X.Y.Z-pre-NPM_TAG) is nonsensical. Since this workflow is supposed to build prerelease versions by combining a stable version + npm_tag (+ optional tag_suffix), VERSION should always be stable X.Y.Z. - npm_tag=latest with a prerelease version was not blocked by the earlier "npm_tag empty" combo check, so a prerelease could still land on the latest dist-tag. Tighten the rules: - VERSION must match ^X.Y.Z$ (no prerelease suffix). - npm_tag is optional but cannot be 'latest'; leave it empty for a stable publish to default latest. - tag_suffix still requires npm_tag. The earlier "npm_tag empty + version contains -" guard becomes unreachable under the stricter VERSION regex and is removed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Semver 2.0 prerelease and build identifiers allow only [0-9A-Za-z.-]. The previous regex permitted underscore (_), so an input like npm_tag=beta_0 would produce npm version 3.18.0-beta_0, which is invalid semver and fails at npm publish. Drop _ from the allowed character set so we fail at validation with a clear error instead of partway through the build. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous regex (^[0-9A-Za-z.-]+$) only checked the character set, so beta., .beta, and beta..0 all passed. When combined into a version suffix (e.g., 3.18.0-beta.) the result is invalid semver and npm publish would fail mid-flight. Switch to ^[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*$ which mirrors the semver 2.0 prerelease identifier rule: each dot-separated identifier must be non-empty and use only [0-9A-Za-z-]. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three fixes from code review:
1. package-publish.yml — combined semver validation
- Previous regex only checked the prerelease character set.
beta.01 passed but 3.18.0-beta.01 is invalid semver (semver 2.0
forbids leading zeros in numeric identifiers).
- 1.0 / v1.4 also passed but npm rejects dist-tags that parse as
semver/range.
- Add a check that NPM_TAG does not match ^v?N(\.N)+$, then build
the candidate npm version and validate against the full semver 2.0
regex. Fails fast with the constructed string in the error message.
2. scripts/check-changelog-draft.js — empty-draft guard
- An empty CHANGELOG_DRAFT.md was distinct from both the placeholder
template and the previous release body, so it slipped through and
the GitHub Release would have been created with an empty body.
Add `if (!draft) exit 1` right after reading the file.
3. scripts/failed-test-retry.js — parse <testcase> file attribute too
- jest-junit's addFileAttribute behavior varies by version. The
existing parser only looked at <testsuite>; if the file attribute
ends up on <testcase> the retry script reports zero failed files
and the retry path silently does nothing. Add a fallback regex
that picks up <testcase file="..."> entries containing a <failure>
or <error> child.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous semver-range check only caught strict numeric forms like 1.0 or v1.4. npm dist-tags also reject other semver-parseable values (1.x, 1.2.x, v1.x, 1.2.3-beta, etc.), and the manual publish would fail late at npm publish --tag. The simplest way to cover all parseable forms is to forbid npm_tag from starting with a digit or v/V. Conventional dist-tags (beta, rc, next, canary) all start with a letter and pass; numeric-led inputs are rejected up front with a clear error. Reference: https://docs.npmjs.com/cli/v8/commands/npm-dist-tag#caveats Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous import:
import pkg from "./package.json" with {type: "json"};
uses JSON import attributes, which Node only supports from 18.20.0 /
20.10.0 onward. package.json declares engines.node: ">=18", so any
Node 18.0.0–18.19.x environment running `yarn build` would fail at
config parse time.
Switch to createRequire(import.meta.url) which is supported across
the whole Node 18 line, keeping the engines.node range honest. Library
consumers (who only consume dist/) are unaffected — this only matters
for environments that build the package.
Reference: https://nodejs.org/api/esm.html#import-attributes
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Document the fix for invisible zero-width spaces inserted during paste in MessageInput that could be included in sent or updated messages. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add Jira-integrated automated release workflow and modernize CI infrastructure.
Release Automation (
release-workflow.yml- new)CHANGELOG_DRAFT.mdfor GitHub Release body to avoid duplicate titlesCI Updates
actions/checkoutv4 → v6,actions/setup-nodev4 → v6 across all workflowsbuild-and-test.ymlNode version from 16.19.1 → 24 (LTS Krypton)npm_token→NPM_TOKENinpackage-publish.ymlNew Files
CHANGELOG_DRAFT.md: template for per-release changelog (used by release workflow and Jira ticket)Fixes CLNP-8355
Changelogs
CHANGELOG_DRAFT.mdtemplate for release notesChecklist