Skip to content

Commit

Permalink
fix(core): update-swagger executor always reinstalls tool (#757)
Browse files Browse the repository at this point in the history
  • Loading branch information
EchelonFour authored Sep 19, 2023
1 parent 12d89ac commit 63cf4b4
Show file tree
Hide file tree
Showing 9 changed files with 247 additions and 42 deletions.
24 changes: 7 additions & 17 deletions packages/core/src/executors/format/executor.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import * as devkit from '@nrwl/devkit';
import { ExecutorContext } from '@nrwl/devkit';

import * as fs from 'fs';

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

Expand Down Expand Up @@ -68,7 +65,9 @@ describe('Format Executor', () => {
});

it('installs dotnet-format if not already installed', async () => {
jest.spyOn(fs, 'existsSync').mockReturnValue(false);
jest
.spyOn(utils, 'readInstalledDotnetToolVersion')
.mockReturnValue(undefined);
const res = await executor(options, context, dotnetClient);
expect(
(dotnetClient as jest.Mocked<DotNetClient>).installTool,
Expand All @@ -77,11 +76,9 @@ describe('Format Executor', () => {
});

it('does not install dotnet-format if already installed', async () => {
jest.spyOn(fs, 'existsSync').mockReturnValue(true);
jest
.spyOn(devkit, 'readJsonFile')
.mockReturnValue({ tools: { 'dotnet-format': '1.0.0' } });

.spyOn(utils, 'readInstalledDotnetToolVersion')
.mockReturnValue('1.0.0');
const res = await executor(options, context, dotnetClient);
expect(
(dotnetClient as jest.Mocked<DotNetClient>).installTool,
Expand All @@ -94,11 +91,6 @@ describe('Format Executor', () => {
'6.0.101',
);

jest.spyOn(fs, 'existsSync').mockReturnValue(true);
jest
.spyOn(devkit, 'readJsonFile')
.mockReturnValue({ tools: { 'dotnet-format': '1.0.0' } });

const res = await executor(options, context, dotnetClient);
expect(
(dotnetClient as jest.Mocked<DotNetClient>).installTool,
Expand All @@ -110,11 +102,9 @@ describe('Format Executor', () => {
(dotnetClient as jest.Mocked<DotNetClient>).getSdkVersion.mockReturnValue(
'5.0.101',
);
jest.spyOn(fs, 'existsSync').mockReturnValue(true);
jest
.spyOn(devkit, 'readJsonFile')
.mockReturnValue({ tools: { 'dotnet-format': '1.0.0' } });

.spyOn(utils, 'readInstalledDotnetToolVersion')
.mockReturnValue('1.0.0');
const res = await executor(options, context, dotnetClient);
expect(res.success).toBeTruthy();

Expand Down
12 changes: 3 additions & 9 deletions packages/core/src/executors/format/executor.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { ExecutorContext, readJsonFile, workspaceRoot } from '@nrwl/devkit';
import { ExecutorContext } from '@nrwl/devkit';

import { existsSync } from 'fs';
import { join } from 'path';
import * as semver from 'semver';

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

import { FormatExecutorSchema } from './schema';
Expand Down Expand Up @@ -60,12 +59,7 @@ function ensureFormatToolInstalled(
dotnetClient: DotNetClient,
majorVersion: number,
) {
const manifestPath = join(workspaceRoot, './.config/dotnet-tools.json');

const manifest = existsSync(manifestPath)
? readJsonFile(manifestPath)
: undefined;
if (manifest?.tools['dotnet-format']) {
if (readInstalledDotnetToolVersion('dotnet-format')) {
// dotnet-format is already installed.
return;
}
Expand Down
33 changes: 29 additions & 4 deletions packages/core/src/executors/update-swagger/executor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,19 @@ describe('Update-Swagger Executor', () => {
}
throw new Error('Attempted to read unexpected file');
});
jest
.spyOn(utils, 'readInstalledDotnetToolVersion')
.mockImplementation((tool) => {
if (tool === SWAGGER_CLI_TOOL) {
return '99.99.99';
}
throw new Error('unknown tool version read');
});
jest
.spyOn(devkit, 'readJsonFile')
.mockImplementation((p: string): object => {
if (p === `${root}/.nx-dotnet.rc.json`) {
return {};
} else if (p === `${root}/.config/dotnet-tools.json`) {
return { tools: { [SWAGGER_CLI_TOOL]: '99.99.99' } };
}
throw new Error(`Attempted to read unexpected file: ${p}`);
});
Expand Down Expand Up @@ -122,6 +128,14 @@ describe('Update-Swagger Executor', () => {
throw new Error('Attempted to read unexpected file');
});
jest.spyOn(devkit, 'readJsonFile').mockReturnValue({});
jest
.spyOn(utils, 'readInstalledDotnetToolVersion')
.mockImplementation((tool) => {
if (tool === SWAGGER_CLI_TOOL) {
return undefined;
}
throw new Error('unknown tool version read');
});
const res = await executor(options, context, dotnetClient);
expect(
(dotnetClient as jest.Mocked<DotNetClient>).installTool,
Expand All @@ -137,13 +151,19 @@ describe('Update-Swagger Executor', () => {
}
throw new Error('Attempted to read unexpected file');
});
jest
.spyOn(utils, 'readInstalledDotnetToolVersion')
.mockImplementation((tool) => {
if (tool === SWAGGER_CLI_TOOL) {
return '99.99.99';
}
throw new Error('unknown tool version read');
});
jest
.spyOn(devkit, 'readJsonFile')
.mockImplementation((p: string): object => {
if (p === `${root}/.nx-dotnet.rc.json`) {
return {};
} else if (p === `${root}/.config/dotnet-tools.json`) {
return { tools: { [SWAGGER_CLI_TOOL]: '99.99.99' } };
}
throw new Error(`Attempted to read unexpected file: ${p}`);
});
Expand All @@ -163,6 +183,10 @@ describe('Update-Swagger Executor', () => {
}
throw new Error('Attempted to read unexpected file');
});
const readToolVersionSpy = jest
.spyOn(utils, 'readInstalledDotnetToolVersion')
.mockReset();

jest.spyOn(devkit, 'readJsonFile').mockReturnValue({});
const res = await executor(
{ ...options, skipInstall: true },
Expand All @@ -172,6 +196,7 @@ describe('Update-Swagger Executor', () => {
expect(
(dotnetClient as jest.Mocked<DotNetClient>).installTool,
).not.toHaveBeenCalled();
expect(readToolVersionSpy).not.toBeCalled();
expect(res.success).toBeTruthy();
});
});
22 changes: 10 additions & 12 deletions packages/core/src/executors/update-swagger/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@ import {
ExecutorContext,
logger,
ProjectConfiguration,
readJsonFile,
workspaceRoot,
} from '@nrwl/devkit';

import { existsSync } from 'fs';
import { ensureDirSync } from 'fs-extra';
import { dirname, join, resolve } from 'path';
import { dirname, resolve } from 'path';

import { DotNetClient, dotnetFactory } from '@nx-dotnet/dotnet';
import {
Expand All @@ -17,6 +15,7 @@ import {
iterateChildrenByPath,
readConfig,
readXml,
readInstalledDotnetToolVersion,
} from '@nx-dotnet/utils';

import { buildStartupAssemblyPath } from '../../generators/utils/get-path-to-startup-assembly';
Expand Down Expand Up @@ -118,16 +117,15 @@ function ensureSwaggerToolInstalled(
dotnetClient: DotNetClient,
version: string,
) {
const manifestPath = join(workspaceRoot, './.config/dotnet-tools.json');
const manifest = existsSync(manifestPath)
? readJsonFile(manifestPath)
: undefined;

if (manifest?.tools[SWAGGER_CLI_TOOL] === version) {
return;
} else if (manifest?.tools[SWAGGER_CLI_TOOL]) {
const installedSwaggerVersion =
readInstalledDotnetToolVersion(SWAGGER_CLI_TOOL);

if (installedSwaggerVersion) {
if (installedSwaggerVersion === version) {
return;
}
logger.warn(
`Swagger CLI was found, but the version does not match the version of Swashbuckle.AspNetCore in ${context.projectName}. We reinstalled it such that the version matches, but you may want to review the changes made.`,
`Swagger CLI was found, but the version "${installedSwaggerVersion}" does not match the expected version "${version}" of Swashbuckle.AspNetCore in ${context.projectName}. We reinstalled it such that the version matches, but you may want to review the changes made.`,
);
}

Expand Down
12 changes: 12 additions & 0 deletions packages/utils/src/lib/models/dotnet-tools-manifest.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export interface DotnetToolsManifestV1 {
version: 1;
isRoot: boolean;
tools: {
[key: string]: {
version: string;
commands: string[];
};
};
}

export type DotnetToolsManifest = DotnetToolsManifestV1;
1 change: 1 addition & 0 deletions packages/utils/src/lib/models/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './cmd-line-parameter';
export * from './nx-dotnet-config.interface';
export * from './nx';
export * from './dotnet-tools-manifest.interface';
143 changes: 143 additions & 0 deletions packages/utils/src/lib/utility-functions/dotnet-tools-manifest.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import {
readDotnetToolsManifest,
readInstalledDotnetToolVersion,
} from './dotnet-tools-manifest';
import * as devkit from '@nrwl/devkit';
import * as fs from 'fs';

const root = '/virtual';
jest.mock('@nrwl/devkit', () => ({
...jest.requireActual('@nrwl/devkit'),
workspaceRoot: '/virtual',
}));

const existsSyncMock = jest.spyOn(fs, 'existsSync');
const readJsonFileMock = jest.spyOn(devkit, 'readJsonFile');

describe('dotnet tools util functions', () => {
describe('readDotnetToolsManifest', () => {
beforeEach(() => {
existsSyncMock.mockReset();
readJsonFileMock.mockReset();
existsSyncMock.mockReturnValue(true);
readJsonFileMock.mockImplementation((p: string): object => {
if (p === `${root}/.config/dotnet-tools.json`) {
return {
version: 1,
isRoot: true,
tools: {
'swashbuckle.aspnetcore.cli': {
version: '99.99.99',
commands: ['swagger'],
},
},
};
}
throw new Error(`Attempted to read unexpected file: ${p}`);
});
});

it('should read from workspace root', async () => {
const result = readDotnetToolsManifest();
expect(result).toEqual({
version: 1,
isRoot: true,
tools: {
'swashbuckle.aspnetcore.cli': {
version: '99.99.99',
commands: ['swagger'],
},
},
});
});

it('should return undefined if file missing', async () => {
existsSyncMock.mockReturnValue(false);
const result = readDotnetToolsManifest();
expect(result).toBeUndefined();
expect(readJsonFileMock).not.toHaveBeenCalled();
});

it('should return undefined if file wrong version', async () => {
readJsonFileMock.mockImplementation((p: string): object => {
if (p === `${root}/.config/dotnet-tools.json`) {
return {
version: 99,
isRoot: true,
tools: {},
};
}
throw new Error(`Attempted to read unexpected file: ${p}`);
});
const result = readDotnetToolsManifest();
expect(result).toBeUndefined();
});

it('read from overridden file path if provided', async () => {
readJsonFileMock.mockImplementation((p: string): object => {
if (p === '/custom/path/file.json') {
return {
version: 1,
isRoot: true,
tools: {},
};
}
throw new Error(`Attempted to read unexpected file: ${p}`);
});
const result = readDotnetToolsManifest('/custom/path/file.json');
expect(result).toEqual({
version: 1,
isRoot: true,
tools: {},
});
});
});

describe('readInstalledDotnetToolVersion', () => {
beforeEach(() => {
existsSyncMock.mockReturnValue(true);
readJsonFileMock.mockImplementation((p: string): object => {
if (p === `${root}/.config/dotnet-tools.json`) {
return {
version: 1,
isRoot: true,
tools: {
'swashbuckle.aspnetcore.cli': {
version: '99.99.99',
commands: ['swagger'],
},
},
};
}
throw new Error(`Attempted to read unexpected file: ${p}`);
});
});

it('should read version', async () => {
const result = readInstalledDotnetToolVersion(
'swashbuckle.aspnetcore.cli',
);
expect(result).toEqual('99.99.99');
});

it('should read version if tool case mismatch', async () => {
const result = readInstalledDotnetToolVersion(
'SwashBuckle.AspNetCore.Cli',
);
expect(result).toEqual('99.99.99');
});

it('should return undefined if tool not installed', async () => {
const result = readInstalledDotnetToolVersion('Not.There');
expect(result).toBeUndefined();
});

it('should return undefined if no tool manifest file', async () => {
existsSyncMock.mockReturnValue(false);
const result = readInstalledDotnetToolVersion(
'swashbuckle.aspnetcore.cli',
);
expect(result).toBeUndefined();
});
});
});
Loading

0 comments on commit 63cf4b4

Please sign in to comment.