Skip to content

Commit 5c40b90

Browse files
authored
fix(lambda-nodejs): logLevel property of BundlingOptions is ignored when nodeModules are defined (#18456)
In this pull request I managed to propagate the effect of the `logLevel` property downstream to the `PackageManager` class. I had to refactor the static approach for constructing handler objects for the various package managers as we need to pass a new optional property in the `fromLockFile(lockFilePath: string)` static builder method. The value for `installCommand` attribute in the constructor now depends on the log level and the approach varies between package managers: while `npm ci` supports a flexible `--loglevel` command option matching each of the `LogLevel` enum existing values, `yarn install` only supports a `--silent` option and similarly `pnpm install` supports a `--reporter=silent` which suppresses the command output except for errors and warnings. For `yarn` and `pnpm` my idea is to include the silent options whenever a log level is specified and its value is different from the default `LogLevel.INFO`. I also adapted existing unit tests and added new ones taking into account the property's value. I have no experience with yarn and pnpm and I am not sure that any tests exist using bundling with yarn- and pnpm-based lambda function handlers, so I cannot guarantee that my changes work for that too. Fixes #18383 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 6595d04 commit 5c40b90

File tree

6 files changed

+75
-41
lines changed

6 files changed

+75
-41
lines changed

packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export class Bundling implements cdk.BundlingOptions {
8686
private readonly packageManager: PackageManager;
8787

8888
constructor(private readonly props: BundlingProps) {
89-
this.packageManager = PackageManager.fromLockFile(props.depsLockFilePath);
89+
this.packageManager = PackageManager.fromLockFile(props.depsLockFilePath, props.logLevel);
9090

9191
Bundling.esbuildInstallation = Bundling.esbuildInstallation ?? PackageInstallation.detect('esbuild');
9292
Bundling.tscInstallation = Bundling.tscInstallation ?? PackageInstallation.detect('tsc');

packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as path from 'path';
33
import * as lambda from '@aws-cdk/aws-lambda';
44
import { Architecture } from '@aws-cdk/aws-lambda';
55
import { Bundling } from './bundling';
6-
import { PackageManager } from './package-manager';
6+
import { LockFile } from './package-manager';
77
import { BundlingOptions } from './types';
88
import { callsites, findUpMultiple } from './util';
99

@@ -138,9 +138,9 @@ function findLockFile(depsLockFilePath?: string): string {
138138
}
139139

140140
const lockFiles = findUpMultiple([
141-
PackageManager.PNPM.lockFile,
142-
PackageManager.YARN.lockFile,
143-
PackageManager.NPM.lockFile,
141+
LockFile.PNPM,
142+
LockFile.YARN,
143+
LockFile.NPM,
144144
]);
145145

146146
if (lockFiles.length === 0) {

packages/@aws-cdk/aws-lambda-nodejs/lib/package-manager.ts

+34-28
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,54 @@
11
import * as os from 'os';
22
import * as path from 'path';
3+
import { LogLevel } from './types';
34

45
interface PackageManagerProps {
56
readonly lockFile: string;
67
readonly installCommand: string[];
78
readonly runCommand: string[];
8-
readonly argsSeparator?: string
9+
readonly argsSeparator?: string;
10+
}
11+
12+
export enum LockFile {
13+
NPM = 'package-lock.json',
14+
YARN = 'yarn.lock',
15+
PNPM = 'pnpm-lock.yaml',
916
}
1017

1118
/**
1219
* A node package manager
1320
*/
1421
export class PackageManager {
15-
public static NPM = new PackageManager({
16-
lockFile: 'package-lock.json',
17-
installCommand: ['npm', 'ci'],
18-
runCommand: ['npx', '--no-install'],
19-
});
20-
21-
public static YARN = new PackageManager({
22-
lockFile: 'yarn.lock',
23-
installCommand: ['yarn', 'install', '--no-immutable'],
24-
runCommand: ['yarn', 'run'],
25-
});
26-
27-
public static PNPM = new PackageManager({
28-
lockFile: 'pnpm-lock.yaml',
29-
installCommand: ['pnpm', 'install'],
30-
runCommand: ['pnpm', 'exec'],
31-
argsSeparator: '--',
32-
});
33-
34-
public static fromLockFile(lockFilePath: string): PackageManager {
22+
/**
23+
* Use a lock file path to determine the package manager to use. Optionally, specify a log level to
24+
* control its verbosity.
25+
* @param lockFilePath Path of the lock file
26+
* @param logLevel optional log level @default LogLevel.INFO
27+
* @returns the right PackageManager for that lock file
28+
*/
29+
public static fromLockFile(lockFilePath: string, logLevel?: LogLevel): PackageManager {
3530
const lockFile = path.basename(lockFilePath);
3631

3732
switch (lockFile) {
38-
case PackageManager.NPM.lockFile:
39-
return PackageManager.NPM;
40-
case PackageManager.YARN.lockFile:
41-
return PackageManager.YARN;
42-
case PackageManager.PNPM.lockFile:
43-
return PackageManager.PNPM;
33+
case LockFile.YARN:
34+
return new PackageManager({
35+
lockFile: LockFile.YARN,
36+
installCommand: logLevel && logLevel !== LogLevel.INFO ? ['yarn', 'install', '--no-immutable', '--silent'] : ['yarn', 'install', '--no-immutable'],
37+
runCommand: ['yarn', 'run'],
38+
});
39+
case LockFile.PNPM:
40+
return new PackageManager({
41+
lockFile: LockFile.PNPM,
42+
installCommand: logLevel && logLevel !== LogLevel.INFO ? ['pnpm', 'install', '--reporter', 'silent'] : ['pnpm', 'install'],
43+
runCommand: ['pnpm', 'exec'],
44+
argsSeparator: '--',
45+
});
4446
default:
45-
return PackageManager.NPM;
47+
return new PackageManager({
48+
lockFile: LockFile.NPM,
49+
installCommand: logLevel ? ['npm', 'ci', '--loglevel', logLevel] : ['npm', 'ci'],
50+
runCommand: ['npx', '--no-install'],
51+
});
4652
}
4753
}
4854

packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ export interface BundlingOptions {
5959
readonly loader?: { [ext: string]: string };
6060

6161
/**
62-
* Log level for esbuild
62+
* Log level for esbuild. This is also propagated to the package manager and
63+
* applies to its specific install command.
6364
*
6465
* @default LogLevel.WARNING
6566
*/
@@ -340,7 +341,7 @@ export interface ICommandHooks {
340341
}
341342

342343
/**
343-
* Log level for esbuild
344+
* Log levels for esbuild and package managers' install commands.
344345
*/
345346
export enum LogLevel {
346347
/** Show everything */

packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,7 @@ test('Local bundling', () => {
422422
environment: {
423423
KEY: 'value',
424424
},
425+
logLevel: LogLevel.ERROR,
425426
});
426427

427428
expect(bundler.local).toBeDefined();

packages/@aws-cdk/aws-lambda-nodejs/test/package-manager.test.ts

+32-6
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,62 @@
11
import * as os from 'os';
2-
import { PackageManager } from '../lib/package-manager';
2+
import { LogLevel } from '../lib';
3+
import { LockFile, PackageManager } from '../lib/package-manager';
34

45
test('from a package-lock.json', () => {
56
const packageManager = PackageManager.fromLockFile('/path/to/package-lock.json');
6-
expect(packageManager).toEqual(PackageManager.NPM);
7+
expect(packageManager.lockFile).toEqual(LockFile.NPM);
8+
expect(packageManager.argsSeparator).toBeUndefined();
9+
expect(packageManager.installCommand).toEqual(['npm', 'ci']);
10+
expect(packageManager.runCommand).toEqual(['npx', '--no-install']);
711

812
expect(packageManager.runBinCommand('my-bin')).toBe('npx --no-install my-bin');
913
});
1014

15+
test('from a package-lock.json with LogLevel.ERROR', () => {
16+
const logLevel = LogLevel.ERROR;
17+
const packageManager = PackageManager.fromLockFile('/path/to/package-lock.json', logLevel);
18+
expect(packageManager.installCommand).toEqual(['npm', 'ci', '--loglevel', logLevel]);
19+
});
20+
1121
test('from a yarn.lock', () => {
1222
const packageManager = PackageManager.fromLockFile('/path/to/yarn.lock');
13-
expect(packageManager).toEqual(PackageManager.YARN);
23+
expect(packageManager.lockFile).toEqual(LockFile.YARN);
24+
expect(packageManager.argsSeparator).toBeUndefined();
25+
expect(packageManager.installCommand).toEqual(['yarn', 'install', '--no-immutable']);
26+
expect(packageManager.runCommand).toEqual(['yarn', 'run']);
1427

1528
expect(packageManager.runBinCommand('my-bin')).toBe('yarn run my-bin');
1629
});
1730

31+
test('from a yarn.lock with LogLevel.ERROR', () => {
32+
const packageManager = PackageManager.fromLockFile('/path/to/yarn.lock', LogLevel.ERROR);
33+
expect(packageManager.installCommand).toEqual(['yarn', 'install', '--no-immutable', '--silent']);
34+
});
35+
1836
test('from a pnpm-lock.yaml', () => {
1937
const packageManager = PackageManager.fromLockFile('/path/to/pnpm-lock.yaml');
20-
expect(packageManager).toEqual(PackageManager.PNPM);
38+
expect(packageManager.lockFile).toEqual(LockFile.PNPM);
39+
expect(packageManager.argsSeparator).toEqual('--');
40+
expect(packageManager.installCommand).toEqual(['pnpm', 'install']);
41+
expect(packageManager.runCommand).toEqual(['pnpm', 'exec']);
2142

2243
expect(packageManager.runBinCommand('my-bin')).toBe('pnpm exec -- my-bin');
2344
});
2445

46+
test('from a pnpm-lock.yaml with LogLevel.ERROR', () => {
47+
const packageManager = PackageManager.fromLockFile('/path/to/pnpm-lock.yaml', LogLevel.ERROR);
48+
expect(packageManager.installCommand).toEqual(['pnpm', 'install', '--reporter', 'silent']);
49+
});
50+
2551
test('defaults to NPM', () => {
2652
const packageManager = PackageManager.fromLockFile('/path/to/other.lock');
27-
expect(packageManager).toEqual(PackageManager.NPM);
53+
expect(packageManager.lockFile).toEqual(LockFile.NPM);
2854
});
2955

3056
test('Windows', () => {
3157
const osPlatformMock = jest.spyOn(os, 'platform').mockReturnValue('win32');
3258

33-
const packageManager = PackageManager.NPM;
59+
const packageManager = PackageManager.fromLockFile('/path/to/whatever');
3460
expect(packageManager.runBinCommand('my-bin')).toEqual('npx.cmd --no-install my-bin');
3561

3662
osPlatformMock.mockRestore();

0 commit comments

Comments
 (0)