Skip to content

Commit ac8c898

Browse files
bcallaghan-etBen Callaghan
authored andcommitted
feat(core): add executor for dotnet publish #33 (#36)
* feat(dotnet): add publish command to client Add a publish command for a future publish executor to use * feat(core): add publish executor Add a publish executor that delegates to `dotnet publish` Resolves #33 * feat(core): add MSBuild properties to publish executor Add support for commonly used but unusually formatted MSBuild properties. * test(core): fix name of publish executor in tests Fix the name of the executor to be consistent with real world targets. Co-authored-by: Ben Callaghan <bcallaghan@selectbankcard.com>
1 parent 401c0bb commit ac8c898

File tree

16 files changed

+297
-19
lines changed

16 files changed

+297
-19
lines changed

CHANGELOG.md

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,37 @@
11
## [0.4.2](https://github.com/nx-dotnet/nx-dotnet/compare/v0.4.1...v0.4.2) (2021-05-05)
22

3-
43
### Bug Fixes
54

6-
* **core:** [#34](https://github.com/nx-dotnet/nx-dotnet/issues/34) remove spec files from built plugin ([f075046](https://github.com/nx-dotnet/nx-dotnet/commit/f07504625a62ea79afb48b5d3c390ace8202e2ea))
7-
* **core:** [#35](https://github.com/nx-dotnet/nx-dotnet/issues/35) dry run is not passed to dotnet new ([8e0b398](https://github.com/nx-dotnet/nx-dotnet/commit/8e0b3986ad4f5f780bd28f0f69ef5502bb75e2d7))
5+
- **core:** [#34](https://github.com/nx-dotnet/nx-dotnet/issues/34) remove spec files from built plugin ([f075046](https://github.com/nx-dotnet/nx-dotnet/commit/f07504625a62ea79afb48b5d3c390ace8202e2ea))
6+
- **core:** [#35](https://github.com/nx-dotnet/nx-dotnet/issues/35) dry run is not passed to dotnet new ([8e0b398](https://github.com/nx-dotnet/nx-dotnet/commit/8e0b3986ad4f5f780bd28f0f69ef5502bb75e2d7))
87

98
## [0.4.1](https://github.com/nx-dotnet/nx-dotnet/compare/v0.4.0...v0.4.1) (2021-05-03)
109

11-
1210
### Bug Fixes
1311

14-
* **core:** test projects not generating ([28d3d1e](https://github.com/nx-dotnet/nx-dotnet/commit/28d3d1ef14ba41169cb33a73bb4de8fda2da13c0))
12+
- **core:** test projects not generating ([28d3d1e](https://github.com/nx-dotnet/nx-dotnet/commit/28d3d1ef14ba41169cb33a73bb4de8fda2da13c0))
1513

1614
# [0.4.0](https://github.com/nx-dotnet/nx-dotnet/compare/v0.3.0...v0.4.0) (2021-05-01)
1715

18-
1916
### Bug Fixes
2017

21-
* **repo:** update .releaserc to commit package.json version back ([36d2f30](https://github.com/nx-dotnet/nx-dotnet/commit/36d2f30af70c864ad689123486a3471622a8cd01))
22-
18+
- **repo:** update .releaserc to commit package.json version back ([36d2f30](https://github.com/nx-dotnet/nx-dotnet/commit/36d2f30af70c864ad689123486a3471622a8cd01))
2319

2420
### Features
2521

26-
* **core:** schematic for adding npm package [#5](https://github.com/nx-dotnet/nx-dotnet/issues/5) ([4f37be7](https://github.com/nx-dotnet/nx-dotnet/commit/4f37be7065d351539fe22c30d94866382693ed3f)), closes [#6](https://github.com/nx-dotnet/nx-dotnet/issues/6)
27-
* **core:** support for single version principle [#6](https://github.com/nx-dotnet/nx-dotnet/issues/6) ([#32](https://github.com/nx-dotnet/nx-dotnet/issues/32)) ([8e60a13](https://github.com/nx-dotnet/nx-dotnet/commit/8e60a131d2e6522c3ad01788ab06cdf234d99cf3))
22+
- **core:** schematic for adding npm package [#5](https://github.com/nx-dotnet/nx-dotnet/issues/5) ([4f37be7](https://github.com/nx-dotnet/nx-dotnet/commit/4f37be7065d351539fe22c30d94866382693ed3f)), closes [#6](https://github.com/nx-dotnet/nx-dotnet/issues/6)
23+
- **core:** support for single version principle [#6](https://github.com/nx-dotnet/nx-dotnet/issues/6) ([#32](https://github.com/nx-dotnet/nx-dotnet/issues/32)) ([8e60a13](https://github.com/nx-dotnet/nx-dotnet/commit/8e60a131d2e6522c3ad01788ab06cdf234d99cf3))
2824

2925
# [0.3.0](https://github.com/nx-dotnet/nx-dotnet/compare/v0.2.1...v0.3.0) (2021-04-28)
3026

3127
### Bug Fixes
3228

33-
* **core:** [#20](https://github.com/nx-dotnet/nx-dotnet/issues/20) test template arg cannot be passed from command line ([e9e47e0](https://github.com/nx-dotnet/nx-dotnet/commit/e9e47e01e227f458cef41c3511bba69032dcf449))
34-
* **repo:** semantic-release not updating package.json ([9273001](https://github.com/nx-dotnet/nx-dotnet/commit/9273001d385a3e1da1ed4edcc8411641b5c2e280))
35-
29+
- **core:** [#20](https://github.com/nx-dotnet/nx-dotnet/issues/20) test template arg cannot be passed from command line ([e9e47e0](https://github.com/nx-dotnet/nx-dotnet/commit/e9e47e01e227f458cef41c3511bba69032dcf449))
30+
- **repo:** semantic-release not updating package.json ([9273001](https://github.com/nx-dotnet/nx-dotnet/commit/9273001d385a3e1da1ed4edcc8411641b5c2e280))
3631

3732
### Features
3833

39-
* **core:** dotnet test support [#20](https://github.com/nx-dotnet/nx-dotnet/issues/20) ([02ceed0](https://github.com/nx-dotnet/nx-dotnet/commit/02ceed0ae846d6a75de03f4fae5c4cb814ca2742))
34+
- **core:** dotnet test support [#20](https://github.com/nx-dotnet/nx-dotnet/issues/20) ([02ceed0](https://github.com/nx-dotnet/nx-dotnet/commit/02ceed0ae846d6a75de03f4fae5c4cb814ca2742))
4035

4136
## [0.2.1](https://github.com/nx-dotnet/nx-dotnet/compare/v0.2.0...v0.2.1) (2021-04-27)
4237

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,4 @@
9393
"url": "https://github.com/nx-dotnet/nx-dotnet.git"
9494
},
9595
"version": "0.4.2-dev.1"
96-
}
96+
}

packages/core/executors.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
"implementation": "./src/executors/test/executor",
1616
"schema": "./src/executors/test/schema.json",
1717
"description": "test executor"
18+
},
19+
"publish": {
20+
"implementation": "./src/executors/publish/executor",
21+
"schema": "./src/executors/publish/schema.json",
22+
"description": "publish executor"
1823
}
1924
},
2025
"builders": {

packages/core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@
2121
"bugs": {
2222
"url": "https://github.com/nx-dotnet/nx-dotnet/issues/new?assignees=&labels=bug%2C+needs-triage&template=bug_report.md&title=%5BBUG%5D+"
2323
}
24-
}
24+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import { ExecutorContext } from '@nrwl/devkit';
2+
3+
import { promises as fs } from 'fs';
4+
5+
import { DotNetClient, mockDotnetFactory } from '@nx-dotnet/dotnet';
6+
import { rimraf } from '@nx-dotnet/utils';
7+
8+
import executor from './executor';
9+
import { PublishExecutorSchema } from './schema';
10+
11+
const options: PublishExecutorSchema = {
12+
configuration: 'Debug',
13+
};
14+
15+
const root = process.cwd() + '/tmp';
16+
17+
jest.mock('../../../../dotnet/src/lib/core/dotnet.client');
18+
19+
describe('Publish Executor', () => {
20+
let context: ExecutorContext;
21+
let dotnetClient: DotNetClient;
22+
23+
beforeEach(() => {
24+
context = {
25+
root: root,
26+
cwd: root,
27+
projectName: 'my-app',
28+
targetName: 'publish',
29+
workspace: {
30+
version: 2,
31+
projects: {
32+
'my-app': {
33+
root: `${root}/apps/my-app`,
34+
sourceRoot: `${root}/apps/my-app`,
35+
targets: {
36+
publish: {
37+
executor: '@nx-dotnet/core:publish',
38+
},
39+
},
40+
},
41+
},
42+
},
43+
isVerbose: false,
44+
};
45+
dotnetClient = new DotNetClient(mockDotnetFactory());
46+
});
47+
48+
afterEach(async () => {
49+
await rimraf(root);
50+
});
51+
52+
it('detects no dotnet project', async () => {
53+
expect.assertions(1);
54+
try {
55+
await executor(options, context, dotnetClient);
56+
} catch (e) {
57+
console.log(e.message);
58+
expect(e.message).toMatch(
59+
"Unable to find a build-able project within project's source directory!",
60+
);
61+
}
62+
});
63+
64+
it('detects multiple dotnet projects', async () => {
65+
expect.assertions(1);
66+
67+
try {
68+
const directoryPath = `${root}/apps/my-app`;
69+
await fs.mkdir(directoryPath, { recursive: true });
70+
await Promise.all([
71+
fs.writeFile(`${directoryPath}/1.csproj`, ''),
72+
fs.writeFile(`${directoryPath}/2.csproj`, ''),
73+
]);
74+
} catch (e) {
75+
console.warn(e.message);
76+
}
77+
78+
try {
79+
await executor(options, context, dotnetClient);
80+
} catch (e) {
81+
console.log(e.message);
82+
expect(e.message).toMatch(
83+
"More than one build-able projects are contained within the project's source directory!",
84+
);
85+
}
86+
});
87+
88+
it('calls publish when 1 project file is found', async () => {
89+
try {
90+
const directoryPath = `${root}/apps/my-app`;
91+
await fs.mkdir(directoryPath, { recursive: true });
92+
await Promise.all([fs.writeFile(`${directoryPath}/1.csproj`, '')]);
93+
} catch (e) {
94+
console.warn(e.message);
95+
}
96+
97+
const res = await executor(options, context, dotnetClient);
98+
expect(
99+
(dotnetClient as jest.Mocked<DotNetClient>).publish,
100+
).toHaveBeenCalled();
101+
expect(res.success).toBeTruthy();
102+
});
103+
});
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { ExecutorContext } from '@nrwl/devkit';
2+
3+
import {
4+
DotNetClient,
5+
dotnetFactory,
6+
dotnetPublishFlags,
7+
} from '@nx-dotnet/dotnet';
8+
import {
9+
getExecutedProjectConfiguration,
10+
getProjectFileForNxProject,
11+
} from '@nx-dotnet/utils';
12+
13+
import { PublishExecutorSchema } from './schema';
14+
15+
export default async function runExecutor(
16+
options: PublishExecutorSchema,
17+
context: ExecutorContext,
18+
dotnetClient: DotNetClient = new DotNetClient(dotnetFactory()),
19+
) {
20+
const nxProjectConfiguration = getExecutedProjectConfiguration(context);
21+
const projectFilePath = await getProjectFileForNxProject(
22+
nxProjectConfiguration,
23+
);
24+
25+
const { publishProfile, extraParameters, ...flags } = options;
26+
27+
dotnetClient.publish(
28+
projectFilePath,
29+
Object.keys(flags).map((x) => ({
30+
flag: x as dotnetPublishFlags,
31+
value: (options as Record<string, string | boolean>)[x],
32+
})),
33+
publishProfile,
34+
extraParameters,
35+
);
36+
37+
return {
38+
success: true,
39+
};
40+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { dotnetPublishFlags } from '@nx-dotnet/dotnet';
2+
3+
export type PublishExecutorSchema = {
4+
[key in dotnetPublishFlags]?: string | boolean;
5+
} & {
6+
publishProfile?: string;
7+
extraParameters?: string;
8+
};
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
{
2+
"$schema": "http://json-schema.org/schema",
3+
"cli": "nx",
4+
"title": "NxDotnet Publish",
5+
"description": "Publishes an app via the `dotnet` cli command.",
6+
"type": "object",
7+
"properties": {
8+
"configuration": {
9+
"type": "string",
10+
"enum": ["Debug", "Release"],
11+
"default": "Debug",
12+
"description": "Defines the build configuration The default for most projects is Debug, but you can override the build configuration settings in your project."
13+
},
14+
"framework": {
15+
"type": "string",
16+
"description": "Publishes the application for the specified target framework. You must specify the target framework in the project file."
17+
},
18+
"force": {
19+
"type": "boolean",
20+
"description": "Forces all dependencies to be resolved even if the last restore was successful. Specifying this flag is the same as deleting the project.assets.json file."
21+
},
22+
"noBuild": {
23+
"type": "boolean",
24+
"description": "Doesn't build the project before publishing. It also implicitly sets the --no-restore flag."
25+
},
26+
"noDependencies": {
27+
"type": "boolean",
28+
"description": "Ignores project-to-project references and only restores the root project."
29+
},
30+
"nologo": {
31+
"type": "boolean",
32+
"description": "Doesn't display the startup banner or the copyright message. Available since .NET Core 3.0 SDK."
33+
},
34+
"noRestore": {
35+
"type": "boolean",
36+
"description": "Doesn't execute an implicit restore when running the command."
37+
},
38+
"output": {
39+
"type": "string",
40+
"description": "Specifies the path for the output directory."
41+
},
42+
"selfContained": {
43+
"type": "boolean",
44+
"description": "Publishes the .NET runtime with your application so the runtime doesn't need to be installed on the target machine. Default is true if a runtime identifier is specified and the project is an executable project (not a library project)."
45+
},
46+
"runtime": {
47+
"type": "string",
48+
"description": "Publishes the application for a given runtime."
49+
},
50+
"verbosity": {
51+
"type": "string",
52+
"enum": ["quiet", "minimal", "normal", "detailed", "diagnostic"],
53+
"default": "minimal"
54+
},
55+
"versionSuffix": {
56+
"type": "string",
57+
"description": "Defines the version suffix to replace the asterisk (*) in the version field of the project file."
58+
},
59+
"publishProfile": {
60+
"type": "string",
61+
"description": "Specifies the name of the publish profile to use while publishing. Do not include the file path or the file extension. MSBuild by default looks in the Properties/PublishProfiles folder and assumes the pubxml file extension."
62+
},
63+
"extraParameters": {
64+
"type": "string",
65+
"description": "Extra command-line arguments that are passed verbatim to the dotnet command."
66+
}
67+
},
68+
"required": []
69+
}

packages/dotnet/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@
1616
"bugs": {
1717
"url": "https://github.com/nx-dotnet/nx-dotnet/issues/new?assignees=&labels=bug%2C+needs-triage&template=bug_report.md&title=%5BBUG%5D+"
1818
}
19-
}
19+
}

packages/dotnet/src/lib/core/dotnet.client.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ import {
1111
dotnetAddPackageOptions,
1212
dotnetBuildOptions,
1313
dotnetNewOptions,
14+
dotnetPublishOptions,
1415
dotnetRunOptions,
1516
dotnetTemplate,
1617
dotnetTestOptions,
1718
newKeyMap,
19+
publishKeyMap,
1820
testKeyMap,
1921
} from '../models';
2022
import { LoadedCLI } from './dotnet.factory';
@@ -88,6 +90,31 @@ export class DotNetClient {
8890
);
8991
}
9092

93+
publish(
94+
project: string,
95+
parameters?: dotnetPublishOptions,
96+
publishProfile?: string,
97+
extraParameters?: string,
98+
): Buffer {
99+
let cmd = `${this.cliCommand.command} publish ${project}`;
100+
if (parameters) {
101+
parameters = swapArrayFieldValueUsingMap(
102+
parameters,
103+
'flag',
104+
publishKeyMap,
105+
);
106+
const paramString = parameters ? getParameterString(parameters) : '';
107+
cmd = `${cmd} ${paramString}`;
108+
}
109+
if (publishProfile) {
110+
cmd = `${cmd} -p:PublishProfile=${publishProfile}`;
111+
}
112+
if (extraParameters) {
113+
cmd = `${cmd} ${extraParameters}`;
114+
}
115+
return this.logAndExecute(cmd);
116+
}
117+
91118
private logAndExecute(cmd: string): Buffer {
92119
console.log(`Executing Command: ${cmd}`);
93120
return execSync(cmd, { stdio: 'inherit' });

0 commit comments

Comments
 (0)