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
59 changes: 0 additions & 59 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

138 changes: 121 additions & 17 deletions scripts/publish.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ const argv = minimist(process.argv.slice(2));
const nextVersion = argv.version;
const skipCli = argv['skip-cli'] === true;
const dryRun = argv['dry-run'] === true;
const publishedPackageNames = new Set([
'@nangohq/types',
'@nangohq/nango-yaml',
'@nangohq/providers',
'@nangohq/node',
'@nangohq/runner-sdk',
'@nangohq/frontend',
'nango'
]);
const lockfileDependencyFields = ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies'];

if (!nextVersion) {
echo`${chalk.red(`Please specify a version: "node publish.mjs 0.0.1"`)}`;
Expand All @@ -30,42 +40,42 @@ await bumpVersionTs();
await tsBuild();

// ---- Publish
await bumpWorkspacePackageVersion('@nangohq/types');
await npmPublish('@nangohq/types');
await bumpReference('@nangohq/types');
await npmInstall();

await bumpWorkspacePackageVersion('@nangohq/nango-yaml');
await npmPublish('@nangohq/nango-yaml');
await bumpReference('@nangohq/nango-yaml');
await npmInstall();

await bumpWorkspacePackageVersion('@nangohq/providers');
await npmPublish('@nangohq/providers');
await bumpReference('@nangohq/providers');
await npmInstall();

await bumpWorkspacePackageVersion('@nangohq/node');
await npmPublish('@nangohq/node');
await bumpReference('@nangohq/node');
await npmInstall();

await bumpWorkspacePackageVersion('@nangohq/runner-sdk');
await npmPublish('@nangohq/runner-sdk');
await bumpReference('@nangohq/runner-sdk');
await npmInstall();

// TODO: to delete maybe, seems unnecessary
await bumpWorkspacePackageVersion('@nangohq/frontend');
await npmPublish('@nangohq/frontend');
await bumpReference('@nangohq/frontend');
await npmInstall();

if (!skipCli) {
await bumpWorkspacePackageVersion('nango');
await npmPublish('nango');
await npmInstall();
}
// ---- /Publish

await $`npm version "${nextVersion}" --no-git-tag-version --allow-same-version`;
await bumpRootVersion();

echo``;
await npmInstall();
echo(chalk.green(`${figures.tick} npm install`));
await bumpLockfileVersions();
echo(chalk.green(`${figures.tick} package-lock.json`));
echo(chalk.grey('done'));

// Output for post deploy debug
Expand Down Expand Up @@ -110,18 +120,67 @@ async function npmPublish(packageName) {
process.exit(1);
}

await $`npm version ${nextVersion} -w "${packageName}"`;
if (!dryRun) {
await $`npm publish --access public --provenance -w "${packageName}"`;
if (dryRun) {
echo(chalk.yellow(`${figures.tick} Dry run, skipping publish ${packageName}`));
return;
}

await $`npm publish --access public --provenance -w "${packageName}"`;

echo(chalk.green(`${figures.tick} Published ${packageName} `));
});
}

// --- Version bump functions ---
// We intentionally avoid `npm install` and `npm version` here and use direct JSON file manipulation instead.
// npm install on Linux CI strips platform-specific optional dependencies (e.g. lightningcss-darwin-arm64)
// from package-lock.json due to a long-standing npm bug (https://github.com/npm/cli/issues/4828).
// A fix shipped in npm 11.3.0 but does not fully resolve the issue, we still see it on npm 11.5.1.
// By never letting npm touch the lockfile during publish, we preserve all platform entries.
async function bumpWorkspacePackageVersion(packageName) {
const packagesJson = await glob('packages/*/package.json');
for (const packageJson of packagesJson) {
let content;
try {
content = JSON.parse((await fs.readFile(packageJson)).toString());
} catch (err) {
echo`${chalk.red(`Failed to parse ${packageJson}: ${err.message}`)}`;
process.exit(1);
}
if (content.name !== packageName) {
continue;
}

if (content.version !== nextVersion) {
content.version = nextVersion;
await fs.writeFile(packageJson, `${JSON.stringify(content, null, 4)}\n`);
echo(chalk.grey(` ${figures.tick} Bumped ${packageName} version in ${packageJson}`));
}
return;
Comment thread
propel-code-bot[bot] marked this conversation as resolved.
}

echo`${chalk.red(`Could not find workspace package ${packageName}`)}`;
process.exit(1);
}

async function bumpRootVersion() {
const rootPackageJson = 'package.json';
let content;
try {
content = JSON.parse((await fs.readFile(rootPackageJson)).toString());
} catch (err) {
echo`${chalk.red(`Failed to parse ${rootPackageJson}: ${err.message}`)}`;
process.exit(1);
}
if (content.version !== nextVersion) {
content.version = nextVersion;
await fs.writeFile(rootPackageJson, `${JSON.stringify(content, null, 4)}\n`);
echo(chalk.grey(` ${figures.tick} Bumped root package version in ${rootPackageJson}`));
}
}

async function bumpReference(packageName) {
const packagesJson = await glob('packages/*/package.json');
// We don't use npm install, because it behaves incoherently with workspaces and different terminals
for (const packageJson of packagesJson) {
const fp = packageJson;
const content = (await fs.readFile(fp)).toString();
Expand All @@ -135,8 +194,53 @@ async function bumpReference(packageName) {
}
}

async function npmInstall() {
await spinner('npm install', async () => {
await $`npm i`;
async function bumpLockfileVersions() {
await spinner('update package-lock versions', async () => {
const lockfilePath = 'package-lock.json';
let lock;
try {
lock = JSON.parse((await fs.readFile(lockfilePath)).toString());
} catch (err) {
echo`${chalk.red(`Failed to parse ${lockfilePath}: ${err.message}`)}`;
process.exit(1);
}

if (lock.version) {
lock.version = nextVersion;
}
if (lock.packages?.['']?.version) {
lock.packages[''].version = nextVersion;
}

for (const [, packageMetadata] of Object.entries(lock.packages ?? {})) {
if (!packageMetadata || typeof packageMetadata !== 'object') {
continue;
}

if (
typeof packageMetadata.name === 'string' &&
typeof packageMetadata.version === 'string' &&
publishedPackageNames.has(packageMetadata.name) &&
versionRegex.test(packageMetadata.version)
) {
packageMetadata.version = nextVersion;
}

for (const field of lockfileDependencyFields) {
const dependencies = packageMetadata[field];
if (!dependencies || typeof dependencies !== 'object') {
continue;
}

for (const dependencyName of publishedPackageNames) {
const currentValue = dependencies[dependencyName];
if (typeof currentValue === 'string' && versionRegex.test(currentValue)) {
dependencies[dependencyName] = nextVersion;
}
}
}
}

await fs.writeFile(lockfilePath, `${JSON.stringify(lock, null, 4)}\n`);
});
}
Loading