diff --git a/docs/core/Generators/import-projects.md b/docs/core/Generators/import-projects.md
deleted file mode 100644
index ba656886..00000000
--- a/docs/core/Generators/import-projects.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# @nx-dotnet/core:import-projects
-
-## Import Projects
-
-Import existing .NET projects in C#, VB, or F# that are in your workspace's apps or libs directories. Simply move the projects into these folders, and then run `nx g @nx-dotnet/core:import-projects` to move them into Nx. Projects inside the apps directory will include a serve target, while projects inside libs will only contain build + lint targets.
diff --git a/docs/core/index.md b/docs/core/index.md
index 9ddf87c4..cd23bd7a 100644
--- a/docs/core/index.md
+++ b/docs/core/index.md
@@ -109,10 +109,6 @@ Restores NuGet packages and .NET tools used by the workspace
Generate a .NET test project for an existing application or library
-### [import-projects](./Generators/import-projects.md)
-
-Import existing projects into your Nx workspace
-
### [add-swagger-target](./Generators/add-swagger-target.md)
Add a swagger target to a webapi based project to extract swagger.json into a newly generated library project
diff --git a/docs/index.md b/docs/index.md
index 154a4b96..560deaf2 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -8,7 +8,7 @@ slug: /
## [@nx-dotnet/core](./core)
- 7 Executors
-- 11 Generators
+- 10 Generators
## [@nx-dotnet/nx-ghpages](./nx-ghpages)
diff --git a/nx.json b/nx.json
index 1437d088..65ba7fe3 100644
--- a/nx.json
+++ b/nx.json
@@ -3,10 +3,6 @@
"affected": {
"defaultBase": "master"
},
- "workspaceLayout": {
- "appsDir": "",
- "libsDir": ""
- },
"plugins": [
{
"plugin": "@nx-dotnet/core",
diff --git a/package.json b/package.json
index 01a7ef66..5d8b2cd8 100644
--- a/package.json
+++ b/package.json
@@ -13,7 +13,8 @@
"documentation:check": "ts-node ./tools/scripts/hooks/documentation.check.ts",
"documentation": "nx g @nx-dotnet/nxdoc:generate-docs",
"publish-dev": "ts-node tools/scripts/publish-dev",
- "sandbox": "ts-node ./tools/scripts/sandbox.ts"
+ "sandbox": "ts-node ./tools/scripts/sandbox.ts",
+ "local-registry": "ts-node ./tools/scripts/local-registry/setup.ts"
},
"private": false,
"dependencies": {
diff --git a/packages/core/generators.json b/packages/core/generators.json
index 312caa90..fa07ffda 100644
--- a/packages/core/generators.json
+++ b/packages/core/generators.json
@@ -50,11 +50,6 @@
"description": "Generate a .NET test project for an existing application or library",
"x-type": "library"
},
- "import-projects": {
- "factory": "./src/generators/import-projects/generator",
- "schema": "./src/generators/import-projects/schema.json",
- "description": "Import existing projects into your Nx workspace"
- },
"add-swagger-target": {
"factory": "./src/generators/add-swagger-target/add-swagger-target",
"schema": "./src/generators/add-swagger-target/schema.json",
diff --git a/packages/core/src/generators/import-projects/generator.spec.ts b/packages/core/src/generators/import-projects/generator.spec.ts
deleted file mode 100644
index aec59e45..00000000
--- a/packages/core/src/generators/import-projects/generator.spec.ts
+++ /dev/null
@@ -1,128 +0,0 @@
-import { getProjects, readProjectConfiguration, Tree } from '@nx/devkit';
-import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
-
-import * as fs from 'fs';
-
-import { DotNetClient, mockDotnetFactory } from '@nx-dotnet/dotnet';
-import * as utils from '@nx-dotnet/utils';
-
-import * as mockedInitGenerator from '../init/generator';
-import generator from './generator';
-
-jest.mock('@nx-dotnet/utils', () => ({
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- ...(jest.requireActual('@nx-dotnet/utils') as any),
- glob: jest.fn(),
- findProjectFileInPath: jest.fn(),
- resolve: (m: string) => m,
-}));
-
-const MOCK_API_PROJECT = `
-
-
- net5.0
- MyTestApi
-
-`;
-
-const MOCK_TEST_PROJECT = `
-
-
- net5.0
- MyTestApi.Test
-
-
-
-
-`;
-
-jest.mock('../init/generator', () => ({
- initGenerator: jest.fn(() => {
- return Promise.resolve(jest.fn(() => Promise.resolve()));
- }),
-}));
-
-describe('import-projects generator', () => {
- let tree: Tree;
- let dotnetClient: DotNetClient;
-
- beforeEach(() => {
- tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
- dotnetClient = new DotNetClient(mockDotnetFactory());
- });
-
- afterEach(() => {
- jest.clearAllMocks();
- });
-
- it('should run successfully if no new projects are found', async () => {
- jest.spyOn(utils, 'glob').mockResolvedValue([]);
- const promise = generator(tree, null, dotnetClient);
- const oldProjects = getProjects(tree);
- await expect(promise).resolves.not.toThrow();
- const newProjects = getProjects(tree);
- expect(oldProjects).toEqual(newProjects);
- });
-
- it('should run successfully if new projects are found', async () => {
- jest
- .spyOn(utils, 'glob')
- .mockImplementation((x) =>
- Promise.resolve(
- x.startsWith('apps') ? ['apps/my-api/my-api.csproj'] : [],
- ),
- );
- jest
- .spyOn(utils, 'findProjectFileInPath')
- .mockImplementation((x) =>
- x.startsWith('apps')
- ? Promise.resolve('apps/my-api/my-api.csproj')
- : Promise.reject(new Error()),
- );
- jest.spyOn(fs, 'readFileSync').mockReturnValue(MOCK_TEST_PROJECT);
- jest.spyOn(fs, 'writeFileSync').mockImplementation(() => null);
- tree.write('apps/my-api/my-api.csproj', MOCK_API_PROJECT);
- const promise = generator(tree, null, dotnetClient);
- await expect(promise).resolves.not.toThrow();
- expect(readProjectConfiguration(tree, 'my-test-api')).toBeDefined();
- });
-
- it('should run add test target if test projects are found', async () => {
- jest
- .spyOn(utils, 'glob')
- .mockImplementation((x) =>
- Promise.resolve(
- x.startsWith('apps') ? ['apps/my-api-test/my-api-test.csproj'] : [],
- ),
- );
- jest
- .spyOn(utils, 'findProjectFileInPath')
- .mockImplementation((x) =>
- x.startsWith('apps')
- ? Promise.resolve('apps/my-api/my-api-test.csproj')
- : Promise.reject(new Error()),
- );
- jest.spyOn(fs, 'readFileSync').mockReturnValue(MOCK_TEST_PROJECT);
- jest.spyOn(fs, 'writeFileSync').mockImplementation(() => null);
- tree.write('apps/my-api-test/my-api-test.csproj', MOCK_TEST_PROJECT);
- const promise = generator(tree, null, dotnetClient);
- await expect(promise).resolves.not.toThrow();
- expect(readProjectConfiguration(tree, 'my-test-api-test')).toBeDefined();
- expect(
- readProjectConfiguration(tree, 'my-test-api-test').targets?.test,
- ).toBeDefined();
- expect(
- readProjectConfiguration(tree, 'my-test-api-test').targets?.serve,
- ).not.toBeDefined();
- });
-
- it('should call init generator', async () => {
- const initGenerator = (
- mockedInitGenerator as jest.Mocked
- ).initGenerator;
-
- jest.spyOn(utils, 'glob').mockResolvedValue([]);
- await generator(tree, null, dotnetClient);
- expect(initGenerator).toHaveBeenCalledWith(tree, null, dotnetClient);
- });
-});
diff --git a/packages/core/src/generators/import-projects/generator.ts b/packages/core/src/generators/import-projects/generator.ts
deleted file mode 100644
index 066d5988..00000000
--- a/packages/core/src/generators/import-projects/generator.ts
+++ /dev/null
@@ -1,131 +0,0 @@
-import {
- addProjectConfiguration,
- formatFiles,
- getProjects,
- getWorkspaceLayout,
- joinPathFragments,
- logger,
- names,
- ProjectConfiguration,
- TargetConfiguration,
- Tree,
-} from '@nx/devkit';
-
-import { basename, dirname } from 'path';
-import { XmlDocument } from 'xmldoc';
-
-import { DotNetClient, dotnetFactory } from '@nx-dotnet/dotnet';
-import { glob, iterateChildrenByPath, projPattern } from '@nx-dotnet/utils';
-
-import {
- GetBuildExecutorConfiguration,
- GetLintExecutorConfiguration,
- GetServeExecutorConfig,
- GetTestExecutorConfig,
-} from '../../models';
-import { initGenerator } from '../init/generator';
-
-export default async function (
- host: Tree,
- options: null, // The second option is provided at runtime by Nx for options passed in to the generator.
- dotnetClient = new DotNetClient(dotnetFactory()),
-) {
- const installTask = await initGenerator(host, null, dotnetClient);
-
- const projectFiles = await getProjectFilesInWorkspace(host);
- const existingProjectJsonDirectories = getDirectoriesWithProjectJson(host);
- for (const projectFile of projectFiles.newLibs) {
- if (
- !existingProjectJsonDirectories.some((x) =>
- projectFile.startsWith(x + '/'),
- )
- ) {
- await addNewDotnetProject(host, projectFile, false);
- logger.log('Found new library', projectFile);
- }
- }
- for (const projectFile of projectFiles.newApps) {
- if (
- !existingProjectJsonDirectories.some((x) =>
- projectFile.startsWith(x + '/'),
- )
- ) {
- await addNewDotnetProject(host, projectFile, true);
- logger.log('Found new application', projectFile);
- }
- }
- return async () => {
- await installTask();
- await formatFiles(host);
- };
-}
-
-async function addNewDotnetProject(
- host: Tree,
- projectFile: string,
- app: boolean,
-) {
- const rootNamespace = readRootNamespace(host, projectFile);
- const projectRoot = dirname(projectFile);
- const projectName = rootNamespace
- ? names(rootNamespace).fileName.replace(/\./g, '-')
- : names(basename(projectRoot)).fileName;
- const configuration: ProjectConfiguration & {
- targets: Record;
- } = {
- root: projectRoot,
- targets: {
- build: GetBuildExecutorConfiguration(projectRoot),
- lint: GetLintExecutorConfiguration(),
- },
- projectType: app ? 'application' : 'library',
- };
- const testProject = await checkIfTestProject(host, projectFile);
- if (app && !testProject) {
- configuration.targets.serve = GetServeExecutorConfig();
- }
- if (testProject) {
- configuration.targets.test = GetTestExecutorConfig();
- }
- addProjectConfiguration(host, projectName, configuration);
-}
-
-async function getProjectFilesInWorkspace(host: Tree) {
- const { appsDir, libsDir } = getWorkspaceLayout(host);
- const newProjects = {
- newLibs: await glob(projPattern(libsDir)),
- newApps: [] as string[],
- };
- if (libsDir !== appsDir) {
- newProjects.newApps = await glob(projPattern(appsDir));
- }
- return newProjects;
-}
-
-function readRootNamespace(host: Tree, path: string): string | undefined {
- const xml = new XmlDocument(host.read(path)?.toString() as string);
- return xml.valueWithPath('PropertyGroup.RootNamespace');
-}
-
-async function checkIfTestProject(host: Tree, path: string): Promise {
- const xml = new XmlDocument(host.read(path)?.toString() as string);
- let isTestProject = false;
- await iterateChildrenByPath(xml, 'ItemGroup.PackageReference', (el) => {
- const pkg = el.attr['Include'];
- if (pkg === 'Microsoft.NET.Test.Sdk') {
- isTestProject = true;
- }
- });
- return isTestProject;
-}
-
-function getDirectoriesWithProjectJson(host: Tree) {
- const nxProjects = getProjects(host);
- const collected: string[] = [];
- for (const proj of nxProjects.values()) {
- if (host.exists(joinPathFragments(proj.root, 'project.json'))) {
- collected.push(proj.root);
- }
- }
- return collected;
-}
diff --git a/packages/core/src/generators/import-projects/schema.json b/packages/core/src/generators/import-projects/schema.json
deleted file mode 100644
index 5179be83..00000000
--- a/packages/core/src/generators/import-projects/schema.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "$schema": "http://json-schema.org/schema",
- "id": "@nx-dotnet/core:import-projects",
- "title": "Import Projects",
- "description": "Import existing .NET projects in C#, VB, or F# that are in your workspace's apps or libs directories. Simply move the projects into these folders, and then run `nx g @nx-dotnet/core:import-projects` to move them into Nx. Projects inside the apps directory will include a serve target, while projects inside libs will only contain build + lint targets.",
- "type": "object",
- "properties": {}
-}
diff --git a/packages/core/src/generators/move/generator.spec.ts b/packages/core/src/generators/move/generator.spec.ts
index 8eda7c17..b59bf3ea 100644
--- a/packages/core/src/generators/move/generator.spec.ts
+++ b/packages/core/src/generators/move/generator.spec.ts
@@ -7,12 +7,23 @@ import {
names,
offsetFromRoot,
ProjectConfiguration,
+ ProjectGraph,
} from '@nx/devkit';
import { uniq } from '@nx/plugin/testing';
import generator from './generator';
import { basename } from 'path';
+let graph: ProjectGraph = {
+ dependencies: {},
+ nodes: {},
+};
+
+jest
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
+ .spyOn(require('@nx/devkit'), 'createProjectGraphAsync')
+ .mockImplementation(() => Promise.resolve(graph));
+
describe('move generator', () => {
let tree: Tree;
@@ -20,6 +31,10 @@ describe('move generator', () => {
tree = createTreeWithEmptyWorkspace({
layout: 'apps-libs',
});
+ graph = {
+ dependencies: {},
+ nodes: {},
+ };
});
it('should move simple projects successfully', async () => {
@@ -107,12 +122,22 @@ describe('move generator', () => {
new RegExp(`^${joinPathFragments(relativeToRoot, 'node_modules')}.*`),
);
});
+
+ it('should work for inferred projects', async () => {
+ const { project, root: source } = makeSimpleProject(tree, 'app', 'a/b');
+ tree.delete(joinPathFragments(source, 'project.json'));
+ const destination = joinPathFragments('a', 'b', 'c', uniq('app'));
+ await generator(tree, { projectName: project, destination });
+ expect(
+ tree.exists(joinPathFragments(destination, 'project.json')),
+ ).toBeFalsy();
+ });
});
function makeSimpleProject(tree: Tree, type: 'app' | 'lib', path?: string) {
const project = uniq(type);
const root = joinPathFragments(`${type}s`, path ?? '', project);
- addProjectConfiguration(tree, project, {
+ const configuration: ProjectConfiguration = {
root,
sourceRoot: joinPathFragments(root, 'src'),
projectType: type === 'app' ? 'application' : 'library',
@@ -122,7 +147,14 @@ function makeSimpleProject(tree: Tree, type: 'app' | 'lib', path?: string) {
outputs: [`{workspaceRoot}/dist/${root}`],
},
},
- });
+ };
+ addProjectConfiguration(tree, project, configuration);
+ graph.nodes[project] = {
+ data: configuration,
+ name: project,
+ type,
+ };
+
tree.write(joinPathFragments(root, 'readme.md'), 'contents');
return { project, root };
}
diff --git a/packages/core/src/generators/move/generator.ts b/packages/core/src/generators/move/generator.ts
index 0df10d05..c7ceaed5 100644
--- a/packages/core/src/generators/move/generator.ts
+++ b/packages/core/src/generators/move/generator.ts
@@ -1,5 +1,6 @@
import {
addProjectConfiguration,
+ createProjectGraphAsync,
formatFiles,
getWorkspaceLayout,
joinPathFragments,
@@ -22,12 +23,22 @@ type NormalizedSchema = {
destinationProject: string;
};
-function normalizeOptions(
+async function getCurrentProjectConfiguration(
+ projectName: string,
+): Promise {
+ return await (
+ await createProjectGraphAsync()
+ ).nodes[projectName].data;
+}
+
+async function normalizeOptions(
tree: Tree,
options: MoveGeneratorSchema,
-): NormalizedSchema {
+): Promise {
const { appsDir, libsDir } = getWorkspaceLayout(tree);
- const currentRoot = readProjectConfiguration(tree, options.projectName).root;
+ const { root: currentRoot } = await getCurrentProjectConfiguration(
+ options.projectName,
+ );
let destinationRoot = options.destination;
if (!options.relativeToRoot) {
if (currentRoot.startsWith(appsDir)) {
@@ -55,28 +66,45 @@ function normalizeOptions(
}
export default async function (tree: Tree, options: MoveGeneratorSchema) {
- const normalizedOptions = normalizeOptions(tree, options);
- const config = readProjectConfiguration(
- tree,
- normalizedOptions.currentProject,
- );
- config.root = normalizedOptions.destinationRoot;
- config.name = normalizedOptions.destinationProject;
- removeProjectConfiguration(tree, normalizedOptions.currentProject);
+ const normalizedOptions = await normalizeOptions(tree, options);
+ const writeNewProjectJson = updateProjectJson(tree, normalizedOptions);
+
renameDirectory(
tree,
normalizedOptions.currentRoot,
normalizedOptions.destinationRoot,
);
- addProjectConfiguration(
- tree,
- options.projectName,
- transformConfiguration(tree, config, normalizedOptions),
- );
+
+ writeNewProjectJson();
+
updateXmlReferences(tree, normalizedOptions);
await formatFiles(tree);
}
+function updateProjectJson(tree: Tree, normalizedOptions: NormalizedSchema) {
+ try {
+ const config = readProjectConfiguration(
+ tree,
+ normalizedOptions.currentProject,
+ );
+ config.root = normalizedOptions.destinationRoot;
+ config.name = normalizedOptions.destinationProject;
+ removeProjectConfiguration(tree, normalizedOptions.currentProject);
+ return () => {
+ addProjectConfiguration(
+ tree,
+ normalizedOptions.destinationProject,
+ transformConfiguration(tree, config, normalizedOptions),
+ );
+ };
+ } catch {
+ // There was no project.json, so dont add one.
+ return () => {
+ /* its fine */
+ };
+ }
+}
+
function transformConfiguration(
tree: Tree,
config: ProjectConfiguration,
diff --git a/packages/core/src/generators/utils/generate-project.ts b/packages/core/src/generators/utils/generate-project.ts
index fbd6ab03..2034fe68 100644
--- a/packages/core/src/generators/utils/generate-project.ts
+++ b/packages/core/src/generators/utils/generate-project.ts
@@ -6,7 +6,6 @@ import {
joinPathFragments,
names,
normalizePath,
- ProjectConfiguration,
ProjectType,
Tree,
} from '@nx/devkit';
@@ -20,7 +19,7 @@ import {
dotnetNewOptions,
KnownDotnetTemplates,
} from '@nx-dotnet/dotnet';
-import { isDryRun, resolve } from '@nx-dotnet/utils';
+import { isDryRun, isNxCrystalEnabled, resolve } from '@nx-dotnet/utils';
import {
GetBuildExecutorConfiguration,
@@ -190,25 +189,21 @@ export async function GenerateProject(
projectType,
);
- const projectConfiguration: ProjectConfiguration = {
- root: normalizedOptions.projectRoot,
- projectType: projectType,
- sourceRoot: `${normalizedOptions.projectRoot}`,
- targets: {
- build: GetBuildExecutorConfiguration(normalizedOptions.projectRoot),
- ...(projectType === 'application'
- ? { serve: GetServeExecutorConfig() }
- : {}),
- lint: GetLintExecutorConfiguration(),
- },
- tags: normalizedOptions.parsedTags,
- };
-
- addProjectConfiguration(
- host,
- normalizedOptions.projectName,
- projectConfiguration,
- );
+ if (!isNxCrystalEnabled()) {
+ addProjectConfiguration(host, normalizedOptions.projectName, {
+ root: normalizedOptions.projectRoot,
+ projectType: projectType,
+ sourceRoot: `${normalizedOptions.projectRoot}`,
+ targets: {
+ build: GetBuildExecutorConfiguration(normalizedOptions.projectRoot),
+ ...(projectType === 'application'
+ ? { serve: GetServeExecutorConfig() }
+ : {}),
+ lint: GetLintExecutorConfiguration(),
+ },
+ tags: normalizedOptions.parsedTags,
+ });
+ }
const newParams: dotnetNewOptions = {
language: normalizedOptions.language,
@@ -232,7 +227,7 @@ export async function GenerateProject(
if (!isDryRun()) {
addToSolutionFile(
host,
- projectConfiguration.root,
+ normalizedOptions.projectRoot,
dotnetClient,
normalizedOptions.solutionFile,
);
diff --git a/packages/core/src/generators/utils/generate-test-project.ts b/packages/core/src/generators/utils/generate-test-project.ts
index bd5d5b45..4d5339e9 100644
--- a/packages/core/src/generators/utils/generate-test-project.ts
+++ b/packages/core/src/generators/utils/generate-test-project.ts
@@ -1,7 +1,11 @@
import { addProjectConfiguration, names, Tree } from '@nx/devkit';
import { DotNetClient, dotnetNewOptions } from '@nx-dotnet/dotnet';
-import { findProjectFileInPath, isDryRun } from '@nx-dotnet/utils';
+import {
+ findProjectFileInPath,
+ isDryRun,
+ isNxCrystalEnabled,
+} from '@nx-dotnet/utils';
import {
GetBuildExecutorConfiguration,
@@ -42,17 +46,19 @@ export async function GenerateTestProject(
const testRoot = schema.projectRoot + separator + suffix;
const testProjectName = schema.projectName + separator + suffix;
- addProjectConfiguration(host, testProjectName, {
- root: testRoot,
- projectType: schema.projectType,
- sourceRoot: `${testRoot}`,
- targets: {
- build: GetBuildExecutorConfiguration(testRoot),
- test: GetTestExecutorConfig(),
- lint: GetLintExecutorConfiguration(),
- },
- tags: schema.parsedTags,
- });
+ if (!isNxCrystalEnabled()) {
+ addProjectConfiguration(host, testProjectName, {
+ root: testRoot,
+ projectType: schema.projectType,
+ sourceRoot: `${testRoot}`,
+ targets: {
+ build: GetBuildExecutorConfiguration(testRoot),
+ test: GetTestExecutorConfig(),
+ lint: GetLintExecutorConfiguration(),
+ },
+ tags: schema.parsedTags,
+ });
+ }
const newParams: dotnetNewOptions = {
language: schema.language,
diff --git a/packages/core/src/graph/__snapshots__/create-nodes.spec.ts.snap b/packages/core/src/graph/__snapshots__/create-nodes.spec.ts.snap
index 2a62e6e8..46db933c 100644
--- a/packages/core/src/graph/__snapshots__/create-nodes.spec.ts.snap
+++ b/packages/core/src/graph/__snapshots__/create-nodes.spec.ts.snap
@@ -2,11 +2,15 @@
exports[`infer-project should generate build, lint, serve targets for projects 1`] = `
{
+ "cache": true,
"configurations": {
"production": {
"configuration": "Release",
},
},
+ "dependsOn": [
+ "^build",
+ ],
"executor": "@nx-dotnet/core:build",
"options": {
"configuration": "Debug",
@@ -15,13 +19,19 @@ exports[`infer-project should generate build, lint, serve targets for projects 1
"outputs": [
"{workspaceRoot}/dist/libs/api",
"{workspaceRoot}/dist/intermediates/libs/api",
+ "{projectRoot}/bin",
+ "{projectRoot}/obj",
],
}
`;
exports[`infer-project should generate build, lint, serve targets for projects 2`] = `
{
+ "cache": true,
"executor": "@nx-dotnet/core:format",
+ "inputs": [
+ "{projectRoot}/**/*.{cs,fs,vb}",
+ ],
}
`;
@@ -41,8 +51,13 @@ exports[`infer-project should generate build, lint, serve targets for projects 3
exports[`infer-project should generate test target for test projects 1`] = `
{
+ "cache": true,
+ "dependsOn": [
+ "build",
+ ],
"executor": "@nx-dotnet/core:test",
"options": {
+ "noBuild": true,
"testProject": undefined,
},
}
diff --git a/packages/core/src/graph/create-dependencies.ts b/packages/core/src/graph/create-dependencies.ts
index 4b338f40..796a259c 100644
--- a/packages/core/src/graph/create-dependencies.ts
+++ b/packages/core/src/graph/create-dependencies.ts
@@ -18,19 +18,16 @@ import {
// It used to only consist of the context, but now it also includes the options.
// The options were inserted as the first parameter, and the context was moved to the second.
// The following types are used to support both signatures.
-type CreateDependenciesV16 = (
- ctx: Parameters[1],
- _: undefined,
-) => ReturnType;
-
-type CreateDependenciesCompat = (
- p0:
- | Parameters>[0]
- | Parameters[0],
- p1:
- | Parameters>[1]
- | Parameters[1],
-) => ReturnType>;
+type CreateDependenciesCompat = {
+ (
+ ctx: CreateDependenciesContext,
+ _: undefined,
+ ): ReturnType>;
+ (
+ opts: Parameters>[0],
+ ctx: CreateDependenciesContext,
+ ): ReturnType>;
+};
export const createDependencies: CreateDependenciesCompat = (
ctxOrOpts: CreateDependenciesContext | NxDotnetConfig | undefined,
diff --git a/packages/core/src/graph/create-nodes.ts b/packages/core/src/graph/create-nodes.ts
index 6e526b3b..d1eec5ff 100644
--- a/packages/core/src/graph/create-nodes.ts
+++ b/packages/core/src/graph/create-nodes.ts
@@ -28,28 +28,57 @@ export const registerProjectTargets = (
) => {
const targets: Record = {};
const { inferredTargets } = opts;
- if (inferredTargets !== false) {
- const projectFileContents = readFileSync(
- resolve(workspaceRoot, projectFile),
- 'utf8',
- );
- if (
- projectFileContents.includes('Microsoft.NET.Test.Sdk') &&
- inferredTargets.test
- ) {
- targets[inferredTargets.test] = GetTestExecutorConfig();
- }
- if (inferredTargets.build) {
- targets[inferredTargets.build] = GetBuildExecutorConfiguration(
- dirname(projectFile),
- );
- }
- if (inferredTargets.lint) {
- targets[inferredTargets.lint] = GetLintExecutorConfiguration();
- }
- if (inferredTargets.serve) {
- targets[inferredTargets.serve] = GetServeExecutorConfig();
- }
+ if (inferredTargets === false) {
+ return {};
+ }
+
+ const projectFileContents = readFileSync(
+ resolve(workspaceRoot, projectFile),
+ 'utf8',
+ );
+
+ if (
+ projectFileContents.includes('Microsoft.NET.Test.Sdk') &&
+ inferredTargets.test
+ ) {
+ const { targetName, ...extraOptions } =
+ typeof inferredTargets.test === 'string'
+ ? { targetName: inferredTargets.test }
+ : inferredTargets.test;
+ targets[targetName] = {
+ ...GetTestExecutorConfig(),
+ ...extraOptions,
+ };
+ }
+ if (inferredTargets.build) {
+ const { targetName, ...extraOptions } =
+ typeof inferredTargets.build === 'string'
+ ? { targetName: inferredTargets.build }
+ : inferredTargets.build;
+ targets[targetName] = {
+ ...GetBuildExecutorConfiguration(dirname(projectFile)),
+ ...extraOptions,
+ };
+ }
+ if (inferredTargets.lint) {
+ const { targetName, ...extraOptions } =
+ typeof inferredTargets.lint === 'string'
+ ? { targetName: inferredTargets.lint }
+ : inferredTargets.lint;
+ targets[targetName] = {
+ ...GetLintExecutorConfiguration(),
+ ...extraOptions,
+ };
+ }
+ if (inferredTargets.serve) {
+ const { targetName, ...extraOptions } =
+ typeof inferredTargets.serve === 'string'
+ ? { targetName: inferredTargets.serve }
+ : inferredTargets.serve;
+ targets[targetName] = {
+ ...GetServeExecutorConfig(),
+ ...extraOptions,
+ };
}
return targets;
};
@@ -84,8 +113,9 @@ export const createNodes: CreateNodesCompat = [
`**/{${projectFilePatterns.join(',')}}`,
(
file: string,
- ctxOrOpts: CreateNodesContext | NxDotnetConfigV2 | undefined,
- maybeCtx: CreateNodesContext | undefined,
+ // We read the config in the function to ensure it's always up to date / compatible.
+ // ctxOrOpts: CreateNodesContext | NxDotnetConfigV2 | undefined,
+ // maybeCtx: CreateNodesContext | undefined,
) => {
const options = readConfig();
diff --git a/packages/core/src/models/build-executor-configuration.ts b/packages/core/src/models/build-executor-configuration.ts
index 59fed9a8..719d3e7c 100644
--- a/packages/core/src/models/build-executor-configuration.ts
+++ b/packages/core/src/models/build-executor-configuration.ts
@@ -15,11 +15,15 @@ export function GetBuildExecutorConfiguration(
: [
`{workspaceRoot}/dist/${projectRoot}`,
`{workspaceRoot}/dist/intermediates/${projectRoot}`,
+ `{projectRoot}/bin`,
+ `{projectRoot}/obj`,
];
return {
executor: '@nx-dotnet/core:build',
outputs,
+ cache: true,
+ dependsOn: ['^build'],
options: {
configuration: 'Debug',
noDependencies: true,
diff --git a/packages/core/src/models/lint-executor-configuration.ts b/packages/core/src/models/lint-executor-configuration.ts
index 8a91161f..86929bfc 100644
--- a/packages/core/src/models/lint-executor-configuration.ts
+++ b/packages/core/src/models/lint-executor-configuration.ts
@@ -3,5 +3,7 @@ import { TargetConfiguration } from '@nx/devkit';
export function GetLintExecutorConfiguration(): TargetConfiguration {
return {
executor: '@nx-dotnet/core:format',
+ cache: true,
+ inputs: ['{projectRoot}/**/*.{cs,fs,vb}'],
};
}
diff --git a/packages/core/src/models/test-executor-configuration.ts b/packages/core/src/models/test-executor-configuration.ts
index b621f2fc..89d9d427 100644
--- a/packages/core/src/models/test-executor-configuration.ts
+++ b/packages/core/src/models/test-executor-configuration.ts
@@ -1,23 +1,21 @@
import { TargetConfiguration } from '@nx/devkit';
+import { TestExecutorSchema } from '../executors/test/schema';
export function GetTestExecutorConfig(
projectName?: string,
): TestTargetConfiguration {
return {
executor: '@nx-dotnet/core:test',
+ cache: true,
+ dependsOn: ['build'],
options: {
testProject: projectName,
+ noBuild: true,
},
};
}
-export interface TestTargetConfiguration extends TargetConfiguration {
- options: {
- /**
- * If null, implicitly this must be the test project.
- * Else, run this target on the testProject instead of
- * the executor's target.
- */
- testProject?: string;
- };
-}
+export type TestTargetConfiguration = TargetConfiguration & {
+ executor: '@nx-dotnet/core:test';
+ options: TestExecutorSchema;
+};
diff --git a/packages/utils/src/lib/models/nx-dotnet-config.interface.ts b/packages/utils/src/lib/models/nx-dotnet-config.interface.ts
index 92608591..19d2edc5 100644
--- a/packages/utils/src/lib/models/nx-dotnet-config.interface.ts
+++ b/packages/utils/src/lib/models/nx-dotnet-config.interface.ts
@@ -1,3 +1,4 @@
+import { TargetConfiguration } from '@nx/devkit';
import { ModuleBoundaries } from './nx';
export interface NxDotnetConfigV1 {
@@ -31,11 +32,15 @@ export interface NxDotnetConfigV1 {
inferProjects?: boolean;
}
+type PluginTargetConfiguration = TargetConfiguration & {
+ targetName: string;
+};
+
type ConfiguredTargets = {
- build: string | false;
- lint: string | false;
- serve: string | false;
- test: string | false;
+ build: PluginTargetConfiguration | string | false;
+ lint: PluginTargetConfiguration | string | false;
+ serve: PluginTargetConfiguration | string | false;
+ test: PluginTargetConfiguration | string | false;
};
export type NxDotnetConfigV2 = Omit & {
diff --git a/packages/utils/src/lib/utility-functions/workspace.ts b/packages/utils/src/lib/utility-functions/workspace.ts
index 4c6c61cd..5230e76c 100644
--- a/packages/utils/src/lib/utility-functions/workspace.ts
+++ b/packages/utils/src/lib/utility-functions/workspace.ts
@@ -2,6 +2,7 @@ import {
DependencyType,
getProjects,
normalizePath as nxNormalizePath,
+ NX_VERSION,
ProjectConfiguration,
ProjectsConfigurations,
RawProjectGraphDependency,
@@ -11,6 +12,7 @@ import {
import { readFileSync } from 'fs';
import { dirname, relative, resolve } from 'path';
+import { lt } from 'semver';
import { XmlDocument, XmlElement } from 'xmldoc';
import { findProjectFileInPath, findProjectFileInPathSync, glob } from './glob';
@@ -192,6 +194,17 @@ export function inlineNxTokens(value: string, project: ProjectConfiguration) {
return value.replace('{projectName}', project.name as string);
}
+export function isNxCrystalEnabled() {
+ // not the default
+ if (lt(NX_VERSION, '18.0.0')) {
+ return process.env.NX_PCV3 === 'true' || process.env.NX_CRYSTAL === 'true';
+ }
+ // should be on by default
+ return !(
+ process.env.NX_PCV3 === 'false' || process.env.NX_CRYSTAL === 'false'
+ );
+}
+
function tryGetXmlDocument(file: string): XmlDocument | null {
try {
return new XmlDocument(readFileSync(file).toString());
diff --git a/smoke/core/tests/nx-dotnet.spec.ts b/smoke/core/tests/nx-dotnet.spec.ts
index 0e085032..f1c888fc 100644
--- a/smoke/core/tests/nx-dotnet.spec.ts
+++ b/smoke/core/tests/nx-dotnet.spec.ts
@@ -41,26 +41,29 @@ function execAsync(command: string, opts: ExecOptions): Promise {
}
describe('nx-dotnet smoke', () => {
- beforeAll(async () => {
- ({ name: smokeDirectory, removeCallback: cleanup } = dirSync({
- unsafeCleanup: true,
- }));
-
- await execAsync(
- 'npx create-nx-workspace@latest test --preset ts --nxCloud false',
- {
- cwd: smokeDirectory,
- env: process.env,
- },
- );
-
- await execAsync('git init', await execAsyncOptions());
-
- await execAsync(
- 'npm i --save-dev @nx-dotnet/core',
- await execAsyncOptions(),
- );
- }, 20 * 60 * 1000); // 20 minutes
+ beforeAll(
+ async () => {
+ ({ name: smokeDirectory, removeCallback: cleanup } = dirSync({
+ unsafeCleanup: true,
+ }));
+
+ await execAsync(
+ 'npx create-nx-workspace@latest test --preset ts --nxCloud skip',
+ {
+ cwd: smokeDirectory,
+ env: process.env,
+ },
+ );
+
+ await execAsync('git init', await execAsyncOptions());
+
+ await execAsync(
+ 'npm i --save-dev @nx-dotnet/core',
+ await execAsyncOptions(),
+ );
+ },
+ 20 * 60 * 1000,
+ ); // 20 minutes
afterAll(async () => {
cleanup();
diff --git a/tools/scripts/local-registry/setup.ts b/tools/scripts/local-registry/setup.ts
index 2eee5dab..9fdf83c3 100644
--- a/tools/scripts/local-registry/setup.ts
+++ b/tools/scripts/local-registry/setup.ts
@@ -49,3 +49,7 @@ export function killVerdaccioInstance() {
process.on('SIGINT', () => {
killVerdaccioInstance();
});
+
+if (require.main === module) {
+ startCleanVerdaccioInstance();
+}
diff --git a/tools/scripts/publish-dev/index.ts b/tools/scripts/publish-dev/index.ts
index cf382e19..779cf105 100644
--- a/tools/scripts/publish-dev/index.ts
+++ b/tools/scripts/publish-dev/index.ts
@@ -3,7 +3,7 @@ import { publishAll } from '../publish-all';
import * as parser from 'yargs-parser';
-export function main(version: string) {
+export async function main(version: string) {
const rootPkg = readJson('package.json');
const [next, tagSpec]: [string, string | null] = rootPkg.version.startsWith(
version,
@@ -15,7 +15,7 @@ export function main(version: string) {
rev = rev === 'NaN' ? '0' : rev;
const newVersion = `${next}-${tag}.${rev}`;
- publishAll(newVersion, tag);
+ return publishAll(newVersion, tag);
}
if (require.main === module) {
@@ -27,5 +27,7 @@ if (require.main === module) {
if (!version) {
throw new Error('Version is required');
}
- main(version);
+ main(version)
+ .then(() => process.exit(0))
+ .catch(() => process.exit(1));
}
diff --git a/tools/scripts/sandbox.ts b/tools/scripts/sandbox.ts
index 0dec7bcd..5080dcab 100644
--- a/tools/scripts/sandbox.ts
+++ b/tools/scripts/sandbox.ts
@@ -12,11 +12,13 @@ import { startCleanVerdaccioInstance } from './local-registry/setup';
const sandboxDirectory = join(__dirname, '../../tmp/sandbox');
-export function setup() {
+export async function setup() {
copySync('.npmrc.local', '.npmrc');
try {
- startCleanVerdaccioInstance();
- } catch {
+ await startCleanVerdaccioInstance();
+ } catch (E) {
+ throw E;
+
// Its ok.
}
execSync('ts-node ./tools/scripts/publish-all 99.99.99 local', {
@@ -29,28 +31,29 @@ export function setup() {
}
if (require.main === module) {
- setup();
- if (existsSync(sandboxDirectory)) {
- removeSync(sandboxDirectory);
- }
- ensureDirSync(dirname(sandboxDirectory));
- execSync(
- `npx create-nx-workspace@latest ${basename(
- sandboxDirectory,
- )} --preset empty --no-nxCloud --packageManager yarn`,
- {
- cwd: dirname(sandboxDirectory),
- stdio: 'inherit',
- },
- );
- copySync('.npmrc.local', join(sandboxDirectory, '.npmrc'));
- getWorkspacePackages()
- .then((pkgs) => {
- execSync(`yarn add --dev ${pkgs}`, {
- cwd: sandboxDirectory,
- stdio: 'inherit',
+ setup()
+ .then(() => {
+ if (existsSync(sandboxDirectory)) {
+ removeSync(sandboxDirectory);
+ }
+ ensureDirSync(dirname(sandboxDirectory));
+ execSync(
+ `npx create-nx-workspace@latest ${basename(
+ sandboxDirectory,
+ )} --preset empty --no-nxCloud --packageManager yarn`,
+ {
+ cwd: dirname(sandboxDirectory),
+ stdio: 'inherit',
+ },
+ );
+ copySync('.npmrc.local', join(sandboxDirectory, '.npmrc'));
+ getWorkspacePackages().then((pkgs) => {
+ execSync(`yarn add --dev ${pkgs}`, {
+ cwd: sandboxDirectory,
+ stdio: 'inherit',
+ });
+ console.log('Sandbox created at', resolve(sandboxDirectory));
});
- console.log('Sandbox created at', resolve(sandboxDirectory));
})
.catch((err) => {
console.error(err);