Skip to content

Commit c60011f

Browse files
committed
Update release process documentation and implement optional skip functionality for publishing
1 parent e2784b4 commit c60011f

14 files changed

Lines changed: 154 additions & 47 deletions

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,11 @@ This project uses a two-step automated release process:
642642
2. **Update CHANGELOG.md**: Edit manually
643643
3. **Publish**: `npm run release:publish`
644644

645+
Optional publish skips:
646+
- `npm run release:publish -- --skip=vintasend-medplum,vintasend-ts-twilio`
647+
- `npm run release:publish -- --skip-root`
648+
- `npm run release:publish -- --skip=root,vintasend-medplum`
649+
645650
For detailed instructions, see:
646651
- [Release Guide](RELEASE_GUIDE.md) - Complete walkthrough with examples
647652
- [Quick Reference](RELEASE_QUICK_REF.md) - Command cheatsheet

RELEASE_GUIDE.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ Manually update the changelog with release notes.
2121
**Step 3: Publish**
2222
```bash
2323
npm run release:publish
24+
25+
# Skip specific implementation packages
26+
npm run release:publish -- --skip=vintasend-medplum,vintasend-ts-twilio
27+
28+
# Skip root package only
29+
npm run release:publish -- --skip-root
30+
31+
# Skip root package + specific implementations
32+
npm run release:publish -- --skip=root,vintasend-medplum
2433
```
2534

2635
## Two-Step Release Process
@@ -120,6 +129,7 @@ npm publish --tag alpha
120129
**Building**: Builds all packages before publishing
121130
**Publishing**: Publishes to npm (main package first, then implementations)
122131
**Git Commits**: Creates separate commits for each package
132+
**Optional Skip List**: Supports `--skip=<comma-separated-package-names>` and `--skip-root`
123133

124134
## What You Do Manually
125135

RELEASE_QUICK_REF.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ Edit the file manually with release notes.
1515
### Step 3: Publish
1616
```bash
1717
npm run release:publish
18+
19+
# Skip specific implementation packages
20+
npm run release:publish -- --skip=vintasend-medplum,vintasend-ts-twilio
21+
22+
# Skip root package
23+
npm run release:publish -- --skip-root
1824
```
1925

2026
## What Happens

scripts/release-publish.js

Lines changed: 123 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,43 @@ const { readPackageJson, getPackageName } = require('./utils/package-updater');
88
const { buildPackage, testPackage, publishPackage } = require('./utils/publisher');
99
const { stageFiles, commit } = require('./utils/git-handler');
1010

11+
// Parse command line arguments
12+
const args = process.argv.slice(2);
13+
14+
function getSkippedPackageNames(cliArgs) {
15+
const skippedPackageNames = new Set();
16+
17+
for (let i = 0; i < cliArgs.length; i++) {
18+
const arg = cliArgs[i];
19+
20+
if (arg === '--skip' && cliArgs[i + 1]) {
21+
const listArg = cliArgs[i + 1];
22+
listArg
23+
.split(',')
24+
.map(item => item.trim())
25+
.filter(Boolean)
26+
.forEach(item => skippedPackageNames.add(item));
27+
i += 1;
28+
continue;
29+
}
30+
31+
if (arg.startsWith('--skip=')) {
32+
arg
33+
.slice('--skip='.length)
34+
.split(',')
35+
.map(item => item.trim())
36+
.filter(Boolean)
37+
.forEach(item => skippedPackageNames.add(item));
38+
}
39+
40+
if (arg === '--skip-root') {
41+
skippedPackageNames.add('root');
42+
}
43+
}
44+
45+
return skippedPackageNames;
46+
}
47+
1148
// Paths
1249
const rootDir = path.join(__dirname, '..');
1350
const rootPackageJsonPath = path.join(rootDir, 'package.json');
@@ -73,56 +110,100 @@ async function main() {
73110

74111
const releaseState = JSON.parse(fs.readFileSync(stateFilePath, 'utf8'));
75112
const { version, packages } = releaseState;
113+
const rootPackage = readPackageJson(rootPackageJsonPath);
114+
const rootPackageName = rootPackage.name;
115+
116+
const requestedSkips = getSkippedPackageNames(args);
117+
const rootAliases = new Set(['root', 'main', rootPackageName]);
118+
const skipRootPackage = Array.from(requestedSkips).some(name => rootAliases.has(name));
119+
120+
const implementationPackages = packages.filter(pkg => !requestedSkips.has(pkg.name));
121+
const skippedImplementationPackages = packages.filter(pkg => requestedSkips.has(pkg.name));
122+
123+
const knownPackageNames = new Set([rootPackageName, 'root', 'main', ...packages.map(pkg => pkg.name)]);
124+
const unknownSkippedPackages = Array.from(requestedSkips).filter(name => !knownPackageNames.has(name));
125+
76126
logInfo(`Release version: ${version}`);
77-
logInfo(`Packages to publish: ${packages.length + 1}`);
127+
logInfo(`Packages to publish: ${implementationPackages.length + (skipRootPackage ? 0 : 1)}`);
78128

79-
// Step 2: Get commit message for main package
80-
logStep('2', 'Getting commit message for main package...');
81-
const defaultMainCommit = `Release v${version}`;
82-
const mainCommitMessage = await question(`Commit message for main package (press Enter for "${defaultMainCommit}"): `);
83-
const finalMainCommit = mainCommitMessage.trim() || defaultMainCommit;
84-
logInfo(`Main package commit: "${finalMainCommit}"`);
129+
if (skipRootPackage || skippedImplementationPackages.length > 0) {
130+
logWarning('Some packages were skipped by CLI options');
131+
if (skipRootPackage) {
132+
logInfo(`Skipped root package: ${rootPackageName}`);
133+
}
134+
if (skippedImplementationPackages.length > 0) {
135+
logInfo(`Skipped implementations: ${skippedImplementationPackages.map(pkg => pkg.name).join(', ')}`);
136+
}
137+
}
85138

86-
// Step 3: Test and build main package
87-
logStep('3', 'Testing main package...');
88-
const testResult = testPackage(rootDir, false);
89-
if (testResult.success === false) {
90-
logError('Tests failed for main package!');
91-
console.log(testResult.error);
92-
process.exit(1);
139+
if (unknownSkippedPackages.length > 0) {
140+
logWarning(`Unknown package names in skip list: ${unknownSkippedPackages.join(', ')}`);
93141
}
94-
logSuccess('Tests passed');
95142

96-
logStep('4', 'Building main package...');
97-
buildPackage(rootDir, false);
98-
logSuccess('Build completed');
143+
// Step 2: Get commit message for main package
144+
let finalMainCommit;
145+
if (!skipRootPackage) {
146+
logStep('2', 'Getting commit message for main package...');
147+
const defaultMainCommit = `Release v${version}`;
148+
const mainCommitMessage = await question(`Commit message for main package (press Enter for "${defaultMainCommit}"): `);
149+
finalMainCommit = mainCommitMessage.trim() || defaultMainCommit;
150+
logInfo(`Main package commit: "${finalMainCommit}"`);
151+
} else {
152+
logStep('2', 'Skipping main package commit message...');
153+
logInfo('Main package was skipped by CLI options');
154+
}
99155

100-
// Step 5: Commit main package
101-
logStep('5', 'Committing main package...');
102-
stageFiles(['.'], false); // Stage all changes
103-
commit(finalMainCommit, false);
104-
logSuccess('Main package committed');
156+
// Step 3: Test and build main package
157+
if (!skipRootPackage) {
158+
logStep('3', 'Testing main package...');
159+
const testResult = testPackage(rootDir, false);
160+
if (testResult.success === false) {
161+
logError('Tests failed for main package!');
162+
console.log(testResult.error);
163+
process.exit(1);
164+
}
165+
logSuccess('Tests passed');
105166

106-
// Step 6: Publish main package
107-
logStep('6', 'Publishing main package...');
108-
logWarning('Publishing main package - this will open a browser for 2FA authorization');
109-
logInfo('After authorizing in the browser, you have 5 minutes to publish all packages');
110-
publishPackage(rootDir, false);
111-
logSuccess(`Published vintasend@${version} to npm`);
167+
logStep('4', 'Building main package...');
168+
buildPackage(rootDir, false);
169+
logSuccess('Build completed');
112170

113-
logWarning('Please confirm you have authorized npm publish in your browser');
114-
await question('Press Enter after authorizing in the browser: ');
115-
logSuccess('Authorization confirmed - proceeding with implementation publishing');
171+
// Step 5: Commit main package
172+
logStep('5', 'Committing main package...');
173+
stageFiles(['.'], false); // Stage all changes
174+
commit(finalMainCommit, false);
175+
logSuccess('Main package committed');
176+
177+
// Step 6: Publish main package
178+
logStep('6', 'Publishing main package...');
179+
logWarning('Publishing main package - this will open a browser for 2FA authorization');
180+
logInfo('After authorizing in the browser, you have 5 minutes to publish all packages');
181+
publishPackage(rootDir, false);
182+
logSuccess(`Published ${rootPackageName}@${version} to npm`);
183+
184+
logWarning('Please confirm you have authorized npm publish in your browser');
185+
await question('Press Enter after authorizing in the browser: ');
186+
logSuccess('Authorization confirmed - proceeding with implementation publishing');
187+
} else {
188+
logStep('3', 'Skipping main package test/build/commit/publish...');
189+
logWarning('Root package publishing was skipped. Ensure npm auth is valid before publishing implementations.');
190+
}
116191

117192
// Step 7: For each implementation, get commit message, test, build, commit, and publish
118-
logStep('7', `Publishing ${packages.length} implementation packages...`);
193+
logStep('7', `Publishing ${implementationPackages.length} implementation packages...`);
194+
195+
let publishedImplementations = 0;
119196

120-
for (let i = 0; i < packages.length; i++) {
121-
const pkg = packages[i];
197+
if (implementationPackages.length === 0) {
198+
logWarning('No implementation packages left to publish after applying skip list');
199+
}
200+
201+
for (let i = 0; i < implementationPackages.length; i++) {
202+
const pkg = implementationPackages[i];
122203
const pkgNum = i + 1;
123204

124205
log(`\n${'─'.repeat(60)}`, 'cyan');
125-
log(`Package ${pkgNum}/${packages.length}: ${pkg.name}`, 'bright');
206+
log(`Package ${pkgNum}/${implementationPackages.length}: ${pkg.name}`, 'bright');
126207
log('─'.repeat(60), 'cyan');
127208

128209
// Get commit message for this implementation
@@ -167,6 +248,7 @@ async function main() {
167248
try {
168249
publishPackage(pkg.dir, false);
169250
logSuccess(`Published ${pkg.name}@${version}`);
251+
publishedImplementations += 1;
170252
} catch (error) {
171253
logError(`Failed to publish ${pkg.name}: ${error.message}`);
172254
}
@@ -182,7 +264,11 @@ async function main() {
182264
log('✓ RELEASE COMPLETED SUCCESSFULLY!', 'green');
183265
log('='.repeat(50), 'green');
184266
console.log(`\nReleased version: ${version}`);
185-
console.log(`Packages published: ${packages.length + 1}`);
267+
console.log(`Packages published: ${publishedImplementations + (skipRootPackage ? 0 : 1)}`);
268+
if (skipRootPackage || skippedImplementationPackages.length > 0) {
269+
const skippedCount = skippedImplementationPackages.length + (skipRootPackage ? 1 : 0);
270+
console.log(`Packages skipped: ${skippedCount}`);
271+
}
186272
console.log('\nNext steps:');
187273
console.log(' 1. Review the commits: git log');
188274
console.log(' 2. Push to remote: git push');

0 commit comments

Comments
 (0)