Skip to content

Commit 273d63a

Browse files
committed
chore(release): migrate from Lerna to Changesets
Replace Lerna with Changesets for versioning and publishing: - Add .changeset/ config + README pointing at UI5/typescript; ignore the private test-packages so changeset publish skips them automatically - Add scripts/auto-changeset.mjs to derive changesets from conventional commits (scope -> packages, type -> bump, subject -> summary) - Rewrite .github/workflows/release.yml to use changesets/action@v1.8.0: opens/updates a 'Version Packages' PR on main, then publishes on merge with npm OIDC trusted publishing + provenance, falling back to NPM_BOOTSTRAP_TOKEN when OIDC isn't configured - Add .github/workflows/changeset.yml as a PR gate that fails when no changeset is present (counts .changesets so empty changesets pass) - Replace root release:* lerna scripts with changeset / version-packages / release-publish; build is now explicit per workspace because the test-packages have no build script - Remove lerna and lerna.json; add @changesets/cli + @changesets/changelog-github devDependencies - Rewrite CONTRIBUTING.md to document the new flow end-to-end while preserving the existing Legal / DCO / AI-generated-code sections
1 parent 0a1c57f commit 273d63a

10 files changed

Lines changed: 1208 additions & 2254 deletions

File tree

.changeset/README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Changesets
2+
3+
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
4+
with multi-package repos, or single-package repos to help you version and publish your code. You can
5+
find the full documentation for it [in our repository](https://github.com/changesets/changesets).
6+
7+
We have a quick list of common questions to get you started engaging with this project in
8+
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md).
9+
10+
## How this repo uses Changesets
11+
12+
This monorepo replaced Lerna with [Changesets](https://github.com/changesets/changesets) for
13+
versioning and releases. The flow is:
14+
15+
1. **In your PR**, run `yarn changeset` and answer the prompts (which packages, semver level,
16+
summary). Commit the generated `.changeset/<random-name>.md` file alongside your code change.
17+
2. When your PR is merged to `main`, the **Release** workflow opens (or updates) a single
18+
`Version Packages` PR that aggregates all pending changesets — bumping versions and updating
19+
each package's `CHANGELOG.md`.
20+
3. **Merging the `Version Packages` PR** triggers the same workflow to publish the new versions
21+
to npm.
22+
23+
Private packages (`test-packages/*`, `demos/*`) are skipped automatically by `changeset publish`.
24+
Only the public packages under `packages/*` are released.
25+
26+
If a change does not warrant a release (docs-only, internal tooling, test refactors, etc.) just
27+
don't add a changeset — the PR will surface a "no changeset detected" hint, which is fine to
28+
acknowledge and merge.

.changeset/config.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
3+
"changelog": ["@changesets/changelog-github", { "repo": "UI5/typescript" }],
4+
"commit": false,
5+
"fixed": [],
6+
"linked": [],
7+
"access": "public",
8+
"baseBranch": "main",
9+
"updateInternalDependencies": "patch",
10+
"ignore": ["@ui5/openui5-snapshot-test", "@ui5/typed-json-model"]
11+
}

.changeset/fresh-cobras-send.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
---

.github/workflows/changeset.yml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: Changeset
2+
3+
# Verifies that every PR carries a changeset (or an explicit empty one).
4+
# Runs only on pull_request — `push` to main carries already-merged
5+
# changesets that the Release workflow then consumes.
6+
7+
on:
8+
pull_request:
9+
branches: [main]
10+
workflow_dispatch:
11+
inputs:
12+
pr_number:
13+
description: "PR number to test (for fork PRs)"
14+
required: true
15+
type: string
16+
17+
permissions:
18+
contents: read
19+
20+
jobs:
21+
changeset:
22+
name: Changeset present
23+
runs-on: ubuntu-latest
24+
# Skip on the auto-generated "Version Packages" PR (it consumes all changesets).
25+
if: github.head_ref != 'changeset-release/main'
26+
steps:
27+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
28+
with:
29+
ref: ${{ inputs.pr_number && format('refs/pull/{0}/head', inputs.pr_number) || '' }}
30+
# Full history so `changeset status --since=origin/main` can diff.
31+
fetch-depth: 0
32+
33+
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
34+
with:
35+
node-version: 24.x
36+
37+
- name: Install dependencies
38+
run: yarn --frozen-lockfile
39+
40+
# Fails the PR if no changeset describes the change.
41+
# Add one with `yarn changeset` (or `yarn changeset:empty` for PRs
42+
# that don't need a release entry) and commit it.
43+
# We check `.changesets` (not `.releases`) so that empty changesets
44+
# — which have 0 package bumps but still document the PR — pass.
45+
- name: Verify changeset is present
46+
run: |
47+
yarn changeset status --since=origin/main --output=/tmp/cs.json
48+
if [ "$(jq '.changesets | length' /tmp/cs.json)" -eq 0 ]; then
49+
echo "::error::No changeset found on this PR. Run 'yarn changeset' (or 'yarn changeset:empty' for PRs that don't need a release entry) and commit the file."
50+
exit 1
51+
fi

.github/workflows/release.yml

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,69 @@
11
name: Release
2+
23
on:
34
push:
45
branches: [main]
5-
workflow_dispatch:
6+
workflow_dispatch: # Manual trigger
7+
8+
env:
9+
HUSKY_SKIP: true
10+
11+
# Skip when the head commit is the workflow's own version-bump commit, to avoid loops.
12+
concurrency:
13+
group: release-${{ github.ref }}
14+
cancel-in-progress: false
615

716
permissions:
8-
contents: read
9-
id-token: write
17+
contents: write # create the "Version Packages" PR and tags
18+
pull-requests: write # open/update the version PR
19+
id-token: write # REQUIRED for npm OIDC trusted publishing
1020

1121
jobs:
1222
release:
1323
runs-on: ubuntu-latest
14-
# Only gate push events by commit message; allow workflow_dispatch always
15-
if: >
16-
github.event_name == 'workflow_dispatch' ||
17-
(github.event_name == 'push' && contains(github.event.head_commit.message, 'chore(release): publish'))
24+
if: "!contains(github.event.head_commit.message, 'skip ci')"
1825
steps:
19-
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
26+
- name: Checkout
27+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
2028
with:
2129
fetch-depth: 0
2230

23-
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
31+
- name: Setup node
32+
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
2433
with:
2534
node-version: 24.15.0
35+
registry-url: https://registry.npmjs.org
2636

2737
- name: Install dependencies
2838
run: yarn --frozen-lockfile
2939

3040
- name: Build
3141
run: yarn build
3242

33-
# Choose publish command based on the event type
34-
- name: Publish to NPM (push)
35-
if: github.event_name == 'push'
36-
run: npm run release:publish
43+
- name: Detect token usage (optional safety)
44+
run: |
45+
if npm whoami 2>/dev/null; then
46+
echo "::warning::Token-based auth active (expected only when OIDC isn't configured)"
47+
else
48+
echo "OIDC auth active"
49+
fi
3750
38-
- name: Publish to NPM (manual)
39-
if: github.event_name == 'workflow_dispatch'
40-
run: npm run release:publish-manual
51+
- name: Configure NPM bootstrap token (non OIDC flow)
52+
env:
53+
NPM_BOOTSTRAP_TOKEN: ${{ secrets.NPM_BOOTSTRAP_TOKEN }}
54+
if: ${{ env.NPM_BOOTSTRAP_TOKEN != '' }}
55+
run: |
56+
echo "//registry.npmjs.org/:_authToken=${NPM_BOOTSTRAP_TOKEN}" >> ~/.npmrc
57+
58+
- name: Create Release Pull Request or Publish
59+
id: changesets
60+
uses: changesets/action@63a615b9cd06ba9a3e6d13796c7fbcb080a60a0b # v1.8.0
61+
with:
62+
version: yarn run version-packages
63+
publish: yarn run release-publish
64+
commit: "chore(release): publish"
65+
title: "chore(release): publish"
66+
env:
67+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
68+
NODE_AUTH_TOKEN: ${{ secrets.NPM_BOOTSTRAP_TOKEN }}
69+
NPM_CONFIG_PROVENANCE: "true"

CONTRIBUTING.md

Lines changed: 138 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# Contribution Guide
22

3-
This is the common top-level contribution guide for this monorepo.
4-
A sub-package **may** have an additional CONTRIBUTING.md file if needed.
3+
This is the common top-level contribution guide for the [UI5/typescript](https://github.com/UI5/typescript) monorepo. A sub-package **may** have an additional CONTRIBUTING.md file if needed.
4+
5+
Thanks for your interest in contributing! All forms of contribution are welcome — bug reports, fixes, documentation, new features, and reviewing other contributors' PRs.
56

67
## Legal
78

@@ -17,12 +18,21 @@ As artificial intelligence evolves, AI-generated code is becoming valuable for m
1718

1819
Please see our [guideline for AI-generated code contributions to SAP Open Source Software Projects](https://github.com/UI5/.github/blob/main/CONTRIBUTING_USING_GENAI.md) for these requirements.
1920

21+
## Reporting Issues
22+
23+
Open a [GitHub issue](https://github.com/UI5/typescript/issues) on the topic that fits your case best:
24+
25+
- For `@ui5/dts-generator` — issues with the **generation logic** itself. Issues in the generated UI5 type definitions usually originate from JSDoc comments in [OpenUI5](https://github.com/UI5/openui5/issues) / SAPUI5 — please open the ticket there in that case.
26+
- For `@ui5/ts-interface-generator` — anything related to control-interface generation for TypeScript controls.
27+
28+
A reproducible example (a minimal repo or a [TypeScript Hello World](https://github.com/SAP-samples/ui5-typescript-helloworld) fork) is the single biggest thing that helps get an issue triaged quickly.
29+
2030
## Development Environment
2131

22-
### pre-requisites
32+
### Pre-requisites
2333

24-
- [Yarn](https://yarnpkg.com/lang/en/docs/install/) >= 1.4.2
25-
- A current [Long-Term Support version](https://nodejs.org/en/about/releases/) of node.js
34+
- A current [Long-Term Support version](https://nodejs.org/en/about/releases/) of Node.js (>= 22; CI tests on 22.x and 24.x).
35+
- [Yarn 1.x](https://classic.yarnpkg.com/lang/en/docs/install/) — this repo uses yarn classic with workspaces.
2636
- (optional) [commitizen](https://github.com/commitizen/cz-cli#installing-the-command-line-tool) for managing commit messages.
2737

2838
### Initial Setup
@@ -32,6 +42,22 @@ The initial setup is trivial:
3242
- clone this repo
3343
- `yarn`
3444

45+
The repo's `.yarnrc` enforces `--frozen-lockfile`, exact-version saves (`save-prefix ""`), and a pinned registry — that's intentional supply-chain hardening, please don't loosen it without discussion.
46+
47+
### Repository Layout
48+
49+
```text
50+
packages/ # public, published to npm
51+
dts-generator/ # @ui5/dts-generator
52+
ts-interface-generator/ # @ui5/ts-interface-generator
53+
test-packages/ # private, never published
54+
openui5-snapshot-test/
55+
typed-json-model/
56+
demos/ # private, never published
57+
```
58+
59+
Only the two `packages/*` are released to npm. Everything under `test-packages/*` and `demos/*` is `"private": true` and is automatically ignored by Changesets.
60+
3561
### Commit Messages format
3662

3763
This project enforces the [conventional-commits][conventional_commits] commit message formats.
@@ -48,16 +74,46 @@ It is recommended to use `git cz` to construct valid conventional commit message
4874
[commit_types]: https://github.com/commitizen/conventional-commit-types/blob/master/index.json
4975
[conventional_commits]: https://www.conventionalcommits.org/en/v1.0.0/
5076

77+
Use the package directory name as the **scope** when the change is package-specific:
78+
79+
```text
80+
feat(dts-generator): support union types in api.json
81+
fix(ts-interface-generator): handle aggregations with cardinality 0..1
82+
chore: bump root devDependencies
83+
```
84+
85+
The scope is also what `yarn changeset:auto` uses to figure out which packages to bump (see [Releases](#release-process) below). Breaking changes are signalled with a `!` after the type/scope **or** a `BREAKING CHANGE:` footer in the body — either flips the bump to `major`.
86+
5187
### Formatting
5288

5389
[Prettier](https://prettier.io/) is used to ensure consistent code formatting in this repository.
5490
This is normally transparent as it automatically activated in a pre-commit hook using [lint-staged](https://github.com/okonet/lint-staged).
5591
However, this does mean that dev flows that do not use a full dev env (e.g editing directly on github) may result in voter failures due to formatting errors.
5692

93+
To run it manually:
94+
95+
```sh
96+
yarn format:fix # rewrite files
97+
yarn format:validate # check, no rewrite (this is what CI runs)
98+
```
99+
57100
### Compiling
58101

59102
See the respective sub-packages for instructions (if needed at all).
60103

104+
To build both publishable packages from the root:
105+
106+
```sh
107+
yarn build
108+
```
109+
110+
Per-package work uses yarn's workspace shorthand:
111+
112+
```sh
113+
yarn workspace @ui5/dts-generator build
114+
yarn workspace @ui5/ts-interface-generator test
115+
```
116+
61117
### Testing
62118

63119
[Mocha][mocha] and [Chai][chai] are used for unit-testing.
@@ -68,22 +124,89 @@ See the respective sub-packages for instructions (if needed at all).
68124
- To run the tests, execute `yarn test` in a specific sub-package.
69125
- Note that not all sub-packages contain tests.
70126

127+
When adding a feature or fixing a bug, **please add or extend a test**. PRs without tests will get a friendly nudge.
128+
71129
### Full Build
72130

73131
To run the full **C**ontinuous **I**ntegration build run `yarn ci` in either the top-level package or a specific subpackage.
74132

75-
### Release Life-Cycle
133+
## Pull Requests
134+
135+
1. Fork the repo (or branch from `main` if you have write access).
136+
2. Create a topic branch with a descriptive name (`feat/union-types`, `fix/aggregation-cardinality`).
137+
3. Make your change, with tests, in commits that each follow the conventional-commits format.
138+
4. Add a changeset (see [Release Process](#release-process) below) — required for any change that should produce a new release.
139+
5. Push and open a PR against `main`.
140+
6. The CI workflows ([`Continuous Integration`](.github/workflows/ci.yml), [`Lint Commit Messages`](.github/workflows/commitlint.yml), [`CodeQL`](.github/workflows/codeql-analysis.yml)) must all pass.
141+
142+
Reviews aim for two pairs of eyes on substantive changes; small fixes and chore commits may be merged with a single approval.
143+
144+
## Release Life-Cycle
145+
146+
This monorepo uses [Changesets](https://github.com/changesets/changesets) for versioning and publishing. Each public package under `packages/*` keeps its own version (independent versioning) and its own `CHANGELOG.md`. Private packages under `test-packages/*` and `demos/*` are never released.
147+
148+
## Release Process
149+
150+
The release flow is fully automated through [GitHub Actions](.github/workflows/release.yml) — there's no local `lerna`, and no contributor needs npm-publish or push-to-`main` rights.
151+
152+
### For contributors — adding a changeset
153+
154+
When your PR changes one or more public packages, add a changeset alongside your code change. Pick whichever of the three commands fits best:
155+
156+
| Command | When to use |
157+
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
158+
| `yarn changeset:auto` | **Recommended for most PRs.** Walks the conventional-commit history on your branch and writes one `.changeset/auto-<sha>.md` per qualifying commit (packages from the commit `scope`, bump from the `type`, summary from the `subject`). Idempotent — safe to re-run. Already-covered commits are skipped, so any hand-written changeset always wins. |
159+
| `yarn changeset` | Interactive — pick packages, bump type, and write a summary by hand. Use when the auto-derived bump or summary is wrong (e.g. a `chore:` commit that secretly contains a `feat:`). The next `:auto` run will then skip the commit because it's covered. |
160+
| `yarn changeset:empty` | Docs- or tooling-only PRs that touch no public package. Writes an empty `.changeset/*.md` so the "no changeset detected" hint goes away without producing any CHANGELOG entry. |
161+
162+
Whichever you pick, **commit the resulting `.changeset/*.md` file alongside your code change**.
163+
164+
How `yarn changeset:auto` chooses the bump:
165+
166+
| Conventional-commit `type` (or marker) | Bump |
167+
| ---------------------------------------------------------- | ------- |
168+
| `feat:` | `minor` |
169+
| `fix:`, `perf:`, `refactor:`, `chore:`, `build:`, `style:` | `patch` |
170+
| `docs(<scope>):` (only when scoped to a package) | `patch` |
171+
| `<type>!:` or a `BREAKING CHANGE:` footer | `major` |
172+
| `ci:`, anything scoped `release` | skipped |
173+
174+
Commits whose only file changes are under `packages/<pkg>/test/` are also skipped — test-only changes don't ship in the published tarball.
175+
176+
If a change does not warrant a release at all (CI tweaks, internal tooling, etc.) just don't add a changeset — the PR can still be merged.
177+
178+
### For maintainers — cutting a release
179+
180+
The release itself happens entirely on GitHub. You don't need npm credentials or a clean local checkout.
181+
182+
1. When a PR with at least one changeset is merged into `main`, the [`Release`](.github/workflows/release.yml) workflow opens (or updates) a single **`Version Packages`** PR. That PR aggregates every pending changeset, bumps the affected `package.json` versions, regenerates each package's `CHANGELOG.md`, and refreshes `yarn.lock`.
183+
2. Review and merge that **`Version Packages`** PR when you're ready to cut a release.
184+
3. Merging it triggers the same workflow again, this time on the `publish` path: `changeset publish` runs, the new versions go to npm (with [npm provenance](https://docs.npmjs.com/generating-provenance-statements)), and matching git tags are pushed.
185+
4. Spot-check the newly published artifacts on [npmjs.com](https://www.npmjs.com/package/@ui5/dts-generator).
186+
187+
You can also trigger the workflow manually via **Actions → Release → Run workflow** — useful if a previous run failed mid-publish. Re-running publishes whatever versions are currently on `main` that haven't been released yet (`changeset publish` is idempotent — it skips versions already on the registry).
188+
189+
#### npm authentication
190+
191+
The workflow prefers npm OIDC trusted publishing (no token required). If OIDC isn't configured for a package, it falls back to `secrets.NPM_BOOTSTRAP_TOKEN`. The "Detect token usage" step in the workflow prints which path is active.
192+
193+
#### Pre-releases / snapshots
194+
195+
Not currently configured. If we need them, [`changeset pre enter <tag>`](https://github.com/changesets/changesets/blob/main/docs/prereleases.md) is the standard mechanism — open an issue first to discuss the tag scheme.
76196

77-
This monorepo uses Lerna's [Independent][lerna-mode] mode which allows subpackages to have different versions.
197+
## Upgrading the version of the dependencies
78198

79-
[lerna-mode]: https://github.com/lerna/lerna#independent-mode
199+
To upgrade the version of the dependencies, [`npm-check-updates`](https://github.com/raineorshine/npm-check-updates) is wired up at the root:
80200

81-
### Release Process
201+
```sh
202+
yarn ncu # list outdated packages across the workspace
203+
yarn ncu-u # apply the bumps to every package.json
204+
yarn install # refresh yarn.lock
205+
yarn ci # sanity-check before opening the PR
206+
```
82207

83-
Performing a release requires push permissions to the repository.
208+
## Where to ask questions
84209

85-
- Ensure you are on the default branch and synced with origin.
86-
- `yarn run release:version`
87-
- Follow the lerna CLI instructions.
88-
- Track the newly pushed commit with the message `chore(release): publish` in the build system for a successful completion (the `Release` GitHub action must be triggered!).
89-
- Inspect the newly published artifacts on npmjs.com.
210+
- For UI5 + TypeScript usage questions, the [ui5.github.io/typescript](https://ui5.github.io/typescript) docs are the best starting point.
211+
- For sample applications, see the [TypeScript Hello World app](https://github.com/SAP-samples/ui5-typescript-helloworld) and the [TypeScript branch of the UI5 CAP Event App](https://github.com/SAP-samples/ui5-cap-event-app/tree/typescript).
212+
- For tooling-specific bugs, please open an [issue](https://github.com/UI5/typescript/issues).

0 commit comments

Comments
 (0)