Skip to content

Commit

Permalink
cleanup(publish)!: remove --contents flag
Browse files Browse the repository at this point in the history
- this was a legacy lerna feature which made the publishing flow much more complex than it has to be. we no longer use this, so remove it from publisher, simplifying the flow.
- has a side effect of executing the prepublish scripts right before publishing. (instead of a special step at the beginning of publish)
  • Loading branch information
AviVahl committed Jul 5, 2024
1 parent f3e83b1 commit 389218a
Show file tree
Hide file tree
Showing 7 changed files with 10 additions and 118 deletions.
4 changes: 1 addition & 3 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,14 @@ program
.command('publish [target]')
.description('publish unpublished packages')
.option('--dry-run', 'no actual publishing (passed to npm as well)', false)
.option('--contents <name>', 'subdirectory to publish (similar to lerna publish --contents)', '.')
.option('--registry <url>', 'npm registry to use')
.option('--tag <tag>', 'tag to use for published version', 'latest')
.action(async (targetPath: string, { dryRun, contents, registry, tag }) => {
.action(async (targetPath: string, { dryRun, registry, tag }) => {
const { publish } = await import('./commands/publish.js');

await publish({
directoryPath: path.resolve(targetPath || ''),
dryRun,
distDir: contents,
registryUrl: registry,
tag,
});
Expand Down
29 changes: 7 additions & 22 deletions src/commands/publish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,14 @@ import fs from 'node:fs';
import path from 'node:path';
import { log } from '../utils/log.js';
import { loadEnvNpmConfig } from '../utils/npm-config.js';
import {
executePrepublishScripts,
getPackagesToPublish,
npmPublishArgs,
removePrepublishScripts,
} from '../utils/npm-publish.js';
import { getPackagesToPublish } from '../utils/npm-publish.js';
import { NpmRegistry, officialNpmRegistryUrl, uriToIdentifier } from '../utils/npm-registry.js';
import { spawnSyncLogged } from '../utils/process.js';

export interface PublishOptions {
directoryPath: string;
/** @default false */
dryRun?: boolean;
/** @default '.' */
distDir?: string;
/** @default .npmrc or official npm registry */
registryUrl?: string;
/** @default 'latest' */
Expand All @@ -28,7 +21,6 @@ export interface PublishOptions {
export async function publish({
directoryPath,
dryRun = false,
distDir = '.',
registryUrl,
tag = 'latest',
}: PublishOptions): Promise<void> {
Expand All @@ -39,24 +31,21 @@ export async function publish({
const token = npmConfig[`${uriToIdentifier(resolvedRegistryUrl)}:_authToken`];
const registry = new NpmRegistry(resolvedRegistryUrl, token);

const filesToRestore = new Map<string, string>();
try {
const packagesToPublish = await getPackagesToPublish(packages, registry);

if (packagesToPublish.length) {
for (const npmPackage of packagesToPublish) {
executePrepublishScripts(npmPackage);
const publishArgs: string[] = ['publish', '--registry', registry.url];
if (dryRun) {
publishArgs.push('--dry-run');
}

for (const npmPackage of packagesToPublish) {
await removePrepublishScripts(path.join(npmPackage.directoryPath, distDir, 'package.json'), filesToRestore);
if (tag !== 'latest') {
publishArgs.push('--tag', tag);
}

const publishArgs = npmPublishArgs(registry, dryRun, tag);

for (const npmPackage of packagesToPublish) {
const spawnOptions: SpawnSyncOptions = {
cwd: path.join(npmPackage.directoryPath, distDir),
cwd: npmPackage.directoryPath,
stdio: 'inherit',
shell: true,
};
Expand All @@ -67,10 +56,6 @@ export async function publish({
log(`Nothing to publish.`);
}
} finally {
for (const [filePath, fileContents] of filesToRestore) {
await fs.promises.writeFile(filePath, fileContents);
}
filesToRestore.clear();
registry.dispose();
}
}
62 changes: 1 addition & 61 deletions src/utils/npm-publish.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import { isPlainObject, isString, type INpmPackage } from '@wixc3/resolve-directory-context';
import type childProcess from 'node:child_process';
import fs from 'node:fs';
import { type INpmPackage } from '@wixc3/resolve-directory-context';
import { retry } from 'promise-assist';
import type { PackageJson } from 'type-fest';
import { log, logWarn } from './log.js';
import type { NpmRegistry } from './npm-registry.js';
import { spawnSyncLogged } from './process.js';

export async function getPackagesToPublish(packages: INpmPackage[], registry: NpmRegistry): Promise<INpmPackage[]> {
const packagesToPublish: INpmPackage[] = [];
Expand Down Expand Up @@ -43,59 +39,3 @@ export async function getPackagesToPublish(packages: INpmPackage[], registry: Np
}
return packagesToPublish;
}

export function npmPublishArgs(registry: NpmRegistry, dryRun: boolean, tag: string): string[] {
const publishArgs: string[] = ['publish', '--registry', registry.url];
if (dryRun) {
publishArgs.push('--dry-run');
}
if (tag !== 'latest') {
publishArgs.push('--tag', tag);
}
return publishArgs;
}

export function executePrepublishScripts({ displayName, directoryPath, packageJson }: INpmPackage): void {
const spawnOptions: childProcess.SpawnSyncOptions = {
cwd: directoryPath,
stdio: 'inherit',
shell: true,
};
const { scripts = {} } = packageJson;
if (isString(scripts.prepare)) {
spawnSyncLogged('npm', ['run', 'prepare'], spawnOptions, displayName);
}
if (isString(scripts.prepublishOnly)) {
spawnSyncLogged('npm', ['run', 'prepublishOnly'], spawnOptions, displayName);
}
if (isString(scripts.prepack)) {
spawnSyncLogged('npm', ['run', 'prepack'], spawnOptions, displayName);
}
}

export async function removePrepublishScripts(
packageJsonPath: string,
filesToRestore: Map<string, string>,
): Promise<void> {
const packageJsonContents = await fs.promises.readFile(packageJsonPath, 'utf8');
const packageJson = JSON.parse(packageJsonContents) as PackageJson;
if (!isPlainObject(packageJson)) {
throw new Error(`${packageJsonPath} is not a valid json object.`);
}
const { scripts } = packageJson;
if (
scripts &&
(scripts.prepare !== undefined || scripts.prepublishOnly !== undefined || scripts.prepack !== undefined)
) {
delete scripts.prepare;
delete scripts.prepublishOnly;
delete scripts.prepack;
// retain original EOL. JSON.stringify always outputs \n.
const newPackageJsonContent = JSON.stringify(packageJson, null, 2) + '\n';
const normalizedNewPackageJsonContent = packageJsonContents.includes('\r\n')
? newPackageJsonContent.replace(/\n/g, '\r\n')
: newPackageJsonContent;
filesToRestore.set(packageJsonPath, packageJsonContents);
await fs.promises.writeFile(packageJsonPath, normalizedNewPackageJsonContent);
}
}
1 change: 0 additions & 1 deletion test/fixtures/dist-dir/.gitignore

This file was deleted.

11 changes: 0 additions & 11 deletions test/fixtures/dist-dir/build.js

This file was deleted.

8 changes: 0 additions & 8 deletions test/fixtures/dist-dir/package.json

This file was deleted.

13 changes: 1 addition & 12 deletions test/publish.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,6 @@ describe('pleb publish', { timeout: 30_000 }, function () {
assert.equal(exitCode, 0);
});

it('allows specifying a custom dist directory', async () => {
const distDirFixturePath = join(fixturesRoot, 'dist-dir');

const { output, exitCode } = await runCli(['publish', distDirFixturePath, '--contents', 'npm']);

assert.match(output, /pleb-new-package: package was never published./);
assert.match(output, /total files:\s+2/);
assert.match(output, /pleb-new-package: done./);
assert.equal(exitCode, 0);
});

it('publishes workspace packages in correct order (deps first)', async () => {
const distDirFixturePath = join(fixturesRoot, 'yarn-workspace');

Expand All @@ -62,7 +51,7 @@ describe('pleb publish', { timeout: 30_000 }, function () {
assert.match(output, /yarn-workspace-a: done./);
assert.match(output, /yarn-workspace-b: done./);
assert.ok(output.indexOf('prepack yarn-workspace-b') < output.indexOf('prepack yarn-workspace-a'));
assert.ok(output.indexOf('prepack yarn-workspace-a') < output.indexOf('yarn-workspace-b: done.'));
assert.ok(output.indexOf('yarn-workspace-b: done.') < output.indexOf('prepack yarn-workspace-a'));
assert.ok(output.indexOf('yarn-workspace-b: done.') < output.indexOf('yarn-workspace-a: done.'));
assert.equal(exitCode, 0);
});
Expand Down

0 comments on commit 389218a

Please sign in to comment.