Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .ado/azure-pipelines.publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ extends:
- script: |
# https://github.com/changesets/changesets/issues/432
# We can't use `changeset publish` because it doesn't support workspaces, so we have to publish each package individually
yarn workspaces foreach -vv --all --topological --no-private npm publish --tolerate-republish
yarn lage publish --verbose --grouped --reporter azureDevops
displayName: 'Publish NPM Packages'
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'), not(${{ parameters.skipNpmPublish }}))

Expand Down
10 changes: 1 addition & 9 deletions .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,5 @@
"linked": [],
"access": "public",
"baseBranch": "origin/main",
"ignore": [
"@fluentui-react-native/dependency-profiles",
"@fluentui-react-native/e2e-testing",
"@fluentui-react-native/tester",
"@fluentui-react-native/tester-core",
"@fluentui-react-native/tester-win32",
"@fluentui-react-native/tester-win32-81",
"@fluentui-react-native/test-*"
]
"ignore": []
}
122 changes: 36 additions & 86 deletions .github/scripts/validate-changesets.mts
Original file line number Diff line number Diff line change
@@ -1,26 +1,22 @@
#!/usr/bin/env zx
import 'zx/globals';
#!/usr/bin/env node
// @ts-ignore
import { styleText } from 'node:util';
import { $, echo, fs } from 'zx';

/**
* Validate changesets in CI
*
* Checks:
* 1. Changesets are present (PRs require changesets)
* 2. No major version bumps (breaking changes disallowed)
* Checks for major version bumps (breaking changes disallowed).
* Private/ignored packages (per .changeset/config.json) are excluded automatically.
*/

// ANSI color codes
const colors = {
red: (msg: string) => `\x1b[31m${msg}\x1b[0m`,
green: (msg: string) => `\x1b[32m${msg}\x1b[0m`,
yellow: (msg: string) => `\x1b[33m${msg}\x1b[0m`,
};
const tmpDir = fs.mkdtempSync('/tmp/changeset-status-');
const STATUS_FILE = `${tmpDir}/status.json`;

// Logging helpers
const log = {
error: (msg: string) => echo(colors.red(msg)),
success: (msg: string) => echo(colors.green(msg)),
warn: (msg: string) => echo(colors.yellow(msg)),
error: (msg: string) => echo(styleText('red', msg)),
success: (msg: string) => echo(styleText('green', msg)),
warn: (msg: string) => echo(styleText('yellow', msg)),
info: (msg: string) => echo(msg),
};

Expand All @@ -35,83 +31,37 @@ interface ChangesetStatusOutput {
changesets: string[];
}

async function checkChangesetPresence() {
log.info('\n🔍 Checking for changeset presence...\n');

const result = await $`yarn changeset status --since=origin/main 2>&1`.nothrow();

if (result.exitCode !== 0) {
log.error('❌ Changeset validation failed\n');
echo(result.stdout);
return false;
}

log.success('✅ Changesets found');
return true;
}

async function checkForMajorBumps() {
log.info('\n🔍 Checking for major version bumps...\n');

const result = await $`yarn changeset status --output bumps.json`.nothrow();

// If no changesets, skip major bump check
if (result.exitCode !== 0 && result.stdout.includes('no changesets were found')) {
log.warn('No changesets found (skipping major check)');
return true;
}

// Other errors
if (result.exitCode !== 0 || !fs.existsSync('bumps.json')) {
log.error('❌ Failed to check for major bumps\n');
if (result.stderr) log.info(result.stderr);
return false;
}

const bumpsData: ChangesetStatusOutput = JSON.parse(fs.readFileSync('bumps.json', 'utf-8'));
fs.unlinkSync('bumps.json');

const majorBumps = bumpsData.releases.filter((release) => release.type === 'major');

if (majorBumps.length > 0) {
log.error('❌ Major version bumps detected!\n');
for (const release of majorBumps) {
log.error(` ${release.name}: major`);
if (release.changesets.length > 0) {
log.error(` (from changesets: ${release.changesets.join(', ')})`);
}
}
log.error('\nMajor version bumps are not allowed.');
log.warn('If you need to make a breaking change, please discuss with the team first.\n');
return false;
}

log.success('✅ No major version bumps found');
return true;
}

// Main execution
log.info(`\n${'='.repeat(60)}`);
log.info('Changesets Validation');
log.info(`${'='.repeat(60)}`);

const results = {
presence: await checkChangesetPresence(),
majorBumps: await checkForMajorBumps(),
};

log.info(`\n${'='.repeat(60)}`);
log.info('Validation Results:');
log.info(`${'='.repeat(60)}\n`);

log.info(`Changeset presence: ${results.presence ? '✅ PASS' : '❌ FAIL'}`);
log.info(`Major version check: ${results.majorBumps ? '✅ PASS' : '❌ FAIL'}\n`);
// Pre-write empty state so changeset status always has a file to overwrite
fs.writeJsonSync(STATUS_FILE, { releases: [], changesets: [] });

await $`yarn changeset status --since=origin/main --output ${STATUS_FILE}`.nothrow();

const allPassed = results.presence && results.majorBumps;
const data: ChangesetStatusOutput = fs.readJsonSync(STATUS_FILE);
fs.removeSync(tmpDir);

if (!allPassed) {
log.error('Validation failed!\n');
// Fail: major version bumps
const majorBumps = data.releases.filter((release) => release.type === 'major');
if (majorBumps.length > 0) {
log.error('❌ Major version bumps detected!\n');
for (const release of majorBumps) {
log.error(` ${release.name}: major`);
if (release.changesets.length > 0) {
log.error(` (from changesets: ${release.changesets.join(', ')})`);
}
}
log.error('\nMajor version bumps are not allowed.');
log.warn('If you need to make a breaking change, please discuss with the team first.\n');
throw new Error('Validation failed');
}

log.success('All validations passed! ✅\n');
// Pass
if (data.releases.length === 0) {
log.info('ℹ️ No public packages changed — no changeset required');
} else {
log.success(`✅ Changesets found (${data.releases.map((r) => r.name).join(', ')})`);
}
log.success('\nAll validations passed! ✅\n');
3 changes: 1 addition & 2 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -325,8 +325,7 @@ jobs:
run: yarn build

- name: Simulate publish
run: |
yarn workspaces foreach -vv --all --topological --no-private npm publish --tolerate-republish --dry-run
run: yarn lage publish-dry-run --verbose --grouped

test-links:
name: Test repo links
Expand Down
382 changes: 191 additions & 191 deletions .yarn/releases/yarn-4.11.0.cjs → .yarn/releases/yarn-4.12.0.cjs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion .yarnrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -302,4 +302,4 @@ plugins:
path: .yarn/plugins/@rnx-kit/yarn-plugin-dynamic-extensions.cjs
spec: "https://raw.githubusercontent.com/microsoft/rnx-kit/main/incubator/yarn-plugin-dynamic-extensions/index.js"

yarnPath: .yarn/releases/yarn-4.11.0.cjs
yarnPath: .yarn/releases/yarn-4.12.0.cjs
17 changes: 17 additions & 0 deletions lage.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,23 @@ const config = {
inputs: [],
outputs: [],
},
publish: {
dependsOn: ['^publish'],
type: 'worker',
options: {
worker: 'scripts/src/worker/publish.js',
},
cache: false,
},
'publish-dry-run': {
dependsOn: ['^publish-dry-run'],
type: 'worker',
options: {
worker: 'scripts/src/worker/publish.js',
dryRun: true,
},
cache: false,
},
},
};

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"cross-env": "catalog:",
"eslint": "^9.39.2",
"eslint-plugin-import": "^2.32.0",
"lage": "^2.0.0",
"lage": "^2.14.19",
"markdown-link-check": "^3.8.7",
"oxfmt": "^0.35.0",
"typescript": "^5.8.0",
Expand All @@ -62,7 +62,7 @@
"engines": {
"node": ">=22.12"
},
"packageManager": "yarn@4.11.0",
"packageManager": "yarn@4.12.0",
"rnx-kit": {
"kitType": "library"
}
Expand Down
3 changes: 2 additions & 1 deletion scripts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
"react": "18.2.0",
"react-native": "^0.74.0",
"typescript": "^5.8.0",
"workspace-tools": "^0.26.3"
"workspace-tools": "^0.26.3",
"zx": "^8.2.4"
},
"bundlesize": [
{
Expand Down
20 changes: 20 additions & 0 deletions scripts/src/worker/publish.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// @ts-check

import { $, fs } from 'zx';
import { join } from 'node:path';

/**
* @param {{ target: { cwd: string; label: string }, options: { dryRun?: boolean } }} data
*/
export async function run({ target, options }) {
const pkg = await fs.readJson(join(target.cwd, 'package.json'));

if (pkg.private) {
return;
}

const dryRun = options?.dryRun ?? false;
const args = ['--tolerate-republish', ...(dryRun ? ['--dry-run'] : [])];

await $({ cwd: target.cwd, verbose: true })`yarn npm publish ${args}`;
}
11 changes: 6 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5037,7 +5037,7 @@ __metadata:
cross-env: "catalog:"
eslint: "npm:^9.39.2"
eslint-plugin-import: "npm:^2.32.0"
lage: "npm:^2.0.0"
lage: "npm:^2.14.19"
markdown-link-check: "npm:^3.8.7"
oxfmt: "npm:^0.35.0"
typescript: "npm:^5.8.0"
Expand Down Expand Up @@ -5074,6 +5074,7 @@ __metadata:
react-native: "npm:^0.74.0"
typescript: "npm:^5.8.0"
workspace-tools: "npm:^0.26.3"
zx: "npm:^8.2.4"
bin:
fluentui-scripts: ./src/cli.mjs
languageName: unknown
Expand Down Expand Up @@ -18338,9 +18339,9 @@ __metadata:
languageName: node
linkType: hard

"lage@npm:^2.0.0":
version: 2.14.18
resolution: "lage@npm:2.14.18"
"lage@npm:^2.14.19":
version: 2.14.19
resolution: "lage@npm:2.14.19"
dependencies:
fsevents: "npm:~2.3.2"
glob-hasher: "npm:^1.4.2"
Expand All @@ -18350,7 +18351,7 @@ __metadata:
bin:
lage: dist/lage.js
lage-server: dist/lage-server.js
checksum: 10c0/c7977e86883bc0c45bacb8c776f025bcc5940b6ccc0651de91d54970214015647a624faeba46e1dd4372980b559d201b916b8a04a4701b04c520d7f8905d56f9
checksum: 10c0/95d5361baf712febd13155fdabde8de8629dccf62ceffad6e120693b7de3b43ccddbddaec1ebb11b272d9be6a725318cfec20176250d622cf7d281123998f61c
languageName: node
linkType: hard

Expand Down
Loading