Skip to content

Commit ed843de

Browse files
Add multi-version publishing script with dist-tags
- Creates publish-versions.js script to handle workspace naming conflicts - Publishes all versions under 'libpg-query' name with dist-tags pg13, pg14, pg15, pg16, pg17 - Includes dry-run mode for testing - Handles backup/restore of package.json files - Follows existing patterns from analyze-sizes.js - Adds convenient npm scripts for publishing Co-Authored-By: Dan Lynch <pyramation@gmail.com>
1 parent 937fb10 commit ed843de

3 files changed

Lines changed: 196 additions & 4 deletions

File tree

TODO.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
TODO
22

33
- [ ] update the @pgsql/types for each
4-
- [ ] publish setup with name proxy
4+
- [x] publish setup with name proxy
55

66
### Workaround Ideas for Your `dist-tag` Use Case:
77

@@ -33,4 +33,4 @@ pnpm build
3333
pnpm publish --tag v17
3434
```
3535

36-
You can then `npm install libpg-query@v17`, `@v16`, etc., via tags, while keeping only one name.
36+
You can then `npm install libpg-query@v17`, `@v16`, etc., via tags, while keeping only one name.

package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@
1313
"build:all": "pnpm -r build",
1414
"test:all": "pnpm -r test",
1515
"clean:all": "pnpm -r clean",
16-
"analyze:sizes": "node scripts/analyze-sizes.js"
16+
"analyze:sizes": "node scripts/analyze-sizes.js",
17+
"publish:dry-run": "node scripts/publish-versions.js --dry-run",
18+
"publish:versions": "node scripts/publish-versions.js",
19+
"publish:specific": "node scripts/publish-versions.js --versions"
1720
},
1821
"devDependencies": {
1922
"@types/node": "^20.0.0"
2023
}
21-
}
24+
}

scripts/publish-versions.js

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
const fs = require('fs');
2+
const path = require('path');
3+
const { execSync } = require('child_process');
4+
5+
function getVersionPackages() {
6+
const versionsDir = './versions';
7+
const packages = [];
8+
9+
if (fs.existsSync(versionsDir)) {
10+
const versions = fs.readdirSync(versionsDir)
11+
.filter(dir => fs.statSync(path.join(versionsDir, dir)).isDirectory())
12+
.sort((a, b) => parseInt(a) - parseInt(b));
13+
14+
versions.forEach(version => {
15+
const packageJsonPath = path.join(versionsDir, version, 'package.json');
16+
if (fs.existsSync(packageJsonPath)) {
17+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
18+
packages.push({
19+
path: path.join(versionsDir, version),
20+
packageJsonPath: packageJsonPath,
21+
originalName: packageJson.name,
22+
version: version,
23+
majorVersion: `${version}.0.0`
24+
});
25+
}
26+
});
27+
}
28+
29+
return packages;
30+
}
31+
32+
function backupPackageJson(packagePath) {
33+
const backupPath = packagePath + '.backup';
34+
fs.copyFileSync(packagePath, backupPath);
35+
return backupPath;
36+
}
37+
38+
function restorePackageJson(packagePath) {
39+
const backupPath = packagePath + '.backup';
40+
if (fs.existsSync(backupPath)) {
41+
fs.copyFileSync(backupPath, packagePath);
42+
fs.unlinkSync(backupPath);
43+
}
44+
}
45+
46+
function modifyPackageJsonForPublishing(packagePath, version) {
47+
const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
48+
49+
packageJson.name = 'libpg-query';
50+
51+
packageJson.version = `${version}.0.0`;
52+
53+
fs.writeFileSync(packagePath, JSON.stringify(packageJson, null, 2) + '\n');
54+
55+
return packageJson;
56+
}
57+
58+
function publishPackage(packageInfo, dryRun = false) {
59+
const { path: packagePath, packageJsonPath, version } = packageInfo;
60+
const distTag = `pg${version}`;
61+
62+
console.log(`\n📦 Publishing ${packageInfo.originalName} as libpg-query@${distTag}`);
63+
64+
if (dryRun) {
65+
console.log(` [DRY RUN] Would run: cd ${packagePath} && pnpm publish --tag ${distTag}`);
66+
return;
67+
}
68+
69+
let backupPath;
70+
try {
71+
backupPath = backupPackageJson(packageJsonPath);
72+
73+
modifyPackageJsonForPublishing(packageJsonPath, version);
74+
75+
console.log(` Building package...`);
76+
execSync('pnpm build', { cwd: packagePath, stdio: 'inherit' });
77+
78+
console.log(` Publishing with tag ${distTag}...`);
79+
execSync(`pnpm publish --tag ${distTag}`, { cwd: packagePath, stdio: 'inherit' });
80+
81+
console.log(` ✅ Successfully published libpg-query@${distTag}`);
82+
83+
} catch (error) {
84+
console.error(` ❌ Failed to publish ${packageInfo.originalName}:`, error.message);
85+
throw error;
86+
} finally {
87+
if (backupPath) {
88+
restorePackageJson(packageJsonPath);
89+
}
90+
}
91+
}
92+
93+
function publishAllVersions(options = {}) {
94+
const { dryRun = false, versions = [] } = options;
95+
96+
console.log('🚀 libpg-query Multi-Version Publisher');
97+
console.log('=====================================');
98+
99+
if (dryRun) {
100+
console.log('🔍 DRY RUN MODE - No actual publishing will occur\n');
101+
}
102+
103+
const packages = getVersionPackages();
104+
105+
const packagesToPublish = versions.length > 0
106+
? packages.filter(pkg => versions.includes(pkg.version))
107+
: packages;
108+
109+
if (packagesToPublish.length === 0) {
110+
console.log('❌ No packages found to publish');
111+
return;
112+
}
113+
114+
console.log(`Found ${packagesToPublish.length} packages to publish:`);
115+
packagesToPublish.forEach(pkg => {
116+
console.log(` - ${pkg.originalName} (v${pkg.version}) -> libpg-query@pg${pkg.version}`);
117+
});
118+
119+
if (!dryRun) {
120+
console.log('\n⚠️ This will publish to npm registry. Continue? (Press Ctrl+C to cancel)');
121+
execSync('sleep 5');
122+
}
123+
124+
let publishedCount = 0;
125+
let failedCount = 0;
126+
127+
for (const packageInfo of packagesToPublish) {
128+
try {
129+
publishPackage(packageInfo, dryRun);
130+
publishedCount++;
131+
} catch (error) {
132+
failedCount++;
133+
console.error(`Failed to publish ${packageInfo.originalName}`);
134+
}
135+
}
136+
137+
console.log('\n📊 Publishing Summary');
138+
console.log('====================');
139+
console.log(`✅ Successfully published: ${publishedCount}`);
140+
console.log(`❌ Failed: ${failedCount}`);
141+
142+
if (!dryRun && publishedCount > 0) {
143+
console.log('\n🎉 Publishing complete! You can now install with:');
144+
packagesToPublish.forEach(pkg => {
145+
console.log(` npm install libpg-query@pg${pkg.version}`);
146+
});
147+
}
148+
}
149+
150+
function main() {
151+
const args = process.argv.slice(2);
152+
const options = {
153+
dryRun: args.includes('--dry-run') || args.includes('-d'),
154+
versions: []
155+
};
156+
157+
const versionIndex = args.findIndex(arg => arg === '--versions' || arg === '-v');
158+
if (versionIndex !== -1 && args[versionIndex + 1]) {
159+
options.versions = args[versionIndex + 1].split(',').map(v => v.trim());
160+
}
161+
162+
if (args.includes('--help') || args.includes('-h')) {
163+
console.log(`
164+
libpg-query Multi-Version Publisher
165+
166+
Usage:
167+
node scripts/publish-versions.js [options]
168+
169+
Options:
170+
--dry-run, -d Run in dry-run mode (no actual publishing)
171+
--versions, -v <list> Comma-separated list of versions to publish (e.g., "13,16,17")
172+
--help, -h Show this help message
173+
174+
Examples:
175+
node scripts/publish-versions.js --dry-run
176+
node scripts/publish-versions.js --versions "16,17"
177+
node scripts/publish-versions.js --dry-run --versions "13"
178+
`);
179+
return;
180+
}
181+
182+
publishAllVersions(options);
183+
}
184+
185+
if (require.main === module) {
186+
main();
187+
}
188+
189+
module.exports = { publishAllVersions, getVersionPackages };

0 commit comments

Comments
 (0)