Skip to content

Commit

Permalink
feat(nx-plugin): add verdaccio to create package e2e
Browse files Browse the repository at this point in the history
  • Loading branch information
xiongemi committed Jun 14, 2023
1 parent a19fbb1 commit 2880d9a
Show file tree
Hide file tree
Showing 17 changed files with 231 additions and 165 deletions.
11 changes: 5 additions & 6 deletions e2e/utils/global-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default async function (globalConfig: Config.ConfigGlobals) {
{ stdio: 'pipe' }
);

childProcess?.stdout?.on('data', (data) => {
const listener = (data) => {
if (data.toString().includes('http://localhost:')) {
const port = parseInt(
data.toString().match(/localhost:(?<port>\d+)/)?.groups?.port
Expand All @@ -35,12 +35,11 @@ export default async function (globalConfig: Config.ConfigGlobals) {
console.log('Set npm and yarn config registry to ' + registry);

resolve(childProcess);
childProcess.stdout?.off('data', listener);
}
});
childProcess?.stderr?.on('data', (data) => {
process.stderr.write(data);
reject(data);
});
};
childProcess?.stdout?.on('data', listener);
childProcess?.stderr?.pipe(process.stderr);
childProcess.on('error', (err) => {
console.log('local registry error', err);
reject(err);
Expand Down
4 changes: 2 additions & 2 deletions e2e/workspace-create/src/create-nx-plugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
uniq,
runCreatePlugin,
cleanupProject,
tmpProjPath,
} from '@nx/e2e/utils';

describe('create-nx-plugin', () => {
Expand Down Expand Up @@ -64,7 +63,8 @@ describe('create-nx-plugin', () => {
runCLI(`build ${pluginName}`);
checkFilesExist(
`dist/${pluginName}/package.json`,
`dist/${pluginName}/generators.json`
`dist/${pluginName}/generators.json`,
`e2e/tests/${pluginName}.spec.ts`
);

runCLI(`build create-${pluginName}-package`);
Expand Down
16 changes: 12 additions & 4 deletions packages/js/src/executors/verdaccio/verdaccio.impl.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { ExecutorContext, logger } from '@nx/devkit';
import { removeSync, existsSync } from 'fs-extra';
import { existsSync, rmSync } from 'fs-extra';
import { ChildProcess, execSync, fork } from 'child_process';
import * as detectPort from 'detect-port';
import { join } from 'path';
import { isRelativePath } from 'nx/src/utils/fileutils';

import { VerdaccioExecutorSchema } from './schema';

Expand All @@ -25,8 +26,14 @@ export async function verdaccioExecutor(
);
}

if (options.clear && options.storage && existsSync(options.storage)) {
removeSync(options.storage);
if (options.storage) {
options.storage = isRelativePath(options.storage)
? join(context.root, options.storage)
: options.storage;
if (options.clear && existsSync(options.storage)) {
console.log(`Clear local registry storage folder ${options.storage}`);
rmSync(options.storage, { recursive: true, force: true });
}
}

const cleanupFunctions =
Expand Down Expand Up @@ -94,7 +101,8 @@ function startVerdaccio(
childProcess.stderr.on('data', (data) => {
if (
data.includes('VerdaccioWarning') ||
data.includes('DeprecationWarning')
data.includes('DeprecationWarning') ||
data.includes('deprecated')
) {
process.stdout.write(data);
} else {
Expand Down
3 changes: 3 additions & 0 deletions packages/js/src/generators/setup-verdaccio/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import * as path from 'path';
import { SetupVerdaccioGeneratorSchema } from './schema';
import { verdaccioVersion } from '../../utils/versions';
import { addLocalRegistryScripts } from '../../utils/add-local-registry-scripts';

export async function setupVerdaccio(
tree: Tree,
Expand Down Expand Up @@ -50,6 +51,8 @@ export async function setupVerdaccio(
});
}

addLocalRegistryScripts(tree);

if (!options.skipFormat) {
await formatFiles(tree);
}
Expand Down
4 changes: 4 additions & 0 deletions packages/js/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@ export * from './utils/typescript/ast-utils';
export * from './utils/package-json';
export * from './utils/assets';
export * from './utils/package-json/update-package-json';
export * from './utils/add-local-registry-scripts';
export * from './utils/start-local-registry';
export * from './utils/stop-local-registry';
export { libraryGenerator } from './generators/library/library';
export { initGenerator } from './generators/init/init';
export { setupVerdaccio } from './generators/setup-verdaccio/generator';

// eslint-disable-next-line @typescript-eslint/no-restricted-imports
export {
Expand Down
53 changes: 53 additions & 0 deletions packages/js/src/utils/add-local-registry-scripts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { ProjectConfiguration, readJson, type Tree } from '@nx/devkit';

const startLocalRegistryScript = (localRegistryTarget: string) => `
/**
* This script starts a local registry for e2e testing purposes.
* It is meant to be called in jest's globalSetup.
*/
import startLocalRegistry from '@nx/js/src/utils/start-local-registry';
export default async () => {
// local registry target to run
const localRegistryTarget = '${localRegistryTarget}';
// storage folder for the local registry
const storage = './tmp/local-registry/storage';
await startLocalRegistry({ localRegistryTarget, storage });
};
`;

const stopLocalRegistryScript = `
/**
* This script stops the local registry for e2e testing purposes.
* It is meant to be called in jest's globalTeardown.
*/
import storyLocalRegistry from '@nx/js/src/utils/stop-local-registry';
export default () => {
storyLocalRegistry();
};
`;

export function addLocalRegistryScripts(tree: Tree) {
const startLocalRegistryPath = 'tools/scripts/start-local-registry.ts';
const stopLocalRegistryPath = 'tools/scripts/stop-local-registry.ts';

const projectConfiguration: ProjectConfiguration = readJson(
tree,
'project.json'
);
const localRegistryTarget = `${projectConfiguration.name}:local-registry`;
if (!tree.exists(startLocalRegistryPath)) {
tree.write(
startLocalRegistryPath,
startLocalRegistryScript(localRegistryTarget)
);
}
if (!tree.exists(stopLocalRegistryPath)) {
tree.write(stopLocalRegistryPath, stopLocalRegistryScript);
}

return { startLocalRegistryPath, stopLocalRegistryPath };
}
7 changes: 2 additions & 5 deletions packages/js/src/utils/minimal-publish-script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,13 @@ const publishScriptContent = `
import { execSync } from 'child_process';
import { readFileSync, writeFileSync } from 'fs';
import chalk from 'chalk';
import devkit from '@nx/devkit';
const { readCachedProjectGraph } = devkit;
function invariant(condition, message) {
if (!condition) {
console.error(chalk.bold.red(message));
console.error(message);
process.exit(1);
}
}
Expand Down Expand Up @@ -58,9 +57,7 @@ try {
json.version = version;
writeFileSync(\`package.json\`, JSON.stringify(json, null, 2));
} catch (e) {
console.error(
chalk.bold.red(\`Error reading package.json file from library build output.\`)
);
console.error(\`Error reading package.json file from library build output.\`);
}
// Execute "npm publish" to publish
Expand Down
58 changes: 58 additions & 0 deletions packages/js/src/utils/start-local-registry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { execSync, fork } from 'child_process';

/**
* This function is used to start a local registry for testing purposes.
* @param localRegistryTarget the target to run to start the local registry e.g. workspace:local-registry
* @param storage the storage location for the local registry
*/
export default async function startLocalRegistry({
localRegistryTarget,
storage,
}: {
localRegistryTarget: string;
storage?: string;
}) {
if (!localRegistryTarget) {
throw new Error(`localRegistryTarget is required`);
}
global.localRegistryProcess = await new Promise((resolve, reject) => {
const childProcess = fork(
require.resolve('nx'),
[
...`run ${localRegistryTarget} --location none --clear true`.split(' '),
...(storage ? [`--storage`, storage] : []),
],
{ stdio: 'pipe' }
);

const listener = (data) => {
if (data.toString().includes('http://localhost:')) {
global.port = parseInt(
data.toString().match(/localhost:(?<port>\d+)/)?.groups?.port
);
console.log('Local registry started on port ' + global.port);

const registry = `http://localhost:${global.port}`;
process.env.npm_config_registry = registry;
process.env.YARN_REGISTRY = registry;
execSync(
`npm config set //localhost:${global.port}/:_authToken "secretVerdaccioToken"`
);
console.log('Set npm and yarn config registry to ' + registry);

resolve(childProcess);
childProcess?.stdout?.off('data', listener);
}
};
childProcess?.stdout?.on('data', listener);
childProcess?.stderr?.pipe(process.stderr);
childProcess.on('error', (err) => {
console.log('local registry error', err);
reject(err);
});
childProcess.on('exit', (code) => {
console.log('local registry exit', code);
reject(code);
});
});
}
12 changes: 12 additions & 0 deletions packages/js/src/utils/stop-local-registry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { execSync } from 'child_process';

export default function stopLocalRegistry() {
if (global.localRegistryProcess) {
global.localRegistryProcess.kill();
}
if (global.localRegistryPort) {
execSync(
`npm config delete //localhost:${global.localRegistryPort}/:_authToken`
);
}
}
49 changes: 10 additions & 39 deletions packages/plugin/src/generators/create-package/create-package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ import {
GeneratorCallback,
runTasksInSerial,
joinPathFragments,
getProjects,
} from '@nx/devkit';
import { libraryGenerator as jsLibraryGenerator } from '@nx/js';
import { nxVersion } from 'nx/src/utils/versions';
import generatorGenerator from '../generator/generator';
import { CreatePackageSchema } from './schema';
import { NormalizedSchema, normalizeSchema } from './utils/normalize-schema';
import e2eProjectGenerator from '../e2e-project/e2e';
import { hasGenerator } from '../../utils/has-generator';

export async function createPackageGenerator(
Expand All @@ -39,6 +39,9 @@ export async function createPackageGenerator(
tasks.push(installTask);

await createCliPackage(host, options, pluginPackageName);
if (options.e2eTestRunner !== 'none') {
addE2eProject(host, options);
}

if (!options.skipFormat) {
await formatFiles(host);
Expand Down Expand Up @@ -149,57 +152,25 @@ async function createCliPackage(
* @param options
* @returns
*/
async function addE2eProject(host: Tree, options: NormalizedSchema) {
const pluginProjectConfiguration = readProjectConfiguration(
host,
options.project
);
const pluginOutputPath =
pluginProjectConfiguration.targets.build.options.outputPath;

const cliProjectConfiguration = readProjectConfiguration(
host,
options.projectName
);
const cliOutputPath =
cliProjectConfiguration.targets.build.options.outputPath;

const e2eTask = await e2eProjectGenerator(host, {
pluginName: options.projectName,
projectDirectory: options.projectDirectory,
pluginOutputPath,
npmPackageName: options.name,
skipFormat: true,
rootProject: false,
});
function addE2eProject(host: Tree, options: NormalizedSchema) {
const projects = getProjects(host);
const isRootProject = projects.get(options.project).root === '.';

const e2eProjectConfiguration = readProjectConfiguration(
host,
`${options.projectName}-e2e`
);
e2eProjectConfiguration.targets.e2e.dependsOn = ['^build'];
updateProjectConfiguration(
host,
e2eProjectConfiguration.name,
e2eProjectConfiguration
isRootProject ? 'e2e' : `${options.project}-e2e`
);

// delete the default e2e test file
host.delete(e2eProjectConfiguration.sourceRoot);

generateFiles(
host,
joinPathFragments(__dirname, './files/e2e'),
e2eProjectConfiguration.sourceRoot,
{
...options,
pluginOutputPath,
cliOutputPath,
pluginName: options.project,
cliName: options.name,
tmpl: '',
}
);

return e2eTask;
}

export default createPackageGenerator;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { getPackageManagerCommand } from '@nx/devkit';
import {
checkFilesExist,
removeTmpProject,
tmpFolder,
uniq,
} from '@nx/plugin/testing';
import { execSync } from 'child_process';
import { join } from 'path';

describe('<%= cliName %> e2e', () => {
let project: string;
beforeAll(async () => {
// publish plugin and cli
const pm = getPackageManagerCommand();
execSync(`${pm.exec} nx publish <%= pluginName %> --ver=1.0.0 --tag=e2e`, {
env: process.env,
});
execSync(`${pm.exec} nx publish <%= cliName %> --ver=1.0.0 --tag=e2e`, {
env: process.env,
});
project = uniq('<%= cliName %>');
execSync(`npx <%= cliName %>@1.0.0 ${project}`, {
cwd: tmpFolder(),
env: process.env,
});
}, 240_000);

afterAll(() => {
// Remove the generated project from the file system
removeTmpProject(project);
});

it('should create project using <%= cliName %>', () => {
expect(() =>
checkFilesExist(join(tmpFolder(), project, 'package.json'))
).not.toThrow();
});
});
Loading

0 comments on commit 2880d9a

Please sign in to comment.