Skip to content

Commit

Permalink
refactor lock file readers
Browse files Browse the repository at this point in the history
  • Loading branch information
rtpascual committed Jan 9, 2025
1 parent 6bef61c commit fffb8b3
Show file tree
Hide file tree
Showing 36 changed files with 524 additions and 306 deletions.
7 changes: 6 additions & 1 deletion .changeset/silver-tables-do.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
---
'@aws-amplify/platform-core': patch
'@aws-amplify/backend-deployer': patch
'create-amplify': patch
'@aws-amplify/backend-cli': patch
'@aws-amplify/cli-core': patch
'@aws-amplify/platform-core': minor
'@aws-amplify/plugin-types': minor
---

Report cdk versions
1 change: 1 addition & 0 deletions .eslint_dictionary.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
"lang",
"linux",
"localhost",
"lockfile",
"lsof",
"lstat",
"macos",
Expand Down
1 change: 1 addition & 0 deletions packages/backend-deployer/src/cdk_deployer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ void describe('invokeCDKCommand', () => {
runWithPackageManager: mock.fn(() => Promise.resolve() as never),
getCommand: (args: string[]) => `'npx ${args.join(' ')}'`,
allowsSignalPropagation: () => true,
getDependencies: mock.fn(() => Promise.resolve([])),
};

const invoker = new CDKDeployer(
Expand Down
3 changes: 2 additions & 1 deletion packages/cli-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"@aws-amplify/platform-core": "^1.3.0",
"@inquirer/prompts": "^3.0.0",
"execa": "^9.5.1",
"kleur": "^4.1.5"
"kleur": "^4.1.5",
"zod": "^3.22.2"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import assert from 'assert';
import fsp from 'fs/promises';
import { afterEach, describe, it, mock } from 'node:test';
import path from 'path';
import { NpmLockFileReader } from './npm_lock_file_reader';
import { NpmLockFileReader } from './npm_lock_file_reader.js';

void describe('NpmLockFileReader', () => {
const fspReadFileMock = mock.method(fsp, 'readFile', () =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import fsp from 'fs/promises';
import path from 'path';
import z from 'zod';
import {
Dependencies,
Dependency,
LockFileContents,
LockFileReader,
} from './lock_file_reader_factory';
} from '@aws-amplify/plugin-types';
import fsp from 'fs/promises';
import path from 'path';
import z from 'zod';
import { printer } from '../../printer.js';
import { LogLevel } from '../../printer/printer.js';

/**
* NpmLockFileReader is an abstraction around the logic used to read and parse lock file contents
*/
export class NpmLockFileReader implements LockFileReader {
getLockFileContentsFromCwd = async (): Promise<LockFileContents> => {
const dependencies: Dependencies = [];
const dependencies: Array<Dependency> = [];
const packageLockJsonPath = path.resolve(
process.cwd(),
'package-lock.json'
Expand All @@ -23,7 +25,10 @@ export class NpmLockFileReader implements LockFileReader {
const jsonLockContents = await fsp.readFile(packageLockJsonPath, 'utf-8');
jsonLockParsedValue = JSON.parse(jsonLockContents);
} catch (error) {
// We failed to get lock file contents either because file doesn't exist or it is not parse-able
printer.log(
`Failed to get lock file contents because ${packageLockJsonPath} does not exist or is not parse-able`,
LogLevel.DEBUG
);
return { dependencies };
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ import assert from 'assert';
import fsp from 'fs/promises';
import { afterEach, describe, it, mock } from 'node:test';
import path from 'path';
import { PnpmLockFileReader } from './pnpm_lock_file_reader';
import { PnpmLockFileReader } from './pnpm_lock_file_reader.js';

void describe('PnpmLockFileReader', () => {
const fspReadFileMock = mock.method(
fsp,
'readFile',
// eslint-disable-next-line spellcheck/spell-checker
() => `lockfileVersion: '9.0'
settings:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import fsp from 'fs/promises';
import path from 'path';
import {
Dependencies,
Dependency,
LockFileContents,
LockFileReader,
} from './lock_file_reader_factory';
} from '@aws-amplify/plugin-types';
import fsp from 'fs/promises';
import path from 'path';
import { printer } from '../../printer.js';
import { LogLevel } from '../../printer/printer.js';

/**
* PnpmLockFileReader is an abstraction around the logic used to read and parse lock file contents
*/
export class PnpmLockFileReader implements LockFileReader {
getLockFileContentsFromCwd = async (): Promise<LockFileContents> => {
const eolRegex = '[\r\n]';
const dependencies: Dependencies = [];
const dependencies: Array<Dependency> = [];
const pnpmLockPath = path.resolve(process.cwd(), 'pnpm-lock.yaml');

try {
Expand Down Expand Up @@ -43,7 +45,10 @@ export class PnpmLockFileReader implements LockFileReader {
dependencies.push({ name: dependencyName, version: dependencyVersion });
}
} catch (error) {
// We failed to get lock file contents either because file doesn't exist or it is not parse-able
printer.log(
`Failed to get lock file contents because ${pnpmLockPath} does not exist or is not parse-able`,
LogLevel.DEBUG
);
return { dependencies };
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import assert from 'assert';
import fsp from 'fs/promises';
import { afterEach, describe, it, mock } from 'node:test';
import path from 'path';
import { YarnClassicLockFileReader } from './yarn_classic_lock_file_reader';
import { YarnClassicLockFileReader } from './yarn_classic_lock_file_reader.js';

void describe('YarnClassicLockFileReader', () => {
const fspReadFileMock = mock.method(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import fsp from 'fs/promises';
import path from 'path';
import {
Dependencies,
Dependency,
LockFileContents,
LockFileReader,
} from './lock_file_reader_factory';
} from '@aws-amplify/plugin-types';
import fsp from 'fs/promises';
import path from 'path';
import { printer } from '../../printer.js';
import { LogLevel } from '../../printer/printer.js';

/**
* YarnClassicLockFileReader is an abstraction around the logic used to read and parse lock file contents
*/
export class YarnClassicLockFileReader implements LockFileReader {
getLockFileContentsFromCwd = async (): Promise<LockFileContents> => {
const eolRegex = '[\r\n]';
const dependencies: Dependencies = [];
const dependencies: Array<Dependency> = [];
const yarnLockPath = path.resolve(process.cwd(), 'yarn.lock');

try {
Expand All @@ -39,7 +41,10 @@ export class YarnClassicLockFileReader implements LockFileReader {
dependencies.push({ name: dependencyName, version: dependencyVersion });
}
} catch (error) {
// We failed to get lock file contents either because file doesn't exist or it is not parse-able
printer.log(
`Failed to get lock file contents because ${yarnLockPath} does not exist or is not parse-able`,
LogLevel.DEBUG
);
return { dependencies };
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import assert from 'assert';
import fsp from 'fs/promises';
import { afterEach, describe, it, mock } from 'node:test';
import path from 'path';
import { YarnModernLockFileReader } from './yarn_modern_lock_file_reader';
import { YarnModernLockFileReader } from './yarn_modern_lock_file_reader.js';

void describe('YarnModernLockFileReader', () => {
const fspReadFileMock = mock.method(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import fsp from 'fs/promises';
import path from 'path';
import {
Dependencies,
Dependency,
LockFileContents,
LockFileReader,
} from './lock_file_reader_factory';
} from '@aws-amplify/plugin-types';
import fsp from 'fs/promises';
import path from 'path';
import { printer } from '../../printer.js';
import { LogLevel } from '../../printer/printer.js';

/**
* YarnModernLockFileReader is an abstraction around the logic used to read and parse lock file contents
*/
export class YarnModernLockFileReader implements LockFileReader {
getLockFileContentsFromCwd = async (): Promise<LockFileContents> => {
const eolRegex = '[\r\n]';
const dependencies: Dependencies = [];
const dependencies: Array<Dependency> = [];
const yarnLockPath = path.resolve(process.cwd(), 'yarn.lock');

try {
Expand All @@ -39,7 +41,10 @@ export class YarnModernLockFileReader implements LockFileReader {
dependencies.push({ name: dependencyName, version: dependencyVersion });
}
} catch (error) {
// We failed to get lock file contents either because file doesn't exist or it is not parse-able
printer.log(
`Failed to get lock file contents because ${yarnLockPath} does not exist or is not parse-able`,
LogLevel.DEBUG
);
return { dependencies };
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import assert from 'assert';
import { execa } from 'execa';
import { NpmPackageManagerController } from './npm_package_manager_controller.js';
import { executeWithDebugLogger } from './execute_with_debugger_logger.js';
import { LockFileReader } from '@aws-amplify/plugin-types';

void describe('NpmPackageManagerController', () => {
const fspMock = {
Expand Down Expand Up @@ -124,4 +125,88 @@ void describe('NpmPackageManagerController', () => {
assert.equal(fspMock.writeFile.mock.callCount(), 1);
});
});

void describe('getDependencies', () => {
const existsSyncMock = mock.fn(() => true);

void it('successfully returns dependency versions', async () => {
const lockFileReaderMock = {
getLockFileContentsFromCwd: async () =>
Promise.resolve({
dependencies: [
{
name: 'aws-cdk',
version: '1.2.3',
},
{
name: 'aws-cdk-lib',
version: '12.13.14',
},
{
name: 'test_dep',
version: '1.23.45',
},
{
name: 'some_other_dep',
version: '12.1.3',
},
],
}),
} as LockFileReader;
const npmPackageManagerController = new NpmPackageManagerController(
'/testProjectRoot',
fspMock as unknown as typeof fsp,
pathMock as unknown as typeof path,
execaMock as unknown as typeof execa,
executeWithDebugLoggerMock as unknown as typeof executeWithDebugLogger,
existsSyncMock,
lockFileReaderMock
);
const dependencyVersions =
await npmPackageManagerController.getDependencies();
const expectedVersions = [
{
name: 'aws-cdk',
version: '1.2.3',
},
{
name: 'aws-cdk-lib',
version: '12.13.14',
},
];

assert.deepEqual(dependencyVersions, expectedVersions);
});

void it('returns empty array if there are no matching dependencies', async () => {
const lockFileReaderMock = {
getLockFileContentsFromCwd: async () =>
Promise.resolve({
dependencies: [
{
name: 'test_dep',
version: '1.23.45',
},
{
name: 'some_other_dep',
version: '12.1.3',
},
],
}),
} as LockFileReader;
const npmPackageManagerController = new NpmPackageManagerController(
'/testProjectRoot',
fspMock as unknown as typeof fsp,
pathMock as unknown as typeof path,
execaMock as unknown as typeof execa,
executeWithDebugLoggerMock as unknown as typeof executeWithDebugLogger,
existsSyncMock,
lockFileReaderMock
);
const dependencyVersions =
await npmPackageManagerController.getDependencies();

assert.deepEqual(dependencyVersions, []);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { execa as _execa } from 'execa';
import * as _path from 'path';
import { executeWithDebugLogger as _executeWithDebugLogger } from './execute_with_debugger_logger.js';
import { PackageManagerControllerBase } from './package_manager_controller_base.js';
import { NpmLockFileReader } from './lock-file-reader/npm_lock_file_reader.js';

/**
* NpmPackageManagerController is an abstraction around npm commands that are needed to initialize a project and install dependencies
Expand All @@ -18,13 +19,15 @@ export class NpmPackageManagerController extends PackageManagerControllerBase {
protected readonly path = _path,
protected readonly execa = _execa,
protected readonly executeWithDebugLogger = _executeWithDebugLogger,
protected readonly existsSync = _existsSync
protected readonly existsSync = _existsSync,
protected readonly lockFileReader = new NpmLockFileReader()
) {
super(
cwd,
'npm',
['init', '--yes'],
'install',
lockFileReader,
fsp,
path,
execa,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import _fsp from 'fs/promises';
import { execa as _execa } from 'execa';
import * as _path from 'path';
import {
Dependency,
ExecaChildProcess,
ExecaOptions,
LockFileReader,
type PackageManagerController,
} from '@aws-amplify/plugin-types';
import { LogLevel } from '../printer/printer.js';
Expand All @@ -27,6 +29,7 @@ export abstract class PackageManagerControllerBase
protected readonly executable: string,
protected readonly initDefault: string[],
protected readonly installCommand: string,
protected readonly lockFileReader: LockFileReader,
protected readonly fsp = _fsp,
protected readonly path = _path,
protected readonly execa = _execa,
Expand Down Expand Up @@ -145,6 +148,25 @@ export abstract class PackageManagerControllerBase
*/
allowsSignalPropagation = () => true;

/**
* getDependencies - Retrieves dependency versions from the lock file in the project root
*/
getDependencies = async (): Promise<Array<Dependency>> => {
const lockFileContents =
await this.lockFileReader.getLockFileContentsFromCwd();
const targetDependencies = ['aws-cdk', 'aws-cdk-lib'];

const dependencyVersions: Array<Dependency> = [];

for (const { name, version } of lockFileContents.dependencies) {
if (targetDependencies.includes(name)) {
dependencyVersions.push({ name, version });
}
}

return dependencyVersions;
};

/**
* Check if a package.json file exists in projectRoot
*/
Expand Down
Loading

0 comments on commit fffb8b3

Please sign in to comment.