update publish script

This commit is contained in:
Carl-Gerhard Lindesvärd
2024-05-16 21:44:24 +02:00
committed by Carl-Gerhard Lindesvärd
parent c5d7807584
commit 42736655c2

View File

@@ -2,9 +2,8 @@ import { execSync } from 'node:child_process';
import fs from 'node:fs';
import path from 'node:path';
import arg from 'arg';
import semver from 'semver';
const sdkPackages = ['sdk', 'react-native', 'web', 'nextjs', 'express'];
import type { ReleaseType } from 'semver';
import semver, { RELEASE_TYPES } from 'semver';
const workspacePath = (relativePath: string) =>
path.resolve(__dirname, '../../', relativePath);
@@ -14,13 +13,15 @@ function savePackageJson(absPath: string, data: Record<string, any>) {
}
function exit(message: string, error?: unknown) {
console.log(`${message}`);
console.log(`\n\n${message}`);
if (error instanceof Error) {
console.log(`Error: ${error.message}`);
console.log(error);
} else if (typeof error === 'string') {
console.log(`Error: ${error}`);
}
console.log('\n');
process.exit(1);
}
@@ -35,36 +36,111 @@ function checkUncommittedChanges() {
execSync('git diff HEAD --exit-code');
console.log('✅ No uncommitted changes');
} catch (error) {
exit('Uncommitted changes', error);
exit('Uncommitted changes');
}
}
function getNextVersion(version: string, type: ReleaseType) {
const nextVersion = semver.inc(version, type);
if (!nextVersion) {
throw new Error('Invalid version');
}
if (type.startsWith('pre')) {
return nextVersion.replace(/-.*$/, '-beta');
}
return nextVersion;
}
type IPackageJson = {
type?: string;
name: string;
version: string;
dependencies: Record<string, string>;
devDependencies: Record<string, string>;
};
type IPackageJsonWithExtra = IPackageJson & {
nextVersion: string;
localPath: string;
};
function main() {
const args = arg({
// Types
'--version': String,
'--name': String,
'--test': Boolean,
'--skip-git': Boolean,
// Aliases
'-v': '--version',
// Semver
'--type': String, // major, minor, patch, premajor, preminor, prepatch, or prerelease
});
if (!args['--skip-git']) {
checkUncommittedChanges();
}
const version = args['--version'];
const pkgName = args['--name'];
const type = args['--type'] as ReleaseType;
const test = args['--test'];
const packages: Record<string, IPackageJsonWithExtra> = {};
const registry = test
? 'http://localhost:4873'
: 'https://registry.npmjs.org';
if (version && !semver.valid(version)) {
return console.error('Version is not valid');
if (!RELEASE_TYPES.includes(type)) {
return exit(
`Invalid release type. Valid types are: ${RELEASE_TYPES.join(', ')}`
);
}
try {
for (const name of sdkPackages) {
const properties: Record<string, unknown> = {
if (!pkgName) {
return exit('--name is requred');
}
// Get all SDKs
const sdks = fs
.readdirSync(workspacePath('./packages/sdks'), {
withFileTypes: true,
})
.filter((item) => item.isDirectory() && !item.name.match(/^[._]/))
.map((item) => item.name);
// Get all SDK package.json
for (const name of sdks) {
const pkgJson = fs.readFileSync(
workspacePath(`./packages/sdks/${name}/package.json`),
'utf-8'
);
const parsed = JSON.parse(pkgJson) as IPackageJsonWithExtra;
parsed.nextVersion = getNextVersion(parsed.version, type);
parsed.localPath = `./packages/sdks/${name}`;
packages[parsed.name] = parsed;
}
const target = packages[pkgName];
if (!target) {
return exit('Selected package does not exist');
}
// Find if any package is dependent on the target
const dependents: string[] = [target.name];
function findDependents(visitPackageName: string) {
Object.entries(packages).forEach(([_name, pkg]) => {
if (pkg.dependencies?.[visitPackageName]) {
dependents.push(pkg.name);
findDependents(pkg.name);
}
});
}
findDependents(target.name);
function updatePackageJsonForRelease(name: string) {
const { nextVersion, localPath, ...restPkgJson } = packages[name]!;
const newPkgJson = JSON.parse(
JSON.stringify({
...restPkgJson,
private: false,
version,
type: 'module',
main: './dist/index.js',
module: './dist/index.mjs',
@@ -74,58 +150,72 @@ function main() {
import: './dist/index.js',
require: './dist/index.cjs',
},
};
version: nextVersion,
dependencies: Object.entries(restPkgJson.dependencies).reduce(
(acc, [depName, depVersion]) => {
const dep = packages[depName];
if (!dep) {
return acc;
}
// Not sure if I even should have type: module for any sdk
if (name === 'nextjs') {
delete properties.type;
}
// eslint-disable-next-line @typescript-eslint/no-var-requires
const pkgJson = require(
workspacePath(`./packages/sdks/${name}/package.json`)
);
savePackageJson(workspacePath(`./packages/sdks/${name}/package.json`), {
...pkgJson,
...properties,
dependencies: Object.entries(pkgJson.dependencies).reduce(
(acc, [depName, depVersion]) => ({
...acc,
[depName]: depName.startsWith('@openpanel') ? version : depVersion,
}),
return {
...acc,
[depName]: dependents.includes(depName)
? dep.nextVersion
: depVersion,
};
},
{}
),
});
})
) as IPackageJson;
if (name === '@openpanel/nextjs') {
delete newPkgJson.type;
}
} catch (error) {
exit('Update JSON files', error);
savePackageJson(workspacePath(`${localPath}/package.json`), newPkgJson);
packages[name]!.dependencies = newPkgJson.dependencies;
}
console.log('✅ Update JSON files');
dependents.forEach((dependent) => {
console.log(
`📦 ${dependent} · Old Version: ${packages[dependent]?.version} · Next Version: ${packages[dependent]?.nextVersion}`
);
updatePackageJsonForRelease(dependent);
});
try {
for (const name of sdkPackages) {
execSync('pnpm build', {
cwd: workspacePath(`./packages/sdks/${name}`),
});
}
} catch (error) {
exit('Failed build packages', error);
}
dependents.forEach((dependent) => {
console.log(`🔨 Building ${dependent}`);
execSync('pnpm build', {
cwd: workspacePath(packages[dependent]!.localPath),
});
});
console.log('✅ Built packages');
// Publish
dependents.forEach((dependent) => {
console.log(`🚀 Publishing ${dependent} to ${registry}`);
execSync(`npm publish --access=public --registry ${registry}`, {
cwd: workspacePath(packages[dependent]!.localPath),
});
});
if (!test) {
try {
for (const name of sdkPackages) {
execSync('npm publish --access=public', {
cwd: workspacePath(`./packages/sdks/${name}`),
});
}
} catch (error) {
exit('Failed publish packages', error);
}
}
// Restoring package.json
const filesToRestore = dependents
.map((dependent) => workspacePath(packages[dependent]!.localPath))
.join(' ');
execSync(`git checkout ${filesToRestore}`);
// // Save new versions only 😈
dependents.forEach((dependent) => {
const { nextVersion, localPath, ...restPkgJson } = packages[dependent]!;
console.log(`🚀 Saving ${dependent} (${nextVersion})`);
savePackageJson(workspacePath(`${localPath}/package.json`), {
...restPkgJson,
version: nextVersion,
});
});
console.log('✅ All done!');
}