diff --git a/.releaserc.json b/.releaserc.json index ef0917bc1..22889c80c 100644 --- a/.releaserc.json +++ b/.releaserc.json @@ -1,13 +1,13 @@ { "branches": [ { - "name": "release-v14", + "name": "master", "channel": "latest" }, { - "name": "master", - "prerelease": "rc", - "channel": "rc" + "name": "release-v14", + "channel": "v14", + "range": "14.x" } ], "plugins": [ diff --git a/AGENTS.md b/AGENTS.md index e34e3a28c..184481e15 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -10,7 +10,7 @@ Agents should prioritize API stability and high test coverage when changing code Stream's React Chat SDK — React components, hooks and contexts for building chat UIs on the Stream Chat API. The published package (`stream-chat-react`) lives at the repo root; `examples/*` are private Yarn workspaces consuming it via `workspace:^`. -This is the **v15** line, developed on `master` and published as release candidates (npm `rc`). The stable v14 line lives on `release-v14` (npm `latest`). It is built on `stream-chat` v10 (the "LLC"), which owns message, thread and composer state; this package renders it. +This is the **v15** line, developed on `master` and published under npm `latest`. The v14 maintenance line lives on `release-v14` (npm `release-v14`). It is built on `stream-chat` v10 (the "LLC"), which owns message, thread and composer state; this package renders it. ## Tech & toolchain @@ -443,7 +443,7 @@ Implement MediaRecorder API integration with MP3 encoding. Closes #123 ``` -- v15 is a major release line: a change that breaks the v14 API is marked with `!` and a `BREAKING CHANGE:` footer, and gets an entry in `ai-docs/ai-migration-v14-v15.md`. +- `master` publishes v15 under `latest`, so a commit marked with `!` or a `BREAKING CHANGE:` footer releases 16.0.0. Mark a commit as breaking only when the next major is planned (see `developers/BRANCHES.md`). - Never commit directly to `master` or `release-v14`; always create a feature branch (see `developers/BRANCHES.md`). v15 work targets `master`; v14 fixes target `release-v14`. - Never commit unless explicitly requested. diff --git a/developers/BRANCHES.md b/developers/BRANCHES.md index dae75e781..06aee03fd 100644 --- a/developers/BRANCHES.md +++ b/developers/BRANCHES.md @@ -2,21 +2,25 @@ We have two base branches: -- `master` — the v15 line. Releases from it are published as release candidates (`15.0.0-rc.N`) under the npm `rc` tag. -- `release-v14` — the stable v14 line. Releases from it are published under the npm `latest` tag. +- `master` — the v15 line. Releases from it are published under the npm `latest` tag. +- `release-v14` — the v14 maintenance line. Releases from it are published under the npm `release-v14` tag (`npm install stream-chat-react@release-v14`). + +Older lines (`release-v13`, `release-v12`, …) are maintenance branches as well, published under the npm `release-v13`, `release-v12`, … tags. If you want to implement a solution, create a branch from the base branch it belongs to: `master` for v15 work, `release-v14` for a v14 fix. A base branch should receive updates only through squash-merging feature branches - each of these squashed commits should be up to date with its base branch and should be passing CI requirements. A fix that applies to both lines is merged into `release-v14` and ported to `master`. -`release-v14` must not receive breaking changes (`!` or a `BREAKING CHANGE:` footer). It is the release branch in `.releaserc.json`, which semantic-release cannot limit to `14.x`, so a breaking change there would publish v15 under `latest`. +`release-v14` accepts only 14.x releases and must not receive breaking changes. It is a maintenance branch in `.releaserc.json` (`"range": "14.x"`), so semantic-release refuses a release that would leave 14.x: a `fix:` or `feat:` commit with a `BREAKING CHANGE:` footer makes the release fail with `EINVALIDNEXTVERSION` instead of publishing v15. Its commit analyzer uses the `angular` preset, which does not read `!` in a header, so a `fix!:` commit on `release-v14` releases nothing. + +A breaking change on `master` releases the next major (16.0.0) under `latest`. Mark a commit on `master` as breaking only when the next major is planned. The branch architecture in this repository is as follows: ```shell -NPM (rc) <--- master <--- branch_solution_x - <--- branch_solution_y - ... -NPM (latest) <--- release-v14 <--- branch_fix_x - ... +NPM (latest) <--- master <--- branch_solution_x + <--- branch_solution_y + ... +NPM (release-v14) <--- release-v14 <--- branch_fix_x + ... ``` diff --git a/developers/RELEASE.md b/developers/RELEASE.md index 74bdd012d..6f617fcd8 100644 --- a/developers/RELEASE.md +++ b/developers/RELEASE.md @@ -9,13 +9,29 @@ The `stream-chat-react` package follows semantic versioning and the release is t In order to get the above generated outputs, each contributor should follow [Angular's Commit Message Format rules](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-format). +## Branches and npm dist-tags + +The Release workflow runs `semantic-release` on the branch you pick, so that branch's own `.releaserc.json` decides where its releases go. `master` and `release-v14` keep the same `branches` list: + +| Branch | Entry in `branches` | Versions | npm dist-tag | +| ------------- | -------------------------------------------------------------- | -------- | ------------- | +| `master` | `{ "name": "master", "channel": "latest" }` | 15.x | `latest` | +| `release-v14` | `{ "name": "release-v14", "channel": "v14", "range": "14.x" }` | 14.x | `release-v14` | + +`@semantic-release/npm` publishes a release under its channel as the dist-tag, and prefixes a channel that reads as a version range with `release-`: the `v14` channel publishes under `release-v14`. Older maintenance branches work the same way (`release-v13` publishes under `release-v13`). + +A maintenance branch only publishes versions inside its `range`. If its commits call for a version outside it, for example 15.0.0 from a breaking change on `release-v14`, the release fails with `EINVALIDNEXTVERSION` and nothing is published. + ## Major version release preparations -We need to: +While the next major is in prerelease, `master` is a prerelease branch, for example `{ "name": "master", "prerelease": "rc", "channel": "rc" }`, and the previous line's branch (for example `release-v14`) is the release branch on `latest`. When the major goes GA: -1. Convert the current latest branch to a version branch by creating a PR with adjusted `.releaserc.json`. Example PR: https://github.com/GetStream/stream-chat-react/pull/2507 +1. Make the previous line a maintenance branch. On that branch, set the `branches` list in `.releaserc.json` to `master` on `latest` plus the branch with its own channel and range, as in the table above. Merge this first: once it is in, a release from that branch can no longer move `latest`. Example PR: https://github.com/GetStream/stream-chat-react/pull/3122 +2. On `master`, replace the prerelease entry with `{ "name": "master", "channel": "latest" }` and list the maintenance branch next to it, the same list as in step 1. Example PR: https://github.com/GetStream/stream-chat-react/pull/3121 +3. Run the Release workflow on `master`, with a dry run first. A release branch ignores the `-rc.N` tags, so `semantic-release` compares `master` with its last stable tag. The breaking commits since then make the release `X.0.0`, published under `latest`. No extra commit is needed. +4. Run the Release workflow on the maintenance branch once, at any time after step 1. With no new fixes it only adds the branch's last version to the branch's dist-tag (for example `14.16.1` to `release-v14`), so `npm install stream-chat-react@release-v14` works before the first maintenance release. The workflow publishes through npm trusted publishing (OIDC). If this step fails with `E401` on `npm dist-tag`, the package's trusted publisher settings on npmjs.com do not allow `npm dist-tag`: allow it, or add the tag by hand with `npm dist-tag add stream-chat-react@14.16.1 release-v14`. A re-run does not retry the step. -2. Configure the `master` branch back from `prerelease` to `latest` and add a config for the next version branch also designated as `latest`. Example PR: https://github.com/GetStream/stream-chat-react/pull/2506. +If step 3 runs before step 1, the next release from the previous line's branch publishes under `latest` and replaces the new major there. ## Required steps @@ -23,9 +39,9 @@ At the moment these manual actions have to be taken to achieve a successful rele 1. make sure that all the new required features and bug fixes in peer dependency repositories `@stream-io/stream-chat-css` and `stream-chat-js` are released 2. make sure that the peer dependencies `@stream-io/stream-chat-css` and `stream-chat-js` are installed at their latest version (see `package.json`, `yarn.lock`) (if applicable) -3. squash-merge required pull requests to `master` branch with appropriate message name, for example: `fix(scope): new feature`, if this feature is breaking, make sure to include `BREAKING CHANGE: ` in the message footer +3. squash-merge required pull requests to their base branch (`master` or `release-v14`) with appropriate message name, for example: `fix(scope): new feature`. A breaking change (`!` or a `BREAKING CHANGE: ` footer) releases a new major from `master`, so merge one only when the next major is planned (see `developers/BRANCHES.md`) 4. navigate to ["Actions"](https://github.com/GetStream/stream-chat-react/actions) and in the left bar select the "Release" workflow -5. click "Run workflow" and select the branch you want to release from then adjust the prompt options and click "Run workflow", note that allowed branches are branch names starting with `release`, `rc` and `master` (a dry run can use any branch), extend the workflow condition and `.releaserc.json` as needed. The `master` branch is the release-candidate branch. +5. click "Run workflow" and select the branch you want to release from then adjust the prompt options and click "Run workflow", note that allowed branches are branch names starting with `release`, `rc` and `master` (a dry run can use any branch), extend the workflow condition and `.releaserc.json` as needed. Releases from `master` go to `latest`, releases from `release-v14` to `release-v14` (see [Branches and npm dist-tags](#branches-and-npm-dist-tags)). ## Available release prompt options diff --git a/examples/ai-chatbot/package.json b/examples/ai-chatbot/package.json index b86d4558c..8761a810f 100644 --- a/examples/ai-chatbot/package.json +++ b/examples/ai-chatbot/package.json @@ -18,7 +18,7 @@ "next": "^16.2.4", "react": "^19.2.6", "react-dom": "^19.2.6", - "stream-chat": "10.0.0-rc.34", + "stream-chat": "^10.0.0", "stream-chat-react": "workspace:^" }, "devDependencies": { diff --git a/examples/cookbook/package.json b/examples/cookbook/package.json index d0a6e7283..e5bc996c8 100644 --- a/examples/cookbook/package.json +++ b/examples/cookbook/package.json @@ -19,7 +19,7 @@ "react": "^19.2.6", "react-dom": "^19.2.6", "react-leaflet": "^5.0.0", - "stream-chat": "10.0.0-rc.34", + "stream-chat": "^10.0.0", "stream-chat-react": "workspace:^" }, "devDependencies": { diff --git a/examples/tutorial/package.json b/examples/tutorial/package.json index 490d9424e..f10c2e936 100644 --- a/examples/tutorial/package.json +++ b/examples/tutorial/package.json @@ -16,7 +16,7 @@ "emoji-mart": "^5.6.0", "react": "^19.2.6", "react-dom": "^19.2.6", - "stream-chat": "10.0.0-rc.34", + "stream-chat": "^10.0.0", "stream-chat-react": "workspace:^" }, "devDependencies": { diff --git a/examples/vite/package.json b/examples/vite/package.json index 87935e5b0..35248b300 100644 --- a/examples/vite/package.json +++ b/examples/vite/package.json @@ -18,7 +18,7 @@ "modern-normalize": "^3.0.1", "react": "^19.2.6", "react-dom": "^19.2.6", - "stream-chat": "10.0.0-rc.34", + "stream-chat": "^10.0.0", "stream-chat-react": "workspace:^" }, "devDependencies": { diff --git a/package.json b/package.json index 387fbd8cc..6f0579f5f 100644 --- a/package.json +++ b/package.json @@ -163,7 +163,7 @@ "modern-normalize": "^3.0.1", "react": "^19.0.0 || ^18.0.0 || ^17.0.0", "react-dom": "^19.0.0 || ^18.0.0 || ^17.0.0", - "stream-chat": "^10.0.0-rc.34" + "stream-chat": "^10.0.0" }, "peerDependenciesMeta": { "@a2ui/react": { @@ -246,7 +246,7 @@ "react-dom": "^19.2.6", "sass": "^1.100.0", "semantic-release": "^25.0.3", - "stream-chat": "10.0.0-rc.34", + "stream-chat": "^10.0.0", "typescript": "^6.0.3", "typescript-eslint": "^8.59.4", "vite": "^8.1.3", diff --git a/yarn.lock b/yarn.lock index da9370a81..a2d8701e5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3288,7 +3288,7 @@ __metadata: react: "npm:^19.2.6" react-dom: "npm:^19.2.6" sass: "npm:^1.100.0" - stream-chat: "npm:10.0.0-rc.34" + stream-chat: "npm:^10.0.0" stream-chat-react: "workspace:^" typescript: "npm:^6.0.3" languageName: unknown @@ -3332,7 +3332,7 @@ __metadata: react: "npm:^19.2.6" react-dom: "npm:^19.2.6" react-leaflet: "npm:^5.0.0" - stream-chat: "npm:10.0.0-rc.34" + stream-chat: "npm:^10.0.0" stream-chat-react: "workspace:^" typescript: "npm:^6.0.3" vite: "npm:^8.1.3" @@ -3350,7 +3350,7 @@ __metadata: emoji-mart: "npm:^5.6.0" react: "npm:^19.2.6" react-dom: "npm:^19.2.6" - stream-chat: "npm:10.0.0-rc.34" + stream-chat: "npm:^10.0.0" stream-chat-react: "workspace:^" typescript: "npm:^6.0.3" vite: "npm:^8.1.3" @@ -3378,7 +3378,7 @@ __metadata: react: "npm:^19.2.6" react-dom: "npm:^19.2.6" sass: "npm:^1.100.0" - stream-chat: "npm:10.0.0-rc.34" + stream-chat: "npm:^10.0.0" stream-chat-react: "workspace:^" typescript: "npm:^6.0.3" vite: "npm:^8.1.3" @@ -12058,7 +12058,7 @@ __metadata: remark-parse: "npm:^11.0.0" sass: "npm:^1.100.0" semantic-release: "npm:^25.0.3" - stream-chat: "npm:10.0.0-rc.34" + stream-chat: "npm:^10.0.0" typescript: "npm:^6.0.3" typescript-eslint: "npm:^8.59.4" unified: "npm:^11.0.5" @@ -12081,7 +12081,7 @@ __metadata: modern-normalize: ^3.0.1 react: ^19.0.0 || ^18.0.0 || ^17.0.0 react-dom: ^19.0.0 || ^18.0.0 || ^17.0.0 - stream-chat: ^10.0.0-rc.34 + stream-chat: ^10.0.0 dependenciesMeta: "@parcel/watcher": built: true @@ -12111,9 +12111,9 @@ __metadata: languageName: unknown linkType: soft -"stream-chat@npm:10.0.0-rc.34": - version: 10.0.0-rc.34 - resolution: "stream-chat@npm:10.0.0-rc.34" +"stream-chat@npm:^10.0.0": + version: 10.0.0 + resolution: "stream-chat@npm:10.0.0" dependencies: "@stream-io/logger": "npm:^2.1.0" "@stream-io/state-store": "npm:^1.2.0" @@ -12124,7 +12124,7 @@ __metadata: built: true husky: built: true - checksum: 10c0/ab420864180b851b849e9abf69577d136cb341af302694cf7436dc81eee54cbbf51181cffff4a353f3417bd312a1d5c244f514c489f600e5fd3e01ef001957f9 + checksum: 10c0/d44d6ddc3c417844f0d43b10ccf30dd483291fb7e7843173f00129759aa20020f05167e6037f6e8fbefc25f65c19a0c967058fa559bb4b23a4d8b255180a5b4c languageName: node linkType: hard