Skip to content

Commit d3d3c59

Browse files
authored
fix(release): fix some gaps between beachball and changesets (#4037)
* ci(release): bump dependency-profiles manually after changesets does * fix yarn change and yarn change:check * docs(changeset): Bump * lock * fix typo
1 parent 6137435 commit d3d3c59

File tree

10 files changed

+650
-217
lines changed

10 files changed

+650
-217
lines changed

.changeset/config.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
{
22
"$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json",
33
"changelog": "@changesets/cli/changelog",
4-
"commit": ["@changesets/cli/commit", { "skipCI": false }],
4+
"commit": [
5+
"@changesets/cli/commit",
6+
{
7+
"skipCI": false
8+
}
9+
],
510
"linked": [],
611
"access": "public",
712
"baseBranch": "origin/main",

.changeset/fancy-rats-speak.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@fluentui-react-native/dependency-profiles": patch
3+
---
4+
5+
Bump dependency-profiles

.github/scripts/change.mts

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
#!/usr/bin/env node
2+
// @ts-ignore
3+
import { parseArgs, styleText } from 'node:util';
4+
5+
import { $, echo, fs } from 'zx';
6+
7+
/**
8+
* Wrapper around `changeset add` (default) and `changeset status` validation (--check).
9+
*
10+
* Without --check: runs `changeset add` interactively with the correct upstream remote
11+
* auto-detected from package.json's repository URL, temporarily patched into config.json.
12+
*
13+
* With --check (CI mode): validates that all changed packages have changesets and that
14+
* no major version bumps are introduced.
15+
*/
16+
17+
interface ChangesetStatusOutput {
18+
releases: Array<{
19+
name: string;
20+
type: 'major' | 'minor' | 'patch' | 'none';
21+
oldVersion: string;
22+
newVersion: string;
23+
changesets: string[];
24+
}>;
25+
changesets: string[];
26+
}
27+
28+
const log = {
29+
error: (msg: string) => echo(styleText('red', msg)),
30+
success: (msg: string) => echo(styleText('green', msg)),
31+
warn: (msg: string) => echo(styleText('yellow', msg)),
32+
info: (msg: string) => echo(msg),
33+
};
34+
35+
/** Find the remote that matches the repo's own URL (works for forks and CI alike). */
36+
async function getBaseBranch(): Promise<string> {
37+
const pkg = JSON.parse(fs.readFileSync('./package.json', 'utf-8'));
38+
const repoUrl: string = pkg.repository?.url ?? '';
39+
// Extract "org/repo" from https://github.com/org/repo.git or git@github.com:org/repo.git
40+
const repoPath = repoUrl.match(/github\.com[:/](.+?)(?:\.git)?$/)?.[1] ?? '';
41+
42+
const remotes = (await $`git remote -v`.quiet()).stdout;
43+
const remote = (repoPath && remotes.match(new RegExp(`^(\\S+)\\s+.*${repoPath}`, 'm'))?.[1]) ?? 'origin';
44+
return `${remote}/main`;
45+
}
46+
47+
/** Run `changeset add` interactively, temporarily patching config.json with the correct baseBranch. */
48+
async function runAdd(baseBranch: string): Promise<void> {
49+
const configPath = '.changeset/config.json';
50+
const config = fs.readJsonSync(configPath);
51+
const originalBaseBranch: string = config.baseBranch;
52+
config.baseBranch = baseBranch;
53+
fs.writeJsonSync(configPath, config, { spaces: 2 });
54+
55+
try {
56+
await $({ stdio: 'inherit' })`yarn changeset`;
57+
} finally {
58+
config.baseBranch = originalBaseBranch;
59+
fs.writeJsonSync(configPath, config, { spaces: 2 });
60+
}
61+
}
62+
63+
function checkMajorBumps(releases: ChangesetStatusOutput['releases']): void {
64+
const majorBumps = releases.filter((r) => r.type === 'major');
65+
if (majorBumps.length === 0) return;
66+
67+
log.error('❌ Major version bumps detected!\n');
68+
for (const release of majorBumps) {
69+
log.error(` ${release.name}: major`);
70+
if (release.changesets.length > 0) {
71+
log.error(` (from changesets: ${release.changesets.join(', ')})`);
72+
}
73+
}
74+
log.error('\nMajor version bumps are not allowed.');
75+
log.warn('If you need to make a breaking change, please discuss with the team first.\n');
76+
process.exit(1);
77+
}
78+
79+
/** Validate that all changed packages have changesets and no major bumps are introduced. */
80+
async function runCheck(baseBranch: string): Promise<void> {
81+
const STATUS_FILE = 'changeset-status.json';
82+
83+
log.info(`\n${'='.repeat(60)}`);
84+
log.info('Changesets Validation');
85+
log.info(`${'='.repeat(60)}\n`);
86+
log.info(`Comparing against ${baseBranch}\n`);
87+
88+
// Pre-write empty state so changeset status always has a file to overwrite
89+
fs.writeJsonSync(STATUS_FILE, { releases: [], changesets: [] });
90+
91+
const statusResult = await $`yarn changeset status --since=${baseBranch} --output ${STATUS_FILE}`.nothrow();
92+
93+
const data: ChangesetStatusOutput = fs.readJsonSync(STATUS_FILE);
94+
fs.removeSync(STATUS_FILE);
95+
96+
// Fail: packages changed but no changeset written
97+
if (statusResult.exitCode !== 0) {
98+
log.error('❌ Some packages have been changed but no changesets were found.');
99+
log.warn('Run `yarn change` to create a changeset, or `yarn changeset --empty` if no release is needed.\n');
100+
process.exit(1);
101+
}
102+
103+
checkMajorBumps(data.releases);
104+
105+
// Pass
106+
if (data.releases.length === 0) {
107+
log.info('ℹ️ No public packages changed — no changeset required');
108+
} else {
109+
log.success(`✅ Changesets found (${data.releases.map((r) => r.name).join(', ')})`);
110+
}
111+
log.success('\nAll validations passed! ✅\n');
112+
}
113+
114+
const { values: args } = parseArgs({ options: { check: { type: 'boolean', default: false } } });
115+
116+
const baseBranch = await getBaseBranch();
117+
118+
if (args.check) {
119+
await runCheck(baseBranch);
120+
} else {
121+
await runAdd(baseBranch);
122+
}

.github/scripts/changeset-version-with-postbump.mts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ import { $, cd, echo, fs } from 'zx';
1414

1515
const DEPENDENCY_PROFILES_DIR = 'packages/dependency-profiles';
1616

17+
function bumpPatch(version: string): string {
18+
const [major, minor, patch] = version.split('.').map(Number);
19+
return `${major}.${minor}.${patch + 1}`;
20+
}
21+
1722
echo('📦 Running changeset version...');
1823
await $`yarn changeset version`;
1924

@@ -22,12 +27,26 @@ await $`yarn changeset version`;
2227
echo('🔙 Undoing changeset commit (keeping changes)...');
2328
await $`git reset --soft HEAD~1`;
2429

30+
// Changesets doesn't bump or update the dependency-profiles package, so we need to do that manually
2531
echo('\n🔄 Updating dependency-profiles...');
2632
if (fs.existsSync(DEPENDENCY_PROFILES_DIR)) {
33+
const profileIndexPath = `${DEPENDENCY_PROFILES_DIR}/src/index.js`;
34+
const profileBefore = fs.readFileSync(profileIndexPath, 'utf-8');
35+
2736
cd(DEPENDENCY_PROFILES_DIR);
2837
await $`yarn update-profile`;
2938
cd('../..');
30-
echo('✅ dependency-profiles updated');
39+
40+
const profileAfter = fs.readFileSync(profileIndexPath, 'utf-8');
41+
if (profileAfter !== profileBefore) {
42+
const pkgPath = `${DEPENDENCY_PROFILES_DIR}/package.json`;
43+
const pkg = fs.readJsonSync(pkgPath);
44+
pkg.version = bumpPatch(pkg.version);
45+
fs.writeJsonSync(pkgPath, pkg, { spaces: 2 });
46+
echo(`✅ dependency-profiles updated and bumped to ${pkg.version}`);
47+
} else {
48+
echo('✅ dependency-profiles updated (no version change needed)');
49+
}
3150
} else {
3251
echo('⚠️ dependency-profiles not found, skipping');
3352
}

.github/scripts/validate-changesets.mts

Lines changed: 0 additions & 66 deletions
This file was deleted.

.github/workflows/pr.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ jobs:
299299
run: yarn install --immutable
300300

301301
- name: Validate changesets
302-
run: yarn changeset:validate
302+
run: yarn change:check
303303

304304
publish-dry-run:
305305
name: NPM Publish Dry Run

.oxfmtrc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"singleQuote": true,
55
"ignorePatterns": [
66
".yarnrc.yml",
7-
".changesets/*.md",
7+
".changeset/*.md",
88
"**/__fixtures__/**",
99
"**/__testfixtures__/**",
1010
"**/lib-commonjs/**",

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@
2020
"docs": "yarn workspace fluent-rn-website start",
2121
"bundle": "lage bundle",
2222
"clean": "lage clean",
23-
"change": "changeset",
23+
"change": "node .github/scripts/change.mts",
2424
"changeset:version": "node .github/scripts/changeset-version-with-postbump.mts",
25-
"changeset:validate": "node .github/scripts/validate-changesets.mts",
25+
"change:check": "node .github/scripts/change.mts --check",
2626
"check-publishing": "node ./scripts/src/cli.mjs check-publishing",
2727
"lint": "lage lint",
2828
"lint-fix": "cross-env FURN_FIX_MODE=true lage lint",

0 commit comments

Comments
 (0)