feat(nx-plugin): add verdaccio to create package e2e (#17566)
This commit is contained in:
parent
93b123a326
commit
7baad04ea5
@ -57,11 +57,12 @@
|
|||||||
"default": "tsc",
|
"default": "tsc",
|
||||||
"description": "The compiler used by the build and test targets."
|
"description": "The compiler used by the build and test targets."
|
||||||
},
|
},
|
||||||
"e2eTestRunner": {
|
"e2eProject": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"description": "The name of the e2e project.",
|
||||||
"description": "Test runner to use for end to end (E2E) tests.",
|
"alias": "p",
|
||||||
"default": "jest"
|
"$default": { "$source": "projectName" },
|
||||||
|
"x-prompt": "What is the name of the e2e project?"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["name", "project"],
|
"required": ["name", "project"],
|
||||||
|
|||||||
@ -22,7 +22,7 @@ export default async function (globalConfig: Config.ConfigGlobals) {
|
|||||||
{ stdio: 'pipe' }
|
{ stdio: 'pipe' }
|
||||||
);
|
);
|
||||||
|
|
||||||
childProcess?.stdout?.on('data', (data) => {
|
const listener = (data) => {
|
||||||
if (data.toString().includes('http://localhost:')) {
|
if (data.toString().includes('http://localhost:')) {
|
||||||
const port = parseInt(
|
const port = parseInt(
|
||||||
data.toString().match(/localhost:(?<port>\d+)/)?.groups?.port
|
data.toString().match(/localhost:(?<port>\d+)/)?.groups?.port
|
||||||
@ -35,11 +35,12 @@ export default async function (globalConfig: Config.ConfigGlobals) {
|
|||||||
console.log('Set npm and yarn config registry to ' + registry);
|
console.log('Set npm and yarn config registry to ' + registry);
|
||||||
|
|
||||||
resolve(childProcess);
|
resolve(childProcess);
|
||||||
|
childProcess.stdout?.off('data', listener);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
childProcess?.stdout?.on('data', listener);
|
||||||
childProcess?.stderr?.on('data', (data) => {
|
childProcess?.stderr?.on('data', (data) => {
|
||||||
process.stderr.write(data);
|
process.stderr.write(data);
|
||||||
reject(data);
|
|
||||||
});
|
});
|
||||||
childProcess.on('error', (err) => {
|
childProcess.on('error', (err) => {
|
||||||
console.log('local registry error', err);
|
console.log('local registry error', err);
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import {
|
|||||||
uniq,
|
uniq,
|
||||||
runCreatePlugin,
|
runCreatePlugin,
|
||||||
cleanupProject,
|
cleanupProject,
|
||||||
tmpProjPath,
|
|
||||||
} from '@nx/e2e/utils';
|
} from '@nx/e2e/utils';
|
||||||
|
|
||||||
describe('create-nx-plugin', () => {
|
describe('create-nx-plugin', () => {
|
||||||
@ -64,7 +63,8 @@ describe('create-nx-plugin', () => {
|
|||||||
runCLI(`build ${pluginName}`);
|
runCLI(`build ${pluginName}`);
|
||||||
checkFilesExist(
|
checkFilesExist(
|
||||||
`dist/${pluginName}/package.json`,
|
`dist/${pluginName}/package.json`,
|
||||||
`dist/${pluginName}/generators.json`
|
`dist/${pluginName}/generators.json`,
|
||||||
|
`e2e/tests/${pluginName}.spec.ts`
|
||||||
);
|
);
|
||||||
|
|
||||||
runCLI(`build create-${pluginName}-package`);
|
runCLI(`build create-${pluginName}-package`);
|
||||||
|
|||||||
1
packages/js/plugins/jest/local-registry.ts
Normal file
1
packages/js/plugins/jest/local-registry.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from '../../src/plugins/jest/start-local-registry';
|
||||||
@ -1,8 +1,8 @@
|
|||||||
import { ExecutorContext, logger } from '@nx/devkit';
|
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 { ChildProcess, execSync, fork } from 'child_process';
|
||||||
import * as detectPort from 'detect-port';
|
import * as detectPort from 'detect-port';
|
||||||
import { join } from 'path';
|
import { join, resolve } from 'path';
|
||||||
|
|
||||||
import { VerdaccioExecutorSchema } from './schema';
|
import { VerdaccioExecutorSchema } from './schema';
|
||||||
|
|
||||||
@ -25,8 +25,12 @@ export async function verdaccioExecutor(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.clear && options.storage && existsSync(options.storage)) {
|
if (options.storage) {
|
||||||
removeSync(options.storage);
|
options.storage = resolve(context.root, options.storage);
|
||||||
|
if (options.clear && existsSync(options.storage)) {
|
||||||
|
rmSync(options.storage, { recursive: true, force: true });
|
||||||
|
console.log(`Cleared local registry storage folder ${options.storage}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const cleanupFunctions =
|
const cleanupFunctions =
|
||||||
@ -84,23 +88,10 @@ function startVerdaccio(
|
|||||||
? { VERDACCIO_STORAGE_PATH: options.storage }
|
? { VERDACCIO_STORAGE_PATH: options.storage }
|
||||||
: {}),
|
: {}),
|
||||||
},
|
},
|
||||||
stdio: ['inherit', 'pipe', 'pipe', 'ipc'],
|
stdio: 'inherit',
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
childProcess.stdout.on('data', (data) => {
|
|
||||||
process.stdout.write(data);
|
|
||||||
});
|
|
||||||
childProcess.stderr.on('data', (data) => {
|
|
||||||
if (
|
|
||||||
data.includes('VerdaccioWarning') ||
|
|
||||||
data.includes('DeprecationWarning')
|
|
||||||
) {
|
|
||||||
process.stdout.write(data);
|
|
||||||
} else {
|
|
||||||
reject(data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
childProcess.on('error', (err) => {
|
childProcess.on('error', (err) => {
|
||||||
reject(err);
|
reject(err);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -8,7 +8,7 @@ auth:
|
|||||||
# a list of other known repositories we can talk to
|
# a list of other known repositories we can talk to
|
||||||
uplinks:
|
uplinks:
|
||||||
npmjs:
|
npmjs:
|
||||||
url: https://registry.npmjs.org/
|
url: <%= npmUplinkRegistry %>
|
||||||
maxage: 60m
|
maxage: 60m
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|||||||
@ -13,13 +13,18 @@ import {
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { SetupVerdaccioGeneratorSchema } from './schema';
|
import { SetupVerdaccioGeneratorSchema } from './schema';
|
||||||
import { verdaccioVersion } from '../../utils/versions';
|
import { verdaccioVersion } from '../../utils/versions';
|
||||||
|
import { execSync } from 'child_process';
|
||||||
|
|
||||||
export async function setupVerdaccio(
|
export async function setupVerdaccio(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
options: SetupVerdaccioGeneratorSchema
|
options: SetupVerdaccioGeneratorSchema
|
||||||
) {
|
) {
|
||||||
if (!tree.exists('.verdaccio/config.yml')) {
|
if (!tree.exists('.verdaccio/config.yml')) {
|
||||||
generateFiles(tree, path.join(__dirname, 'files'), '.verdaccio', {});
|
generateFiles(tree, path.join(__dirname, 'files'), '.verdaccio', {
|
||||||
|
npmUplinkRegistry:
|
||||||
|
execSync('npm config get registry')?.toString()?.trim() ??
|
||||||
|
'https://registry.npmjs.org',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const verdaccioTarget: TargetConfiguration = {
|
const verdaccioTarget: TargetConfiguration = {
|
||||||
|
|||||||
75
packages/js/src/plugins/jest/start-local-registry.ts
Normal file
75
packages/js/src/plugins/jest/start-local-registry.ts
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
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
|
||||||
|
* @param verbose whether to log verbose output
|
||||||
|
*/
|
||||||
|
export function startLocalRegistry({
|
||||||
|
localRegistryTarget,
|
||||||
|
storage,
|
||||||
|
verbose,
|
||||||
|
}: {
|
||||||
|
localRegistryTarget: string;
|
||||||
|
storage?: string;
|
||||||
|
verbose?: boolean;
|
||||||
|
}) {
|
||||||
|
if (!localRegistryTarget) {
|
||||||
|
throw new Error(`localRegistryTarget is required`);
|
||||||
|
}
|
||||||
|
return new Promise<() => void>((resolve, reject) => {
|
||||||
|
const childProcess = fork(
|
||||||
|
require.resolve('nx'),
|
||||||
|
[
|
||||||
|
...`run ${localRegistryTarget} --location none --clear true`.split(' '),
|
||||||
|
...(storage ? [`--storage`, storage] : []),
|
||||||
|
],
|
||||||
|
{ stdio: 'pipe' }
|
||||||
|
);
|
||||||
|
|
||||||
|
const listener = (data) => {
|
||||||
|
if (verbose) {
|
||||||
|
process.stdout.write(data);
|
||||||
|
}
|
||||||
|
if (data.toString().includes('http://localhost:')) {
|
||||||
|
const port = parseInt(
|
||||||
|
data.toString().match(/localhost:(?<port>\d+)/)?.groups?.port
|
||||||
|
);
|
||||||
|
console.log('Local registry started on port ' + port);
|
||||||
|
|
||||||
|
const registry = `http://localhost:${port}`;
|
||||||
|
process.env.npm_config_registry = registry;
|
||||||
|
process.env.YARN_REGISTRY = registry;
|
||||||
|
execSync(
|
||||||
|
`npm config set //localhost:${port}/:_authToken "secretVerdaccioToken"`
|
||||||
|
);
|
||||||
|
console.log('Set npm and yarn config registry to ' + registry);
|
||||||
|
|
||||||
|
resolve(() => {
|
||||||
|
childProcess.kill();
|
||||||
|
execSync(`npm config delete //localhost:${port}/:_authToken`);
|
||||||
|
});
|
||||||
|
childProcess?.stdout?.off('data', listener);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
childProcess?.stdout?.on('data', listener);
|
||||||
|
childProcess?.stderr?.on('data', (data) => {
|
||||||
|
process.stderr.write(data);
|
||||||
|
});
|
||||||
|
childProcess.on('error', (err) => {
|
||||||
|
console.log('local registry error', err);
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
childProcess.on('exit', (code) => {
|
||||||
|
console.log('local registry exit', code);
|
||||||
|
if (code !== 0) {
|
||||||
|
reject(code);
|
||||||
|
} else {
|
||||||
|
resolve(() => {});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default startLocalRegistry;
|
||||||
64
packages/js/src/utils/add-local-registry-scripts.ts
Normal file
64
packages/js/src/utils/add-local-registry-scripts.ts
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
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/plugins/jest/local-registry';
|
||||||
|
import { execFileSync } from 'child_process';
|
||||||
|
|
||||||
|
export default async () => {
|
||||||
|
// local registry target to run
|
||||||
|
const localRegistryTarget = '${localRegistryTarget}';
|
||||||
|
// storage folder for the local registry
|
||||||
|
const storage = './tmp/local-registry/storage';
|
||||||
|
|
||||||
|
global.stopLocalRegistry = await startLocalRegistry({
|
||||||
|
localRegistryTarget,
|
||||||
|
storage,
|
||||||
|
verbose: false,
|
||||||
|
});
|
||||||
|
const nx = require.resolve('nx');
|
||||||
|
execFileSync(
|
||||||
|
nx,
|
||||||
|
['run-many', '--targets', 'publish', '--ver', '1.0.0', '--tag', 'e2e'],
|
||||||
|
{ env: process.env, stdio: 'inherit' }
|
||||||
|
);
|
||||||
|
};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const stopLocalRegistryScript = `
|
||||||
|
/**
|
||||||
|
* This script stops the local registry for e2e testing purposes.
|
||||||
|
* It is meant to be called in jest's globalTeardown.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
if (global.stopLocalRegistry) {
|
||||||
|
global.stopLocalRegistry();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
`;
|
||||||
|
|
||||||
|
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 };
|
||||||
|
}
|
||||||
@ -12,14 +12,13 @@ const publishScriptContent = `
|
|||||||
|
|
||||||
import { execSync } from 'child_process';
|
import { execSync } from 'child_process';
|
||||||
import { readFileSync, writeFileSync } from 'fs';
|
import { readFileSync, writeFileSync } from 'fs';
|
||||||
import chalk from 'chalk';
|
|
||||||
|
|
||||||
import devkit from '@nx/devkit';
|
import devkit from '@nx/devkit';
|
||||||
const { readCachedProjectGraph } = devkit;
|
const { readCachedProjectGraph } = devkit;
|
||||||
|
|
||||||
function invariant(condition, message) {
|
function invariant(condition, message) {
|
||||||
if (!condition) {
|
if (!condition) {
|
||||||
console.error(chalk.bold.red(message));
|
console.error(message);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,9 +57,7 @@ try {
|
|||||||
json.version = version;
|
json.version = version;
|
||||||
writeFileSync(\`package.json\`, JSON.stringify(json, null, 2));
|
writeFileSync(\`package.json\`, JSON.stringify(json, null, 2));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(
|
console.error(\`Error reading package.json file from library build output.\`);
|
||||||
chalk.bold.red(\`Error reading package.json file from library build output.\`)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute "npm publish" to publish
|
// Execute "npm publish" to publish
|
||||||
|
|||||||
@ -11,13 +11,13 @@ import {
|
|||||||
GeneratorCallback,
|
GeneratorCallback,
|
||||||
runTasksInSerial,
|
runTasksInSerial,
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
|
getProjects,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { libraryGenerator as jsLibraryGenerator } from '@nx/js';
|
import { libraryGenerator as jsLibraryGenerator } from '@nx/js';
|
||||||
import { nxVersion } from 'nx/src/utils/versions';
|
import { nxVersion } from 'nx/src/utils/versions';
|
||||||
import generatorGenerator from '../generator/generator';
|
import generatorGenerator from '../generator/generator';
|
||||||
import { CreatePackageSchema } from './schema';
|
import { CreatePackageSchema } from './schema';
|
||||||
import { NormalizedSchema, normalizeSchema } from './utils/normalize-schema';
|
import { NormalizedSchema, normalizeSchema } from './utils/normalize-schema';
|
||||||
import e2eProjectGenerator from '../e2e-project/e2e';
|
|
||||||
import { hasGenerator } from '../../utils/has-generator';
|
import { hasGenerator } from '../../utils/has-generator';
|
||||||
|
|
||||||
export async function createPackageGenerator(
|
export async function createPackageGenerator(
|
||||||
@ -39,6 +39,9 @@ export async function createPackageGenerator(
|
|||||||
tasks.push(installTask);
|
tasks.push(installTask);
|
||||||
|
|
||||||
await createCliPackage(host, options, pluginPackageName);
|
await createCliPackage(host, options, pluginPackageName);
|
||||||
|
if (options.e2eProject) {
|
||||||
|
addE2eProject(host, options);
|
||||||
|
}
|
||||||
|
|
||||||
if (!options.skipFormat) {
|
if (!options.skipFormat) {
|
||||||
await formatFiles(host);
|
await formatFiles(host);
|
||||||
@ -149,57 +152,22 @@ async function createCliPackage(
|
|||||||
* @param options
|
* @param options
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async function addE2eProject(host: Tree, options: NormalizedSchema) {
|
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,
|
|
||||||
});
|
|
||||||
|
|
||||||
const e2eProjectConfiguration = readProjectConfiguration(
|
const e2eProjectConfiguration = readProjectConfiguration(
|
||||||
host,
|
host,
|
||||||
`${options.projectName}-e2e`
|
options.e2eProject
|
||||||
);
|
);
|
||||||
e2eProjectConfiguration.targets.e2e.dependsOn = ['^build'];
|
|
||||||
updateProjectConfiguration(
|
|
||||||
host,
|
|
||||||
e2eProjectConfiguration.name,
|
|
||||||
e2eProjectConfiguration
|
|
||||||
);
|
|
||||||
|
|
||||||
// delete the default e2e test file
|
|
||||||
host.delete(e2eProjectConfiguration.sourceRoot);
|
|
||||||
|
|
||||||
generateFiles(
|
generateFiles(
|
||||||
host,
|
host,
|
||||||
joinPathFragments(__dirname, './files/e2e'),
|
joinPathFragments(__dirname, './files/e2e'),
|
||||||
e2eProjectConfiguration.sourceRoot,
|
e2eProjectConfiguration.sourceRoot,
|
||||||
{
|
{
|
||||||
...options,
|
pluginName: options.project,
|
||||||
pluginOutputPath,
|
cliName: options.name,
|
||||||
cliOutputPath,
|
|
||||||
tmpl: '',
|
tmpl: '',
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return e2eTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default createPackageGenerator;
|
export default createPackageGenerator;
|
||||||
|
|||||||
@ -0,0 +1,31 @@
|
|||||||
|
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 () => {
|
||||||
|
// create a workspace with cli
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -1,29 +0,0 @@
|
|||||||
import {
|
|
||||||
runCreatePackageCli,
|
|
||||||
removeTmpProject,
|
|
||||||
} from '@nx/plugin/testing';
|
|
||||||
|
|
||||||
describe('<%= name %> e2e', () => {
|
|
||||||
const project = '<%= name %>';
|
|
||||||
let createPackageResult;
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
|
||||||
// Create project using CLI command
|
|
||||||
createPackageResult = await runCreatePackageCli(
|
|
||||||
project,
|
|
||||||
{
|
|
||||||
pluginLibraryBuildPath: '<%= pluginOutputPath %>',
|
|
||||||
createPackageLibraryBuildPath: '<%= cliOutputPath %>',
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}, 240_000);
|
|
||||||
|
|
||||||
afterAll(() => {
|
|
||||||
// Remove the generated project from the file system
|
|
||||||
removeTmpProject(project);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create project using <%= name %>', () => {
|
|
||||||
expect(createPackageResult).toContain('Successfully created');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -13,5 +13,5 @@ export interface CreatePackageSchema {
|
|||||||
compiler: 'swc' | 'tsc';
|
compiler: 'swc' | 'tsc';
|
||||||
|
|
||||||
// options to create e2e project, passed to e2e project generator
|
// options to create e2e project, passed to e2e project generator
|
||||||
e2eTestRunner?: 'jest' | 'none';
|
e2eProject?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -59,11 +59,14 @@
|
|||||||
"default": "tsc",
|
"default": "tsc",
|
||||||
"description": "The compiler used by the build and test targets."
|
"description": "The compiler used by the build and test targets."
|
||||||
},
|
},
|
||||||
"e2eTestRunner": {
|
"e2eProject": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"description": "The name of the e2e project.",
|
||||||
"description": "Test runner to use for end to end (E2E) tests.",
|
"alias": "p",
|
||||||
"default": "jest"
|
"$default": {
|
||||||
|
"$source": "projectName"
|
||||||
|
},
|
||||||
|
"x-prompt": "What is the name of the e2e project?"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["name", "project"]
|
"required": ["name", "project"]
|
||||||
|
|||||||
@ -9,16 +9,19 @@ import {
|
|||||||
getWorkspaceLayout,
|
getWorkspaceLayout,
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
names,
|
names,
|
||||||
|
offsetFromRoot,
|
||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
runTasksInSerial,
|
runTasksInSerial,
|
||||||
updateProjectConfiguration,
|
updateProjectConfiguration,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { jestProjectGenerator } from '@nx/jest';
|
import { addPropertyToJestConfig, jestProjectGenerator } from '@nx/jest';
|
||||||
import { getRelativePathToRootTsConfig } from '@nx/js';
|
import { getRelativePathToRootTsConfig } from '@nx/js';
|
||||||
import * as path from 'path';
|
import { setupVerdaccio } from '@nx/js/src/generators/setup-verdaccio/generator';
|
||||||
|
import { addLocalRegistryScripts } from '@nx/js/src/utils/add-local-registry-scripts';
|
||||||
|
import { join } from 'path';
|
||||||
|
import { Linter, lintProjectGenerator } from '@nx/linter';
|
||||||
|
|
||||||
import type { Schema } from './schema';
|
import type { Schema } from './schema';
|
||||||
import { Linter, lintProjectGenerator } from '@nx/linter';
|
|
||||||
|
|
||||||
interface NormalizedSchema extends Schema {
|
interface NormalizedSchema extends Schema {
|
||||||
projectRoot: string;
|
projectRoot: string;
|
||||||
@ -63,7 +66,7 @@ function validatePlugin(host: Tree, pluginName: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addFiles(host: Tree, options: NormalizedSchema) {
|
function addFiles(host: Tree, options: NormalizedSchema) {
|
||||||
generateFiles(host, path.join(__dirname, './files'), options.projectRoot, {
|
generateFiles(host, join(__dirname, './files'), options.projectRoot, {
|
||||||
...options,
|
...options,
|
||||||
tmpl: '',
|
tmpl: '',
|
||||||
rootTsConfigPath: getRelativePathToRootTsConfig(host, options.projectRoot),
|
rootTsConfigPath: getRelativePathToRootTsConfig(host, options.projectRoot),
|
||||||
@ -87,6 +90,22 @@ async function addJest(host: Tree, options: NormalizedSchema) {
|
|||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { startLocalRegistryPath, stopLocalRegistryPath } =
|
||||||
|
addLocalRegistryScripts(host);
|
||||||
|
|
||||||
|
addPropertyToJestConfig(
|
||||||
|
host,
|
||||||
|
join(options.projectRoot, 'jest.config.ts'),
|
||||||
|
'globalSetup',
|
||||||
|
join(offsetFromRoot(options.projectRoot), startLocalRegistryPath)
|
||||||
|
);
|
||||||
|
addPropertyToJestConfig(
|
||||||
|
host,
|
||||||
|
join(options.projectRoot, 'jest.config.ts'),
|
||||||
|
'globalTeardown',
|
||||||
|
join(offsetFromRoot(options.projectRoot), stopLocalRegistryPath)
|
||||||
|
);
|
||||||
|
|
||||||
const project = readProjectConfiguration(host, options.projectName);
|
const project = readProjectConfiguration(host, options.projectName);
|
||||||
const testTarget = project.targets.test;
|
const testTarget = project.targets.test;
|
||||||
|
|
||||||
@ -133,6 +152,11 @@ export async function e2eProjectGenerator(host: Tree, schema: Schema) {
|
|||||||
validatePlugin(host, schema.pluginName);
|
validatePlugin(host, schema.pluginName);
|
||||||
const options = normalizeOptions(host, schema);
|
const options = normalizeOptions(host, schema);
|
||||||
addFiles(host, options);
|
addFiles(host, options);
|
||||||
|
tasks.push(
|
||||||
|
await setupVerdaccio(host, {
|
||||||
|
skipFormat: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
tasks.push(await addJest(host, options));
|
tasks.push(await addJest(host, options));
|
||||||
|
|
||||||
if (options.linter !== Linter.None) {
|
if (options.linter !== Linter.None) {
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
checkFilesExist,
|
checkFilesExist,
|
||||||
ensureNxProject,
|
ensureNxProject,
|
||||||
readJson,
|
|
||||||
runNxCommandAsync,
|
runNxCommandAsync,
|
||||||
runNxCommand,
|
runNxCommand,
|
||||||
} from '@nx/plugin/testing';
|
} from '@nx/plugin/testing';
|
||||||
|
|||||||
@ -1,72 +0,0 @@
|
|||||||
import { workspaceRoot } from '@nx/devkit';
|
|
||||||
import { tmpFolder } from './paths';
|
|
||||||
import { fork } from 'child_process';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function is used to run the create package CLI command.
|
|
||||||
* It builds the plugin library and the create package library and run the create package command with for the plugin library.
|
|
||||||
* It needs to be ran inside an Nx project. It would assume that an Nx project already exists.
|
|
||||||
* @param projectToBeCreated project name to be created using the cli
|
|
||||||
* @param pluginLibraryBuildPath e.g. dist/packages/my-plugin
|
|
||||||
* @param createPackageLibraryBuildPath e.g. dist/packages/create-my-plugin-package
|
|
||||||
* @param extraArguments extra arguments to be passed to the create package command
|
|
||||||
* @param verbose if true, NX_VERBOSE_LOGGING will be set to true
|
|
||||||
* @returns results for the create package command
|
|
||||||
*/
|
|
||||||
export function runCreatePackageCli(
|
|
||||||
projectToBeCreated: string,
|
|
||||||
{
|
|
||||||
pluginLibraryBuildPath,
|
|
||||||
createPackageLibraryBuildPath,
|
|
||||||
extraArguments,
|
|
||||||
verbose,
|
|
||||||
}: {
|
|
||||||
pluginLibraryBuildPath: string;
|
|
||||||
createPackageLibraryBuildPath: string;
|
|
||||||
extraArguments?: string[];
|
|
||||||
verbose?: boolean;
|
|
||||||
}
|
|
||||||
): Promise<string> {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const childProcess = fork(
|
|
||||||
`${workspaceRoot}/${createPackageLibraryBuildPath}/bin/index.js`,
|
|
||||||
[projectToBeCreated, ...(extraArguments || [])],
|
|
||||||
{
|
|
||||||
stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
|
|
||||||
env: {
|
|
||||||
...process.env,
|
|
||||||
[`NX_E2E_PRESET_VERSION`]: `file:${workspaceRoot}/${pluginLibraryBuildPath}`,
|
|
||||||
// only add NX_VERBOSE_LOGGING if verbose is true
|
|
||||||
...(verbose && { NX_VERBOSE_LOGGING: 'true' }),
|
|
||||||
},
|
|
||||||
cwd: tmpFolder(),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Ensure the child process is killed when the parent exits
|
|
||||||
process.on('exit', () => childProcess.kill());
|
|
||||||
process.on('SIGTERM', () => childProcess.kill());
|
|
||||||
|
|
||||||
let allMessages = '';
|
|
||||||
childProcess.on('message', (message) => {
|
|
||||||
allMessages += message;
|
|
||||||
});
|
|
||||||
childProcess.stdout.on('data', (data) => {
|
|
||||||
allMessages += data;
|
|
||||||
});
|
|
||||||
childProcess.on('error', (error) => {
|
|
||||||
reject(error);
|
|
||||||
});
|
|
||||||
childProcess.on('exit', (code) => {
|
|
||||||
if (code === 0) {
|
|
||||||
resolve(allMessages);
|
|
||||||
} else {
|
|
||||||
reject(allMessages);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function generatedPackagePath(projectToBeCreated: string) {
|
|
||||||
return `${tmpFolder()}/${projectToBeCreated}`;
|
|
||||||
}
|
|
||||||
@ -1,6 +1,5 @@
|
|||||||
export * from './async-commands';
|
export * from './async-commands';
|
||||||
export * from './commands';
|
export * from './commands';
|
||||||
export * from './create-package-cli';
|
|
||||||
export * from './paths';
|
export * from './paths';
|
||||||
export * from './nx-project';
|
export * from './nx-project';
|
||||||
export * from './utils';
|
export * from './utils';
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user