Skip to content

Commit

Permalink
fix(dotnet): prevent "false" being incorrectly passed to dotnet comma…
Browse files Browse the repository at this point in the history
…nd (#818)

* fix(dotnet): prevent "false" being incorrectly passed to dotnet command

* chore(dotnet): refactor how command line flags are built
  • Loading branch information
EchelonFour authored Jan 31, 2024
1 parent d9fff67 commit 0945571
Show file tree
Hide file tree
Showing 12 changed files with 368 additions and 100 deletions.
157 changes: 150 additions & 7 deletions packages/dotnet/src/lib/core/dotnet.client.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import { DotNetClient } from './dotnet.client';
import { dotnetFactory, mockDotnetFactory } from './dotnet.factory';

describe('dotnet client', () => {
afterEach(() => {
jest.resetAllMocks();
});

describe('publish', () => {
describe('extra parameters', () => {
const dotnetClient = new DotNetClient(mockDotnetFactory());
Expand All @@ -13,13 +17,7 @@ describe('dotnet client', () => {
beforeEach(() => {
spawnSyncSpy = jest
.spyOn(cp, 'spawnSync')
.mockReturnValue({ status: 0 } as Partial<
cp.SpawnSyncReturns<Buffer>
> as cp.SpawnSyncReturns<Buffer>);
});

afterEach(() => {
jest.resetAllMocks();
.mockReturnValue({ status: 0 } as cp.SpawnSyncReturns<Buffer>);
});

it('should handle multiple parameters', () => {
Expand Down Expand Up @@ -78,6 +76,27 @@ describe('dotnet client', () => {
expect(spawnSyncSpy.mock.calls[0][1]).toContain('-p:Name=bar');
});
});
it('should convert options to flags', () => {
const dotnetClient = new DotNetClient(mockDotnetFactory());
const spawnSyncSpy = jest
.spyOn(cp, 'spawnSync')
.mockReturnValue({ status: 0 } as cp.SpawnSyncReturns<Buffer>);
dotnetClient.publish('my-project', {
noBuild: false,
noRestore: true,
configuration: 'Release',
});
expect(spawnSyncSpy).toBeCalledTimes(1);
expect(spawnSyncSpy.mock.calls[0][1]).toMatchInlineSnapshot(`
[
"publish",
""my-project"",
"--no-restore",
"--configuration",
"Release",
]
`);
});
});

describe('listInstalledTemplates', () => {
Expand Down Expand Up @@ -484,4 +503,128 @@ ASP.NET Core gRPC Service grpc [C#]
`);
});
});

describe('test', () => {
it('should convert options to flags', () => {
const dotnetClient = new DotNetClient(mockDotnetFactory());
const spawnSyncSpy = jest
.spyOn(cp, 'spawnSync')
.mockReturnValue({ status: 0 } as cp.SpawnSyncReturns<Buffer>);
dotnetClient.test('my-project', false, {
blame: false,
noRestore: true,
blameHang: true,
blameHangDump: 'dump.file',
});
expect(spawnSyncSpy).toHaveBeenCalledTimes(1);
expect(spawnSyncSpy.mock.calls[0][1]).toMatchInlineSnapshot(`
[
"test",
"my-project",
"--no-restore",
"--blame-hang",
"--blame-hang-dump",
"dump.file",
]
`);
});
});

describe('build', () => {
it('should convert options to flags', () => {
const dotnetClient = new DotNetClient(mockDotnetFactory());
const spawnSyncSpy = jest
.spyOn(cp, 'spawnSync')
.mockReturnValue({ status: 0 } as cp.SpawnSyncReturns<Buffer>);
dotnetClient.build('my-project', {
noDependencies: false,
noRestore: true,
configuration: 'Release',
});
expect(spawnSyncSpy).toHaveBeenCalledTimes(1);
expect(spawnSyncSpy.mock.calls[0][1]).toMatchInlineSnapshot(`
[
"build",
"my-project",
"--no-restore",
"--configuration",
"Release",
]
`);
});
});

describe('addPackageReference', () => {
it('should convert options to flags', () => {
const dotnetClient = new DotNetClient(mockDotnetFactory());
const spawnSyncSpy = jest
.spyOn(cp, 'spawnSync')
.mockReturnValue({ status: 0 } as cp.SpawnSyncReturns<Buffer>);
dotnetClient.addPackageReference('my-project', 'other-package', {
noRestore: true,
version: '1.2.3',
});
expect(spawnSyncSpy).toHaveBeenCalledTimes(1);
expect(spawnSyncSpy.mock.calls[0][1]).toMatchInlineSnapshot(`
[
"add",
"my-project",
"package",
"other-package",
"--no-restore",
"--version",
"1.2.3",
]
`);
});
});

describe('new', () => {
it('should convert options to flags', () => {
const dotnetClient = new DotNetClient(mockDotnetFactory());
const spawnSyncSpy = jest
.spyOn(cp, 'spawnSync')
.mockReturnValue({ status: 0 } as cp.SpawnSyncReturns<Buffer>);
dotnetClient.new('my-template', {
dryRun: true,
force: false,
name: 'my-project',
});
expect(spawnSyncSpy).toHaveBeenCalledTimes(1);
expect(spawnSyncSpy.mock.calls[0][1]).toMatchInlineSnapshot(`
[
"new",
"my-template",
"--dry-run",
"--name",
"my-project",
]
`);
});
});

describe('run', () => {
it('should convert options to flags', () => {
const dotnetClient = new DotNetClient(mockDotnetFactory());
const spawnSpy = jest
.spyOn(cp, 'spawn')
.mockReturnValue({ exitCode: 0 } as cp.ChildProcess);
dotnetClient.run('my-project', false, {
noRestore: true,
noDependencies: false,
configuration: 'Release',
});
expect(spawnSpy).toHaveBeenCalledTimes(1);
expect(spawnSpy.mock.calls[0][1]).toMatchInlineSnapshot(`
[
"run",
"--project",
"my-project",
"--no-restore",
"--configuration",
"Release",
]
`);
});
});
});
71 changes: 43 additions & 28 deletions packages/dotnet/src/lib/core/dotnet.client.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { ChildProcess, spawn, spawnSync } from 'child_process';
import * as semver from 'semver';

import { getSpawnParameterArray, swapKeysUsingMap } from '@nx-dotnet/utils';
import {
convertOptionsToParams,
getSpawnParameterArray,
} from '@nx-dotnet/utils';

import {
addPackageKeyMap,
buildKeyMap,
addPackageCommandLineParamFixes,
buildCommandLineParamFixes,
dotnetAddPackageOptions,
dotnetBuildOptions,
dotnetFormatOptions,
Expand All @@ -14,18 +17,21 @@ import {
dotnetRunOptions,
DotnetTemplate,
dotnetTestOptions,
formatKeyMap,
formatCommandLineParamFixes,
KnownDotnetTemplates,
newKeyMap,
publishKeyMap,
runKeyMap,
testKeyMap,
newCommandLineParamFixes,
publishCommandLineParamFixes,
runCommandLineParamFixes,
testCommandLineParamFixes,
} from '../models';
import { parseDotnetNewListOutput } from '../utils/parse-dotnet-new-list-output';
import { LoadedCLI } from './dotnet.factory';

export class DotNetClient {
constructor(private cliCommand: LoadedCLI, public cwd?: string) {}
constructor(
private cliCommand: LoadedCLI,
public cwd?: string,
) {}

new(
template: KnownDotnetTemplates,
Expand All @@ -34,8 +40,9 @@ export class DotNetClient {
): void {
const params = [`new`, template];
if (parameters) {
parameters = swapKeysUsingMap(parameters, newKeyMap);
params.push(...getSpawnParameterArray(parameters));
params.push(
...convertOptionsToParams(parameters, newCommandLineParamFixes),
);
}
params.push(...(additionalArguments ?? []));
return this.logAndExecute(params);
Expand Down Expand Up @@ -72,8 +79,9 @@ export class DotNetClient {
): void {
const params = [`build`, project];
if (parameters) {
parameters = swapKeysUsingMap(parameters, buildKeyMap);
params.push(...getSpawnParameterArray(parameters));
params.push(
...convertOptionsToParams(parameters, buildCommandLineParamFixes),
);
}
if (extraParameters) {
const matches = extraParameters.match(EXTRA_PARAMS_REGEX);
Expand All @@ -91,8 +99,9 @@ export class DotNetClient {
? [`watch`, `--project`, project, `run`]
: [`run`, `--project`, project];
if (parameters) {
parameters = swapKeysUsingMap(parameters, runKeyMap);
params.push(...getSpawnParameterArray(parameters));
params.push(
...convertOptionsToParams(parameters, runCommandLineParamFixes),
);
}

return this.logAndSpawn(params);
Expand All @@ -109,8 +118,9 @@ export class DotNetClient {
: [`test`, project];

if (parameters) {
parameters = swapKeysUsingMap(parameters, testKeyMap);
params.push(...getSpawnParameterArray(parameters));
params.push(
...convertOptionsToParams(parameters, testCommandLineParamFixes),
);
}
if (extraParameters) {
const matches = extraParameters.match(EXTRA_PARAMS_REGEX);
Expand All @@ -130,8 +140,9 @@ export class DotNetClient {
): void {
const params = [`add`, project, `package`, pkg];
if (parameters) {
parameters = swapKeysUsingMap(parameters, addPackageKeyMap);
params.push(...getSpawnParameterArray(parameters));
params.push(
...convertOptionsToParams(parameters, addPackageCommandLineParamFixes),
);
}
return this.logAndExecute(params);
}
Expand All @@ -148,8 +159,9 @@ export class DotNetClient {
): void {
const params = [`publish`, `"${project}"`];
if (parameters) {
parameters = swapKeysUsingMap(parameters, publishKeyMap);
params.push(...getSpawnParameterArray(parameters));
params.push(
...convertOptionsToParams(parameters, publishCommandLineParamFixes),
);
}
if (publishProfile) {
params.push(`-p:PublishProfile=${publishProfile}`);
Expand Down Expand Up @@ -216,8 +228,9 @@ export class DotNetClient {
...parameters,
};
subcommandParams.push(
...getSpawnParameterArray(
swapKeysUsingMap(subcommandParameterObject, formatKeyMap),
...convertOptionsToParams(
subcommandParameterObject,
formatCommandLineParamFixes,
),
);
this.logAndExecute(subcommandParams);
Expand All @@ -233,8 +246,9 @@ export class DotNetClient {
subcommandParameterObject.severity = style;
}
subcommandParams.push(
...getSpawnParameterArray(
swapKeysUsingMap(subcommandParameterObject, formatKeyMap),
...convertOptionsToParams(
subcommandParameterObject,
formatCommandLineParamFixes,
),
);
this.logAndExecute(subcommandParams);
Expand All @@ -250,8 +264,9 @@ export class DotNetClient {
subcommandParameterObject.severity = analyzers;
}
subcommandParams.push(
...getSpawnParameterArray(
swapKeysUsingMap(subcommandParameterObject, formatKeyMap),
...convertOptionsToParams(
subcommandParameterObject,
formatCommandLineParamFixes,
),
);
this.logAndExecute(subcommandParams);
Expand All @@ -260,7 +275,7 @@ export class DotNetClient {
params.push(project);
if (parameters) {
params.push(
...getSpawnParameterArray(swapKeysUsingMap(parameters, formatKeyMap)),
...convertOptionsToParams(parameters, formatCommandLineParamFixes),
);
}
return this.logAndExecute(params);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { CommandLineParamFixes } from '@nx-dotnet/utils';

export type dotnetAddPackageFlags =
| 'version'
| 'framework'
Expand All @@ -6,9 +8,11 @@ export type dotnetAddPackageFlags =
| 'noRestore'
| 'source';

export const addPackageKeyMap: Partial<{
[key in dotnetAddPackageFlags]: string;
}> = {
packageDirectory: 'package-directory',
noRestore: 'no-restore',
};
export const addPackageCommandLineParamFixes: CommandLineParamFixes<dotnetAddPackageFlags> =
{
keyMap: {
packageDirectory: 'package-directory',
noRestore: 'no-restore',
},
explicitFalseKeys: [],
};
18 changes: 12 additions & 6 deletions packages/dotnet/src/lib/models/dotnet-build/dotnet-build-flags.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { CommandLineParamFixes } from '@nx-dotnet/utils';

export type dotnetBuildFlags =
| 'configuration'
| 'framework'
Expand All @@ -12,9 +14,13 @@ export type dotnetBuildFlags =
| 'versionSuffix'
| 'runtime';

export const buildKeyMap: Partial<{ [key in dotnetBuildFlags]: string }> = {
noRestore: 'no-restore',
noIncremental: 'no-incremental',
noDependencies: 'no-dependencies',
versionSuffix: 'version-suffix',
};
export const buildCommandLineParamFixes: CommandLineParamFixes<dotnetBuildFlags> =
{
keyMap: {
noRestore: 'no-restore',
noIncremental: 'no-incremental',
noDependencies: 'no-dependencies',
versionSuffix: 'version-suffix',
},
explicitFalseKeys: [],
};
Loading

0 comments on commit 0945571

Please sign in to comment.