Skip to content

Commit 49ce6bc

Browse files
committed
feat(core): pickup global.json overrides at the project level
To accomplish this `dotnet` must be launched from the project's root directories. Closes #87 Closes #86
1 parent 2dea7fc commit 49ce6bc

File tree

17 files changed

+213
-113
lines changed

17 files changed

+213
-113
lines changed

.github/workflows/pr.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
name: Run PR checks
22

3-
on:
4-
# Triggers the workflow on push or pull request events but only for the master branch
5-
pull_request:
6-
branches: [master, dev]
3+
on: pull_request
4+
75

86
env:
97
NX_BRANCH: ${{ github.event.number }}

docs/core/executors/test.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,7 @@ Runs test via the dotnet cli
100100
### verbosity
101101

102102
- (string): Sets the verbosity level of the command. For more information, see LoggerVerbosity.
103+
104+
### watch
105+
106+
- (boolean): Determines if `dotnet test` or `dotnet watch test` is used to execute tests.

packages/core/src/executors/build/executor.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { ExecutorContext } from '@nrwl/devkit';
2+
import { appRootPath } from '@nrwl/tao/src/utils/app-root';
23

34
import {
45
dotnetBuildFlags,
@@ -9,6 +10,7 @@ import {
910
getExecutedProjectConfiguration,
1011
getProjectFileForNxProject,
1112
} from '@nx-dotnet/utils';
13+
import { resolve } from 'path';
1214

1315
import { BuildExecutorSchema } from './schema';
1416

@@ -18,9 +20,15 @@ export default async function runExecutor(
1820
dotnetClient: DotNetClient = new DotNetClient(dotnetFactory()),
1921
) {
2022
const nxProjectConfiguration = getExecutedProjectConfiguration(context);
21-
const projectFilePath = await getProjectFileForNxProject(
22-
nxProjectConfiguration,
23+
dotnetClient.cwd = resolve(appRootPath, nxProjectConfiguration.root);
24+
dotnetClient.printSdkVersion();
25+
const projectFilePath = resolve(
26+
appRootPath,
27+
await getProjectFileForNxProject(nxProjectConfiguration),
2328
);
29+
options.output = options.output
30+
? resolve(appRootPath, options.output)
31+
: undefined;
2432

2533
dotnetClient.build(
2634
projectFilePath,

packages/core/src/executors/publish/executor.spec.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jest.mock('../../../../dotnet/src/lib/core/dotnet.client');
1818

1919
describe('Publish Executor', () => {
2020
let context: ExecutorContext;
21-
let dotnetClient: DotNetClient;
21+
let dotnetClient: jest.Mocked<DotNetClient>;
2222

2323
beforeEach(() => {
2424
context = {
@@ -42,7 +42,9 @@ describe('Publish Executor', () => {
4242
},
4343
isVerbose: false,
4444
};
45-
dotnetClient = new DotNetClient(mockDotnetFactory());
45+
dotnetClient = new DotNetClient(
46+
mockDotnetFactory(),
47+
) as jest.Mocked<DotNetClient>;
4648
});
4749

4850
afterEach(async () => {
@@ -95,9 +97,21 @@ describe('Publish Executor', () => {
9597
}
9698

9799
const res = await executor(options, context, dotnetClient);
98-
expect(
99-
(dotnetClient as jest.Mocked<DotNetClient>).publish,
100-
).toHaveBeenCalled();
100+
expect(dotnetClient.publish).toHaveBeenCalled();
101+
expect(res.success).toBeTruthy();
102+
});
103+
104+
it('should pass path relative to project root, not workspace root', async () => {
105+
const directoryPath = `${root}/apps/my-app`;
106+
try {
107+
await fs.mkdir(directoryPath, { recursive: true });
108+
await Promise.all([fs.writeFile(`${directoryPath}/1.csproj`, '')]);
109+
} catch (e) {
110+
console.warn(e.message);
111+
}
112+
const res = await executor(options, context, dotnetClient);
113+
expect(dotnetClient.publish).toHaveBeenCalled();
114+
expect(dotnetClient.cwd).toEqual(directoryPath);
101115
expect(res.success).toBeTruthy();
102116
});
103117
});

packages/core/src/executors/publish/executor.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { ExecutorContext } from '@nrwl/devkit';
2+
import { appRootPath } from '@nrwl/tao/src/utils/app-root';
23

34
import {
45
DotNetClient,
@@ -9,6 +10,7 @@ import {
910
getExecutedProjectConfiguration,
1011
getProjectFileForNxProject,
1112
} from '@nx-dotnet/utils';
13+
import { resolve } from 'path';
1214

1315
import { PublishExecutorSchema } from './schema';
1416

@@ -18,14 +20,17 @@ export default async function runExecutor(
1820
dotnetClient: DotNetClient = new DotNetClient(dotnetFactory()),
1921
) {
2022
const nxProjectConfiguration = getExecutedProjectConfiguration(context);
23+
const cwd = resolve(appRootPath, nxProjectConfiguration.root);
24+
dotnetClient.cwd = cwd;
2125
const projectFilePath = await getProjectFileForNxProject(
2226
nxProjectConfiguration,
2327
);
2428

2529
const { publishProfile, extraParameters, ...flags } = options;
30+
flags.output = flags.output ? resolve(appRootPath, flags.output) : undefined;
2631

2732
dotnetClient.publish(
28-
projectFilePath,
33+
resolve(appRootPath, projectFilePath),
2934
Object.keys(flags).map((x) => ({
3035
flag: x as dotnetPublishFlags,
3136
value: (options as Record<string, string | boolean>)[x],

packages/core/src/executors/publish/schema.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { dotnetPublishFlags } from '@nx-dotnet/dotnet';
33
export type PublishExecutorSchema = {
44
[key in dotnetPublishFlags]?: string | boolean;
55
} & {
6+
output?: string;
67
publishProfile?: string;
78
extraParameters?: string;
89
};
Lines changed: 14 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { ExecutorContext } from '@nrwl/devkit';
2+
import { appRootPath } from '@nrwl/tao/src/utils/app-root';
23

34
import { ChildProcess } from 'child_process';
4-
import * as chockidar from 'chokidar';
5+
import { resolve as pathResolve } from 'path';
56

67
import {
78
DotNetClient,
@@ -10,17 +11,15 @@ import {
1011
dotnetRunOptions,
1112
} from '@nx-dotnet/dotnet';
1213
import {
13-
getDependantProjectsForNxProject,
1414
getExecutedProjectConfiguration,
1515
getProjectFileForNxProject,
16+
handleChildProcessPassthrough,
1617
rimraf,
1718
} from '@nx-dotnet/utils';
1819

1920
import { ServeExecutorSchema } from './schema';
2021

21-
let resolver: (returnObject: { success: boolean }) => void;
2222
let childProcess: ChildProcess;
23-
let timeout: NodeJS.Timeout;
2423
let projectDirectory: string;
2524

2625
export default function dotnetRunExecutor(
@@ -29,90 +28,28 @@ export default function dotnetRunExecutor(
2928
dotnetClient: DotNetClient = new DotNetClient(dotnetFactory()),
3029
): Promise<{ success: boolean }> {
3130
const nxProjectConfiguration = getExecutedProjectConfiguration(context);
31+
const cwd = pathResolve(appRootPath, nxProjectConfiguration.root);
32+
dotnetClient.cwd = cwd;
3233

33-
return getProjectFileForNxProject(nxProjectConfiguration).then((project) => {
34-
projectDirectory = nxProjectConfiguration.root;
35-
36-
return new Promise((resolve) => {
37-
resolver = resolve;
38-
39-
const watcher = chockidar.watch(nxProjectConfiguration.root);
40-
41-
getDependantProjectsForNxProject(
42-
context.projectName as string,
43-
context.workspace,
44-
(dependency) => {
45-
watcher.add(dependency.root);
46-
},
47-
);
48-
49-
watcher.on('all', (event, path) => {
50-
if (path.includes('bin') || path.includes('obj')) {
51-
return;
52-
}
53-
54-
if (timeout) {
55-
clearTimeout(timeout);
56-
}
57-
58-
timeout = setTimeout(() => {
59-
setupDotnetRun(dotnetClient, project, options);
60-
}, 1000);
61-
62-
console.log(event, path);
63-
});
64-
});
65-
});
34+
return getProjectFileForNxProject(nxProjectConfiguration).then((project) =>
35+
runDotnetRun(dotnetClient, pathResolve(appRootPath, project), options),
36+
);
6637
}
6738

68-
const setupDotnetRun = (
39+
const runDotnetRun = (
6940
dotnetClient: DotNetClient,
7041
project: string,
7142
options: ServeExecutorSchema,
7243
) => {
73-
if (childProcess) {
74-
childProcess.kill('SIGTERM');
75-
}
76-
7744
const opts: dotnetRunOptions = Object.keys(options).map((x) => ({
7845
flag: x as dotnetRunFlags,
7946
value: (options as Record<string, string | boolean>)[x],
8047
}));
8148

82-
childProcess = dotnetClient.run(project, opts);
83-
84-
childProcess.on('error', (err) => {
85-
console.error(err);
49+
childProcess = dotnetClient.run(project, true, opts);
50+
return handleChildProcessPassthrough(childProcess).then(async () => {
51+
await rimraf(projectDirectory + '/bin');
52+
await rimraf(projectDirectory + '/obj');
53+
return { success: true };
8654
});
8755
};
88-
89-
const exitHandler = async (options: { exit: boolean }, exitCode = 0) => {
90-
console.log('Exit Handler Called');
91-
92-
await rimraf(projectDirectory + '/bin');
93-
await rimraf(projectDirectory + '/obj');
94-
95-
if (exitCode || exitCode === 0) console.log(exitCode);
96-
97-
if (childProcess) {
98-
childProcess.kill('SIGINT');
99-
}
100-
resolver({
101-
success: true,
102-
});
103-
104-
if (options.exit) process.exit();
105-
};
106-
107-
//do something when app is closing
108-
process.on('exit', () => exitHandler({ exit: false }));
109-
110-
//catches ctrl+c event
111-
process.on('SIGINT', () => exitHandler({ exit: true }));
112-
113-
// catches "kill pid" (for example: nodemon restart)
114-
process.on('SIGUSR1', () => exitHandler({ exit: true }));
115-
process.on('SIGUSR2', () => exitHandler({ exit: true }));
116-
117-
//catches uncaught exceptions
118-
process.on('uncaughtException', () => exitHandler({ exit: true }));

packages/core/src/executors/test/executor.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import { ExecutorContext } from '@nrwl/devkit';
2+
import { appRootPath } from '@nrwl/tao/src/utils/app-root';
3+
4+
import { resolve } from 'path';
25

36
import {
47
DotNetClient,
@@ -8,28 +11,42 @@ import {
811
import {
912
getExecutedProjectConfiguration,
1013
getProjectFileForNxProject,
14+
handleChildProcessPassthrough,
15+
isChildProcess,
16+
rimraf,
1117
} from '@nx-dotnet/utils';
1218

1319
import { TestExecutorSchema } from './schema';
1420

21+
let projectDirectory: string;
22+
1523
export default async function runExecutor(
1624
options: TestExecutorSchema,
1725
context: ExecutorContext,
1826
dotnetClient: DotNetClient = new DotNetClient(dotnetFactory()),
19-
) {
27+
): Promise<{ success: boolean }> {
2028
const nxProjectConfiguration = getExecutedProjectConfiguration(context);
29+
projectDirectory = resolve(appRootPath, nxProjectConfiguration.root);
2130
const projectFilePath = await getProjectFileForNxProject(
2231
nxProjectConfiguration,
2332
);
33+
dotnetClient.cwd = projectDirectory;
34+
const { watch, ...parsedOptions } = options;
2435

25-
dotnetClient.test(
26-
projectFilePath,
36+
const result = dotnetClient.test(
37+
resolve(appRootPath, projectFilePath),
38+
watch,
2739
Object.keys(options).map((x) => ({
2840
flag: x as dotnetTestFlags,
29-
value: (options as Record<string, string | boolean>)[x],
41+
value: (parsedOptions as Record<string, string | boolean>)[x],
3042
})),
3143
);
3244

45+
if (watch && isChildProcess(result)) {
46+
await handleChildProcessPassthrough(result);
47+
await rimraf(projectDirectory + '/bin');
48+
await rimraf(projectDirectory + '/obj');
49+
}
3350
return {
3451
success: true,
3552
};

packages/core/src/executors/test/schema.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,5 @@ export interface TestExecutorSchema {
3131
| 'detailed'
3232
| 'diag'
3333
| 'diagnostic';
34+
watch?: boolean;
3435
}

packages/core/src/executors/test/schema.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@
108108
"diag",
109109
"diagnostic"
110110
]
111+
},
112+
"watch": {
113+
"description": "Determines if `dotnet test` or `dotnet watch test` is used to execute tests.",
114+
"type": "boolean",
115+
"default": false
111116
}
112117
},
113118
"required": []

0 commit comments

Comments
 (0)