Skip to content

Commit c0f8466

Browse files
use zx
1 parent 03d53ce commit c0f8466

File tree

6 files changed

+121
-157
lines changed

6 files changed

+121
-157
lines changed
Lines changed: 26 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,41 @@
1-
#!/usr/bin/env node
1+
#!/usr/bin/env zx
2+
import 'zx/globals';
3+
24
/**
35
* Post-version hook for dependency-profiles package
46
*
57
* This script runs after changesets version bump to update dependency-profiles
68
* with the latest package versions and commit the changes.
7-
*
8-
* Usage: node scripts/update-dependency-profiles-postbump.mts
99
*/
1010

11-
import { execSync } from 'child_process';
12-
import { existsSync } from 'fs';
13-
import { resolve } from 'path';
14-
1511
const DEPENDENCY_PROFILES_DIR = 'packages/dependency-profiles';
1612

17-
function execCommand(command: string, cwd?: string): void {
18-
console.log(`> ${command}`);
19-
execSync(command, {
20-
stdio: 'inherit',
21-
cwd: cwd ? resolve(cwd) : undefined
22-
});
23-
}
24-
25-
function hasGitChanges(): boolean {
26-
try {
27-
const output = execSync('git status --porcelain', { encoding: 'utf8' });
28-
return output.trim().length > 0;
29-
} catch (error) {
30-
console.error('Failed to check git status:', error);
31-
return false;
32-
}
33-
}
34-
35-
function main(): void {
36-
console.log('🔍 Checking for dependency-profiles package...');
37-
38-
if (!existsSync(DEPENDENCY_PROFILES_DIR)) {
39-
console.log('⚠️ dependency-profiles directory not found, skipping');
40-
return;
41-
}
42-
43-
console.log('📦 Updating dependency-profiles');
13+
echo('🔍 Checking for dependency-profiles package...');
4414

45-
// Run update-profile script
46-
execCommand('yarn update-profile', DEPENDENCY_PROFILES_DIR);
15+
if (!fs.existsSync(DEPENDENCY_PROFILES_DIR)) {
16+
echo('⚠️ dependency-profiles directory not found, skipping');
17+
} else {
18+
echo('📦 Updating dependency-profiles');
19+
cd(DEPENDENCY_PROFILES_DIR);
20+
await $`yarn update-profile`;
4721

48-
// Update lockfile at root
49-
console.log('🔄 Updating yarn.lock');
50-
execCommand('yarn install --mode update-lockfile');
22+
echo('🔄 Updating yarn.lock');
23+
cd('../..');
24+
await $`yarn install --mode update-lockfile`;
5125

5226
// Check if there are changes to commit
53-
if (!hasGitChanges()) {
54-
console.log('✅ No changes to commit');
55-
return;
27+
const status = await $`git status --porcelain`;
28+
if (!status.stdout.trim()) {
29+
echo('✅ No changes to commit');
30+
} else {
31+
echo('💾 Committing dependency-profiles updates');
32+
33+
await $`git config user.name "github-actions[bot]"`;
34+
await $`git config user.email "github-actions[bot]@users.noreply.github.com"`;
35+
await $`git add .`;
36+
await $`git commit -m "chore: update dependency-profiles and lockfile"`;
37+
await $`git push`;
38+
39+
echo('✅ Committed dependency-profiles updates');
5640
}
57-
58-
console.log('💾 Committing dependency-profiles updates');
59-
60-
// Configure git
61-
execCommand('git config user.name "github-actions[bot]"');
62-
execCommand('git config user.email "github-actions[bot]@users.noreply.github.com"');
63-
64-
// Stage all changes
65-
execCommand('git add .');
66-
67-
// Commit
68-
execCommand('git commit -m "chore: update dependency-profiles and lockfile"');
69-
70-
// Push
71-
execCommand('git push');
72-
73-
console.log('✅ Committed dependency-profiles updates');
7441
}
75-
76-
main();

.github/scripts/validate-changesets.mts

100755100644
Lines changed: 79 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,97 @@
1-
#!/usr/bin/env node
1+
#!/usr/bin/env zx
2+
import 'zx/globals';
3+
24
/**
35
* Validate changesets in CI
46
*
57
* Checks:
68
* 1. Changesets are present (PRs require changesets)
79
* 2. No major version bumps (breaking changes disallowed)
810
* 3. Changeset status passes (validates format, config, dependencies)
9-
*
10-
* Usage: node .github/scripts/validate-changesets.mts
1111
*/
1212

13-
import { execSync } from 'child_process';
14-
import { readFileSync, readdirSync } from 'fs';
15-
import { join } from 'path';
16-
1713
const CHANGESETS_DIR = '.changeset';
18-
const RED = '\x1b[31m';
19-
const GREEN = '\x1b[32m';
20-
const YELLOW = '\x1b[33m';
21-
const RESET = '\x1b[0m';
14+
15+
// ANSI color codes
16+
const colors = {
17+
red: (msg: string) => `\x1b[31m${msg}\x1b[0m`,
18+
green: (msg: string) => `\x1b[32m${msg}\x1b[0m`,
19+
yellow: (msg: string) => `\x1b[33m${msg}\x1b[0m`,
20+
};
21+
22+
// Logging helpers
23+
const log = {
24+
error: (msg: string) => echo(colors.red(msg)),
25+
success: (msg: string) => echo(colors.green(msg)),
26+
warn: (msg: string) => echo(colors.yellow(msg)),
27+
info: (msg: string) => echo(msg),
28+
};
2229

2330
interface ChangesetFrontmatter {
2431
[packageName: string]: 'major' | 'minor' | 'patch';
2532
}
2633

2734
function parseChangesetForMajorCheck(filePath: string): ChangesetFrontmatter | null {
2835
try {
29-
const content = readFileSync(filePath, 'utf-8');
30-
31-
// Extract frontmatter between --- markers
36+
const content = fs.readFileSync(filePath, 'utf-8');
3237
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
33-
if (!frontmatterMatch) {
34-
return null;
35-
}
38+
if (!frontmatterMatch) return null;
3639

3740
const frontmatter = frontmatterMatch[1];
38-
const result: ChangesetFrontmatter = {};
41+
const result = {};
3942

40-
// Parse YAML-like frontmatter
41-
// Format: "@scope/package": minor
4243
const lines = frontmatter.split('\n').filter(line => line.trim());
4344
for (const line of lines) {
4445
const match = line.match(/^["']?([^"':]+)["']?\s*:\s*(major|minor|patch)/);
4546
if (match) {
4647
const [, packageName, bumpType] = match;
47-
result[packageName.trim()] = bumpType as 'major' | 'minor' | 'patch';
48+
result[packageName.trim()] = bumpType;
4849
}
4950
}
5051

5152
return Object.keys(result).length > 0 ? result : null;
52-
} catch (error) {
53-
// Parsing errors will be caught by changeset status
53+
} catch {
5454
return null;
5555
}
5656
}
5757

58-
function checkChangesetPresence(): boolean {
59-
console.log('\n🔍 Checking for changeset presence...\n');
58+
async function checkChangesetPresence() {
59+
log.info('\n🔍 Checking for changeset presence...\n');
6060

6161
try {
62-
const statusOutput = execSync('yarn changeset status --since=origin/main 2>&1', {
63-
encoding: 'utf-8'
64-
});
65-
66-
if (statusOutput.includes('No changesets present')) {
67-
console.log(`${RED}❌ No changesets found${RESET}\n`);
68-
console.log(`${YELLOW}This PR requires a changeset to document the changes.${RESET}`);
69-
console.log(`${YELLOW}To create a changeset, run: yarn changeset${RESET}\n`);
62+
const { stdout } = await $`yarn changeset status --since=origin/main 2>&1`;
63+
64+
if (stdout.includes('No changesets present')) {
65+
log.error('❌ No changesets found\n');
66+
log.warn('This PR requires a changeset to document the changes.');
67+
log.warn('To create a changeset, run: yarn changeset\n');
7068
return false;
7169
}
7270

73-
console.log(`${GREEN}✅ Changesets found${RESET}`);
71+
log.success('✅ Changesets found');
7472
return true;
7573
} catch (error: any) {
76-
console.log(`${RED}❌ Failed to check changeset status${RESET}\n`);
77-
console.log(error.message);
74+
log.error('❌ Failed to check changeset status\n');
75+
log.info(error.message);
7876
return false;
7977
}
8078
}
8179

82-
function checkForMajorBumps(): boolean {
83-
console.log('\n🔍 Checking for major version bumps...\n');
80+
async function checkForMajorBumps() {
81+
log.info('\n🔍 Checking for major version bumps...\n');
8482

85-
const changesetFiles = readdirSync(CHANGESETS_DIR)
83+
const files = fs.readdirSync(CHANGESETS_DIR);
84+
const changesetFiles = files
8685
.filter(file => file.endsWith('.md') && file !== 'README.md')
87-
.map(file => join(CHANGESETS_DIR, file));
86+
.map(file => path.join(CHANGESETS_DIR, file));
8887

8988
if (changesetFiles.length === 0) {
90-
console.log(`${YELLOW}No changesets found (skipping major check)${RESET}`);
89+
log.warn('No changesets found (skipping major check)');
9190
return true;
9291
}
9392

9493
let hasMajor = false;
95-
const majorBumps: Array<{ file: string; packages: string[] }> = [];
94+
const majorBumps = [];
9695

9796
for (const file of changesetFiles) {
9897
const frontmatter = parseChangesetForMajorCheck(file);
@@ -109,80 +108,69 @@ function checkForMajorBumps(): boolean {
109108
}
110109

111110
if (hasMajor) {
112-
console.log(`${RED}❌ Major version bumps detected!${RESET}\n`);
111+
log.error('❌ Major version bumps detected!\n');
113112
for (const { file, packages } of majorBumps) {
114-
console.log(`${RED} ${file}:${RESET}`);
113+
log.error(` ${file}:`);
115114
for (const pkg of packages) {
116-
console.log(`${RED} - ${pkg}: major${RESET}`);
115+
log.error(` - ${pkg}: major`);
117116
}
118117
}
119-
console.log(`\n${RED}Major version bumps are not allowed.${RESET}`);
120-
console.log(`${YELLOW}If you need to make a breaking change, please discuss with the team first.${RESET}\n`);
118+
log.error('\nMajor version bumps are not allowed.');
119+
log.warn('If you need to make a breaking change, please discuss with the team first.\n');
121120
return false;
122121
}
123122

124-
console.log(`${GREEN}✅ No major version bumps found${RESET}`);
123+
log.success('✅ No major version bumps found');
125124
return true;
126125
}
127126

128-
function validateChangesetStatus(): boolean {
129-
console.log('\n🔍 Validating changesets with changeset status...\n');
127+
async function validateChangesetStatus() {
128+
log.info('\n🔍 Validating changesets with changeset status...\n');
130129

131130
try {
132-
// This validates:
133-
// - Changeset file format
134-
// - Package references
135-
// - Dependency graph
136-
// - Config validity
137-
const statusOutput = execSync('yarn changeset status --since=origin/main 2>&1', {
138-
encoding: 'utf-8'
139-
});
140-
141-
// Check for errors (but "No changesets present" is not an error here)
142-
if (statusOutput.toLowerCase().includes('error') && !statusOutput.includes('No changesets present')) {
143-
console.log(`${RED}❌ Changeset validation failed!${RESET}\n`);
144-
console.log(statusOutput);
131+
const { stdout } = await $`yarn changeset status --since=origin/main 2>&1`;
132+
133+
if (stdout.toLowerCase().includes('error') && !stdout.includes('No changesets present')) {
134+
log.error('❌ Changeset validation failed!\n');
135+
log.info(stdout);
145136
return false;
146137
}
147138

148-
console.log(`${GREEN}✅ Changeset validation passed${RESET}`);
139+
log.success('✅ Changeset validation passed');
149140
return true;
150141
} catch (error: any) {
151-
console.log(`${RED}❌ Changeset validation failed!${RESET}\n`);
152-
console.log(`${RED}Error:${RESET}`, error.message);
153-
if (error.stdout) console.log(error.stdout);
154-
if (error.stderr) console.log(error.stderr);
142+
log.error('❌ Changeset validation failed!\n');
143+
log.error(`Error: ${error.message}`);
144+
if (error.stdout) log.info(error.stdout);
145+
if (error.stderr) log.info(error.stderr);
155146
return false;
156147
}
157148
}
158149

159-
function main(): void {
160-
console.log(`\n${'='.repeat(60)}`);
161-
console.log('Changesets Validation');
162-
console.log(`${'='.repeat(60)}`);
150+
// Main execution
151+
log.info(`\n${'='.repeat(60)}`);
152+
log.info('Changesets Validation');
153+
log.info(`${'='.repeat(60)}`);
163154

164-
const results = {
165-
presence: checkChangesetPresence(),
166-
majorBumps: checkForMajorBumps(),
167-
validation: validateChangesetStatus()
168-
};
155+
const results = {
156+
presence: await checkChangesetPresence(),
157+
majorBumps: await checkForMajorBumps(),
158+
validation: await validateChangesetStatus()
159+
};
169160

170-
console.log(`\n${'='.repeat(60)}`);
171-
console.log('Validation Results:');
172-
console.log(`${'='.repeat(60)}\n`);
161+
log.info(`\n${'='.repeat(60)}`);
162+
log.info('Validation Results:');
163+
log.info(`${'='.repeat(60)}\n`);
173164

174-
console.log(`Changeset presence: ${results.presence ? GREEN + '✅ PASS' : RED + '❌ FAIL'}${RESET}`);
175-
console.log(`Major version check: ${results.majorBumps ? GREEN + '✅ PASS' : RED + '❌ FAIL'}${RESET}`);
176-
console.log(`Changeset validation: ${results.validation ? GREEN + '✅ PASS' : RED + '❌ FAIL'}${RESET}\n`);
165+
log.info(`Changeset presence: ${results.presence ? '✅ PASS' : '❌ FAIL'}`);
166+
log.info(`Major version check: ${results.majorBumps ? '✅ PASS' : '❌ FAIL'}`);
167+
log.info(`Changeset validation: ${results.validation ? '✅ PASS' : '❌ FAIL'}\n`);
177168

178-
const allPassed = results.presence && results.majorBumps && results.validation;
179-
180-
if (!allPassed) {
181-
console.log(`${RED}Validation failed!${RESET}\n`);
182-
process.exit(1);
183-
}
169+
const allPassed = results.presence && results.majorBumps && results.validation;
184170

185-
console.log(`${GREEN}All validations passed! ✅${RESET}\n`);
171+
if (!allPassed) {
172+
log.error('Validation failed!\n');
173+
throw new Error('Validation failed');
186174
}
187175

188-
main();
176+
log.success('All validations passed! ✅\n');

.github/workflows/changesets-version.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,4 @@ jobs:
5757

5858
- name: Post-version hook for dependency-profiles
5959
if: steps.changesets.outputs.hasChangesets == 'true'
60-
run: node .github/scripts/update-dependency-profiles-postbump.mts
60+
run: npx zx .github/scripts/update-dependency-profiles-postbump.mts

.github/workflows/pr.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,4 @@ jobs:
3131
run: yarn install --immutable
3232

3333
- name: Validate changesets
34-
run: node .github/scripts/validate-changesets.mts
34+
run: npx zx .github/scripts/validate-changesets.mts

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@
3232
"clean": "lage clean",
3333
"changeset": "changeset",
3434
"changeset:version": "changeset version && yarn install --mode update-lockfile",
35-
"changeset:version:postbump": "node .github/scripts/update-dependency-profiles-postbump.mts",
35+
"changeset:version:postbump": "zx .github/scripts/update-dependency-profiles-postbump.mts",
3636
"changeset:publish": "changeset publish",
3737
"changeset:status": "changeset status",
38-
"changeset:validate": "node .github/scripts/validate-changesets.mts",
38+
"changeset:validate": "zx .github/scripts/validate-changesets.mts",
3939
"checkchange:changeset": "changeset status --since=origin/main",
4040
"check-publishing": "node ./scripts/src/cli.mjs check-publishing",
4141
"lint": "lage lint",
@@ -67,7 +67,8 @@
6767
"lage": "^2.0.0",
6868
"markdown-link-check": "^3.8.7",
6969
"prettier": "^2.4.1",
70-
"typescript": "^5.8.0"
70+
"typescript": "^5.8.0",
71+
"zx": "^8.2.4"
7172
},
7273
"workspaces": [
7374
"apps/*",

0 commit comments

Comments
 (0)