Skip to content

Commit

Permalink
feat(core): add executor for dotnet publish #33 (#36)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
bcallaghan-et and Ben Callaghan authored May 6, 2021
1 parent 282e44f commit f7cbd27
Show file tree
Hide file tree
Showing 16 changed files with 297 additions and 19 deletions.
23 changes: 9 additions & 14 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,42 +1,37 @@
## [0.4.2-dev.1](https://github.com/nx-dotnet/nx-dotnet/compare/v0.4.1...v0.4.2-dev.1) (2021-05-05)


### Bug Fixes

* **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))
* **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))
- **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))
- **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))

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


### Bug Fixes

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

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


### Bug Fixes

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

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

### Features

* **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)
* **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))
- **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)
- **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))

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

### Bug Fixes

* **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))
* **repo:** semantic-release not updating package.json ([9273001](https://github.com/nx-dotnet/nx-dotnet/commit/9273001d385a3e1da1ed4edcc8411641b5c2e280))

- **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))
- **repo:** semantic-release not updating package.json ([9273001](https://github.com/nx-dotnet/nx-dotnet/commit/9273001d385a3e1da1ed4edcc8411641b5c2e280))

### Features

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

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

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,4 @@
"url": "https://github.com/nx-dotnet/nx-dotnet.git"
},
"version": "0.4.2-dev.1"
}
}
5 changes: 5 additions & 0 deletions packages/core/executors.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
"implementation": "./src/executors/test/executor",
"schema": "./src/executors/test/schema.json",
"description": "test executor"
},
"publish": {
"implementation": "./src/executors/publish/executor",
"schema": "./src/executors/publish/schema.json",
"description": "publish executor"
}
},
"builders": {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@
"bugs": {
"url": "https://github.com/nx-dotnet/nx-dotnet/issues/new?assignees=&labels=bug%2C+needs-triage&template=bug_report.md&title=%5BBUG%5D+"
}
}
}
103 changes: 103 additions & 0 deletions packages/core/src/executors/publish/executor.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { ExecutorContext } from '@nrwl/devkit';

import { promises as fs } from 'fs';

import { DotNetClient, mockDotnetFactory } from '@nx-dotnet/dotnet';
import { rimraf } from '@nx-dotnet/utils';

import executor from './executor';
import { PublishExecutorSchema } from './schema';

const options: PublishExecutorSchema = {
configuration: 'Debug',
};

const root = process.cwd() + '/tmp';

jest.mock('../../../../dotnet/src/lib/core/dotnet.client');

describe('Publish Executor', () => {
let context: ExecutorContext;
let dotnetClient: DotNetClient;

beforeEach(() => {
context = {
root: root,
cwd: root,
projectName: 'my-app',
targetName: 'publish',
workspace: {
version: 2,
projects: {
'my-app': {
root: `${root}/apps/my-app`,
sourceRoot: `${root}/apps/my-app`,
targets: {
publish: {
executor: '@nx-dotnet/core:publish',
},
},
},
},
},
isVerbose: false,
};
dotnetClient = new DotNetClient(mockDotnetFactory());
});

afterEach(async () => {
await rimraf(root);
});

it('detects no dotnet project', async () => {
expect.assertions(1);
try {
await executor(options, context, dotnetClient);
} catch (e) {
console.log(e.message);
expect(e.message).toMatch(
"Unable to find a build-able project within project's source directory!",
);
}
});

it('detects multiple dotnet projects', async () => {
expect.assertions(1);

try {
const directoryPath = `${root}/apps/my-app`;
await fs.mkdir(directoryPath, { recursive: true });
await Promise.all([
fs.writeFile(`${directoryPath}/1.csproj`, ''),
fs.writeFile(`${directoryPath}/2.csproj`, ''),
]);
} catch (e) {
console.warn(e.message);
}

try {
await executor(options, context, dotnetClient);
} catch (e) {
console.log(e.message);
expect(e.message).toMatch(
"More than one build-able projects are contained within the project's source directory!",
);
}
});

it('calls publish when 1 project file is found', async () => {
try {
const directoryPath = `${root}/apps/my-app`;
await fs.mkdir(directoryPath, { recursive: true });
await Promise.all([fs.writeFile(`${directoryPath}/1.csproj`, '')]);
} catch (e) {
console.warn(e.message);
}

const res = await executor(options, context, dotnetClient);
expect(
(dotnetClient as jest.Mocked<DotNetClient>).publish,
).toHaveBeenCalled();
expect(res.success).toBeTruthy();
});
});
40 changes: 40 additions & 0 deletions packages/core/src/executors/publish/executor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { ExecutorContext } from '@nrwl/devkit';

import {
DotNetClient,
dotnetFactory,
dotnetPublishFlags,
} from '@nx-dotnet/dotnet';
import {
getExecutedProjectConfiguration,
getProjectFileForNxProject,
} from '@nx-dotnet/utils';

import { PublishExecutorSchema } from './schema';

export default async function runExecutor(
options: PublishExecutorSchema,
context: ExecutorContext,
dotnetClient: DotNetClient = new DotNetClient(dotnetFactory()),
) {
const nxProjectConfiguration = getExecutedProjectConfiguration(context);
const projectFilePath = await getProjectFileForNxProject(
nxProjectConfiguration,
);

const { publishProfile, extraParameters, ...flags } = options;

dotnetClient.publish(
projectFilePath,
Object.keys(flags).map((x) => ({
flag: x as dotnetPublishFlags,
value: (options as Record<string, string | boolean>)[x],
})),
publishProfile,
extraParameters,
);

return {
success: true,
};
}
8 changes: 8 additions & 0 deletions packages/core/src/executors/publish/schema.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { dotnetPublishFlags } from '@nx-dotnet/dotnet';

export type PublishExecutorSchema = {
[key in dotnetPublishFlags]?: string | boolean;
} & {
publishProfile?: string;
extraParameters?: string;
};
69 changes: 69 additions & 0 deletions packages/core/src/executors/publish/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
{
"$schema": "http://json-schema.org/schema",
"cli": "nx",
"title": "NxDotnet Publish",
"description": "Publishes an app via the `dotnet` cli command.",
"type": "object",
"properties": {
"configuration": {
"type": "string",
"enum": ["Debug", "Release"],
"default": "Debug",
"description": "Defines the build configuration The default for most projects is Debug, but you can override the build configuration settings in your project."
},
"framework": {
"type": "string",
"description": "Publishes the application for the specified target framework. You must specify the target framework in the project file."
},
"force": {
"type": "boolean",
"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."
},
"noBuild": {
"type": "boolean",
"description": "Doesn't build the project before publishing. It also implicitly sets the --no-restore flag."
},
"noDependencies": {
"type": "boolean",
"description": "Ignores project-to-project references and only restores the root project."
},
"nologo": {
"type": "boolean",
"description": "Doesn't display the startup banner or the copyright message. Available since .NET Core 3.0 SDK."
},
"noRestore": {
"type": "boolean",
"description": "Doesn't execute an implicit restore when running the command."
},
"output": {
"type": "string",
"description": "Specifies the path for the output directory."
},
"selfContained": {
"type": "boolean",
"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)."
},
"runtime": {
"type": "string",
"description": "Publishes the application for a given runtime."
},
"verbosity": {
"type": "string",
"enum": ["quiet", "minimal", "normal", "detailed", "diagnostic"],
"default": "minimal"
},
"versionSuffix": {
"type": "string",
"description": "Defines the version suffix to replace the asterisk (*) in the version field of the project file."
},
"publishProfile": {
"type": "string",
"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."
},
"extraParameters": {
"type": "string",
"description": "Extra command-line arguments that are passed verbatim to the dotnet command."
}
},
"required": []
}
2 changes: 1 addition & 1 deletion packages/dotnet/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
"bugs": {
"url": "https://github.com/nx-dotnet/nx-dotnet/issues/new?assignees=&labels=bug%2C+needs-triage&template=bug_report.md&title=%5BBUG%5D+"
}
}
}
27 changes: 27 additions & 0 deletions packages/dotnet/src/lib/core/dotnet.client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ import {
dotnetAddPackageOptions,
dotnetBuildOptions,
dotnetNewOptions,
dotnetPublishOptions,
dotnetRunOptions,
dotnetTemplate,
dotnetTestOptions,
newKeyMap,
publishKeyMap,
testKeyMap,
} from '../models';
import { LoadedCLI } from './dotnet.factory';
Expand Down Expand Up @@ -88,6 +90,31 @@ export class DotNetClient {
);
}

publish(
project: string,
parameters?: dotnetPublishOptions,
publishProfile?: string,
extraParameters?: string,
): Buffer {
let cmd = `${this.cliCommand.command} publish ${project}`;
if (parameters) {
parameters = swapArrayFieldValueUsingMap(
parameters,
'flag',
publishKeyMap,
);
const paramString = parameters ? getParameterString(parameters) : '';
cmd = `${cmd} ${paramString}`;
}
if (publishProfile) {
cmd = `${cmd} -p:PublishProfile=${publishProfile}`;
}
if (extraParameters) {
cmd = `${cmd} ${extraParameters}`;
}
return this.logAndExecute(cmd);
}

private logAndExecute(cmd: string): Buffer {
console.log(`Executing Command: ${cmd}`);
return execSync(cmd, { stdio: 'inherit' });
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export type dotnetPublishFlags =
| 'configuration'
| 'framework'
| 'force'
| 'manifest'
| 'noBuild'
| 'noDependencies'
| 'nologo'
| 'noRestore'
| 'output'
| 'selfContained'
| 'runtime'
| 'verbosity'
| 'versionSuffix';

export const publishKeyMap: Partial<{ [key in dotnetPublishFlags]: string }> = {
noBuild: 'no-build',
noDependencies: 'no-dependencies',
noRestore: 'no-restore',
selfContained: 'self-contained',
versionSuffix: 'version-suffix',
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { dotnetPublishFlags } from './dotnet-publish-flags';

export type dotnetPublishOptions = {
flag: dotnetPublishFlags;
value?: string | boolean;
}[];
2 changes: 2 additions & 0 deletions packages/dotnet/src/lib/models/dotnet-publish/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './dotnet-publish-flags';
export * from './dotnet-publish-options';
1 change: 1 addition & 0 deletions packages/dotnet/src/lib/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './dotnet-build';
export * from './dotnet-run';
export * from './dotnet-test';
export * from './dotnet-add-package';
export * from './dotnet-publish';
2 changes: 1 addition & 1 deletion packages/typescript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@
"bugs": {
"url": "https://github.com/nx-dotnet/nx-dotnet/issues/new?assignees=&labels=bug%2C+needs-triage&template=bug_report.md&title=%5BBUG%5D+"
}
}
}
Loading

0 comments on commit f7cbd27

Please sign in to comment.