Skip to content

Commit

Permalink
Merge pull request #2396 from GreGosPhaTos/feature/issues-1929
Browse files Browse the repository at this point in the history
feat: add warning message for the info command
  • Loading branch information
kamilmysliwiec committed Jan 8, 2024
2 parents f8d5db0 + d29182f commit 4dd9447
Show file tree
Hide file tree
Showing 3 changed files with 300 additions and 1 deletion.
105 changes: 104 additions & 1 deletion actions/info.action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,26 @@ interface PackageJsonDependencies {
interface NestDependency {
name: string;
value: string;
packageName: string;
}

interface NestDependencyWarnings {
[key: string]: Array<NestDependency>;
}

export class InfoAction extends AbstractAction {
private manager!: AbstractPackageManager;
// Nest dependencies whitelist used to compare minor version
private warningMessageDependenciesWhiteList = [
'@nestjs/core',
'@nestjs/common',
'@nestjs/schematics',
'@nestjs/platform-express',
'@nestjs/platform-fastify',
'@nestjs/platform-socket.io',
'@nestjs/platform-ws',
'@nestjs/websockets',
];

public async handle() {
this.manager = await PackageManagerFactory.find();
Expand Down Expand Up @@ -104,9 +120,94 @@ export class InfoAction extends AbstractAction {
}

displayNestVersions(dependencies: PackageJsonDependencies) {
this.buildNestVersionsMessage(dependencies).forEach((dependency) =>
const nestDependencies = this.buildNestVersionsMessage(dependencies);
nestDependencies.forEach((dependency) =>
console.info(dependency.name, chalk.blue(dependency.value)),
);

this.displayWarningMessage(nestDependencies);
}

displayWarningMessage(nestDependencies: NestDependency[]) {
try {
const warnings = this.buildNestVersionsWarningMessage(nestDependencies);
const minorVersions = Object.keys(warnings);
if (minorVersions.length > 0) {
console.info('\r');
console.info(chalk.yellow('[Warnings]'));
console.info(
'The following packages are not in the same minor version',
);
console.info('This could lead to runtime errors');
minorVersions.forEach((version) => {
console.info(chalk.bold(`* Under version ${version}`));
warnings[version].forEach(({ packageName, value }) => {
console.info(`- ${packageName} ${value}`);
});
});
}
} catch {
console.info('\t');
console.error(
chalk.red(
MESSAGES.NEST_INFORMATION_PACKAGE_WARNING_FAILED(
this.warningMessageDependenciesWhiteList,
),
),
);
}
}

buildNestVersionsWarningMessage(
nestDependencies: NestDependency[],
): NestDependencyWarnings {
const unsortedWarnings: NestDependencyWarnings =
nestDependencies.reduce<NestDependencyWarnings>(
(acc, { name, packageName, value }) => {
if (!this.warningMessageDependenciesWhiteList.includes(packageName)) {
return acc;
}

const cleanedValue = value.replace(/[^\d.]/g, '');
const [major, minor] = cleanedValue.split('.');
const minorVersion = `${major}.${minor}`;
acc[minorVersion] = [
...(acc[minorVersion] || []),
{ name, packageName, value },
];

return acc;
},
{},
);

const unsortedMinorVersions = Object.keys(unsortedWarnings);
if (unsortedMinorVersions.length <= 1) {
return {};
}

const sortedMinorVersions = unsortedMinorVersions.sort(
(versionA, versionB) => {
const numA = parseFloat(versionA);
const numB = parseFloat(versionB);

if (isNaN(numA) && isNaN(numB)) {
// If both are not valid numbers, maintain the current order.
return 0;
}

// NaN is considered greater than any number, so if numA is NaN, place it later.
return isNaN(numA) ? 1 : isNaN(numB) ? -1 : numB - numA;
},
);

return sortedMinorVersions.reduce<NestDependencyWarnings>(
(warnings, minorVersion) => {
warnings[minorVersion] = unsortedWarnings[minorVersion];
return warnings;
},
{},
);
}

buildNestVersionsMessage(
Expand All @@ -130,9 +231,11 @@ export class InfoAction extends AbstractAction {
nestDependencies.push({
name: `${key.replace(/@nestjs\//, '').replace(/@.*/, '')} version`,
value: value || dependencies[key].version,
packageName: key,
});
}
});

return nestDependencies;
}

Expand Down
7 changes: 7 additions & 0 deletions lib/ui/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ export const MESSAGES = {
`${EMOJIS.SCREAM} Packages installation failed!\nIn case you don't see any errors above, consider manually running the failed command ${commandToRunManually} to see more details on why it errored out.`,
// tslint:disable-next-line:max-line-length
NEST_INFORMATION_PACKAGE_MANAGER_FAILED: `${EMOJIS.SMIRK} cannot read your project package.json file, are you inside your project directory?`,
NEST_INFORMATION_PACKAGE_WARNING_FAILED: (nestDependencies: string[]) =>
`${
EMOJIS.SMIRK
} failed to compare dependencies versions, please check that following packages are in the same minor version : \n ${nestDependencies.join(
'\n',
)}`,

LIBRARY_INSTALLATION_FAILED_BAD_PACKAGE: (name: string) =>
`Unable to install library ${name} because package did not install. Please check package name.`,
LIBRARY_INSTALLATION_FAILED_NO_LIBRARY: 'No library found.',
Expand Down
189 changes: 189 additions & 0 deletions test/actions/info.action.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import { InfoAction } from '../../actions/info.action';

jest.mock('fs', () => ({
readFileSync: jest.fn(() => '{"version": "1.2.3"}'),
}));

jest.mock('../../lib/package-managers', () => ({
PackageManagerFactory: {
find: jest.fn(() => ({
name: 'MockedPackageManager',
version: jest.fn(() => '1.0.0'),
})),
},
}));

describe('InfoAction', () => {
let infoAction: InfoAction;

beforeEach(() => {
infoAction = new InfoAction();
});

describe('buildNestVersionsWarningMessage', () => {
it('should return an empty object for one or zero minor versions', () => {
const dependencies = [
{ packageName: '@nestjs/core', name: 'core', value: '1.2.3' },
{ packageName: '@nestjs/common', name: 'common', value: '1.2.4' },
];
const result = infoAction.buildNestVersionsWarningMessage(dependencies);
expect(result).toEqual({});
});

it('should return an object only with whitelisted dependencies', () => {
const dependencies = [
{ packageName: '@nestjs/core', name: 'core', value: '1.2.3' },
{ packageName: '@nestjs/common', name: 'common', value: '1.2.4' },
{
packageName: '@nestjs/schematics',
name: 'schematics',
value: '1.2.4',
},
{
packageName: '@nestjs/platform-express',
name: 'platform-express',
value: '1.2.4',
},
{
packageName: '@nestjs/platform-fastify',
name: 'platform-fastify',
value: '1.2.4',
},
{
packageName: '@nestjs/platform-socket.io',
name: 'platform-socket.io',
value: '1.2.4',
},
{
packageName: '@nestjs/platform-ws',
name: 'platform-ws',
value: '2.1.0',
},
{
packageName: '@nestjs/websockets',
name: 'websockets',
value: '2.1.0',
},
{ packageName: '@nestjs/test1', name: 'test1', value: '1.2.4' },
{ packageName: '@nestjs/test2', name: 'test2', value: '1.2.4' },
];
const result = infoAction.buildNestVersionsWarningMessage(dependencies);
const expected = {
'1.2': [
{ packageName: '@nestjs/core', name: 'core', value: '1.2.3' },
{ packageName: '@nestjs/common', name: 'common', value: '1.2.4' },
{
packageName: '@nestjs/schematics',
name: 'schematics',
value: '1.2.4',
},
{
packageName: '@nestjs/platform-express',
name: 'platform-express',
value: '1.2.4',
},
{
packageName: '@nestjs/platform-fastify',
name: 'platform-fastify',
value: '1.2.4',
},
{
packageName: '@nestjs/platform-socket.io',
name: 'platform-socket.io',
value: '1.2.4',
},
],
'2.1': [
{
packageName: '@nestjs/platform-ws',
name: 'platform-ws',
value: '2.1.0',
},
{
packageName: '@nestjs/websockets',
name: 'websockets',
value: '2.1.0',
},
],
};
expect(result).toEqual(expected);
});

it('should group dependencies by minor versions and sort them in descending order', () => {
const dependencies = [
{
name: 'schematics',
packageName: '@nestjs/schematics',
value: '1.2.3',
},
{
name: 'platform-express',
packageName: '@nestjs/platform-express',
value: '1.2.4',
},
{
name: 'platform-fastify',
packageName: '@nestjs/platform-fastify',
value: '2.1.0',
},
{
packageName: '@nestjs/platform-socket.io',
name: 'platform-socket.io',
value: '1.2$$.4',
},
{
name: 'platform-socket.io',
packageName: '@nestjs/platform-socket.io',
value: '2.0.1',
},
{
packageName: '@nestjs/websockets',
name: 'websockets',
value: '^2.*&1.0',
},
];

const result = infoAction.buildNestVersionsWarningMessage(dependencies);
const expected = {
'2.1': [
{
name: 'platform-fastify',
packageName: '@nestjs/platform-fastify',
value: '2.1.0',
},
{
packageName: '@nestjs/websockets',
name: 'websockets',
value: '^2.*&1.0',
},
],
'2.0': [
{
name: 'platform-socket.io',
packageName: '@nestjs/platform-socket.io',
value: '2.0.1',
},
],
'1.2': [
{
name: 'schematics',
packageName: '@nestjs/schematics',
value: '1.2.3',
},
{
name: 'platform-express',
packageName: '@nestjs/platform-express',
value: '1.2.4',
},
{
packageName: '@nestjs/platform-socket.io',
name: 'platform-socket.io',
value: '1.2$$.4',
},
],
};

expect(result).toEqual(expected);
});
});
});

0 comments on commit 4dd9447

Please sign in to comment.