Skip to content

Commit a5b364a

Browse files
authored
Merge pull request #2461 from Automattic/fix/sonarcloud
fix: code smells detected by SonarCloud
2 parents 5a77ecc + 41b68bd commit a5b364a

File tree

10 files changed

+83
-70
lines changed

10 files changed

+83
-70
lines changed

__tests__/lib/cli/config.js

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1+
import fs from 'node:fs';
2+
3+
import { loadConfigFile } from '../../../src/lib/cli/config';
4+
15
describe( 'utils/cli/config', () => {
2-
beforeEach( () => {
3-
jest.resetModules();
4-
jest.clearAllMocks();
6+
afterEach( () => {
7+
jest.restoreAllMocks();
58
} );
9+
610
it.each( [
711
{
812
description: 'should return development if config.local.json is present',
@@ -17,28 +21,26 @@ describe( 'utils/cli/config', () => {
1721
{
1822
description: 'should throw error if config.local.json and config.publish.json are missing',
1923
files: { local: false, publish: false },
20-
expected: Error,
24+
expected: null,
2125
},
2226
] )( '$description', ( { files, expected } ) => {
23-
// An array of files would've been nicer but it doesn't play well with jest.doMock
24-
if ( ! files.local ) {
25-
jest.doMock( '../../../config/config.local.json', () => {
26-
throw new Error();
27-
} );
28-
}
29-
if ( ! files.publish ) {
30-
jest.doMock( '../../../config/config.publish.json', () => {
27+
const origReadFileSync = fs.readFileSync;
28+
jest.spyOn( fs, 'readFileSync' ).mockImplementation( ( filePath, ...params ) => {
29+
if ( typeof filePath !== 'string' || ! filePath.includes( 'config.' ) ) {
30+
return origReadFileSync( filePath, ...params );
31+
}
32+
33+
if (
34+
( filePath.includes( 'config.local.json' ) && ! files.local ) ||
35+
( filePath.includes( 'config.publish.json' ) && ! files.publish )
36+
) {
3137
throw new Error();
32-
} );
33-
}
38+
}
39+
40+
return JSON.stringify( expected );
41+
} );
3442

35-
if ( ! files.local && ! files.publish ) {
36-
// eslint-disable-next-line jest/no-conditional-expect
37-
expect( () => require( '../../../src/lib/cli/config' ) ).toThrow( expected );
38-
} else {
39-
const config = require( '../../../src/lib/cli/config' );
40-
// eslint-disable-next-line jest/no-conditional-expect
41-
expect( config.default ).toMatchObject( expected );
42-
}
43+
const actual = loadConfigFile();
44+
expect( actual ).toStrictEqual( expected );
4345
} );
4446
} );

src/bin/vip-app.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,10 @@ command( { requiredArgs: 1, format: true } )
7070
await trackEvent( 'app_command_success' );
7171

7272
// Clone the read-only response object so we can modify it
73-
const clonedResponse = Object.assign( {}, res );
73+
const clonedResponse = { ...res };
7474

7575
clonedResponse.environments = clonedResponse.environments.map( env => {
76-
const clonedEnv = Object.assign( {}, env );
76+
const clonedEnv = { ...env };
7777

7878
clonedEnv.name = getEnvIdentifier( env );
7979

src/bin/vip-import-sql.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,8 @@ function isValidMd5( md5 ) {
113113
}
114114

115115
/**
116-
* @param {AppForImport} app
117-
* @param {EnvForImport} env
116+
* @param {import('../lib/site-import/db-file-import').AppForImport} app
117+
* @param {import('../lib/site-import/db-file-import').EnvForImport} env
118118
* @param {string} fileNameOrURL
119119
* @param {boolean} isUrl
120120
* @param {string|null} md5
@@ -427,7 +427,7 @@ const displayPlaybook = ( {
427427
}
428428
};
429429

430-
void command( {
430+
command( {
431431
appContext: true,
432432
appQuery,
433433
envContext: true,

src/commands/phpmyadmin.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,13 @@ export class PhpMyAdminCommand {
148148
this.progressTracker.stopPrinting();
149149
}
150150

151-
public async openUrl( url: string ): Promise< void > {
151+
public async openUrl( url: string ): Promise< unknown > {
152152
const { default: open } = await import( 'open' );
153-
void open( url, { wait: false } );
153+
return open( url, { wait: false } );
154154
}
155155

156156
public async getStatus(): Promise< string > {
157-
return await getPhpMyAdminStatus( this.app.id as number, this.env.id as number );
157+
return getPhpMyAdminStatus( this.app.id as number, this.env.id as number );
158158
}
159159

160160
private async maybeEnablePhpMyAdmin(): Promise< void > {

src/lib/cli/command.js

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -374,21 +374,19 @@ args.argv = async function ( argv, cb ) {
374374
}
375375

376376
// Negotiate flag values
377-
switch ( _opts.module ) {
378-
case 'import-media':
379-
if ( [ true, 'true', 'yes' ].includes( options.saveErrorLog ) ) {
380-
options.saveErrorLog = 'true';
381-
} else if ( [ false, 'false', 'no' ].includes( options.saveErrorLog ) ) {
382-
options.saveErrorLog = 'false';
383-
} else {
384-
options.saveErrorLog = 'prompt';
385-
}
386-
break;
377+
if ( _opts.module === 'import-media' ) {
378+
if ( [ true, 'true', 'yes' ].includes( options.saveErrorLog ) ) {
379+
options.saveErrorLog = 'true';
380+
} else if ( [ false, 'false', 'no' ].includes( options.saveErrorLog ) ) {
381+
options.saveErrorLog = 'false';
382+
} else {
383+
options.saveErrorLog = 'prompt';
384+
}
387385
}
388386

389387
// Prompt for confirmation if necessary
390388
if ( _opts.requireConfirm && ! options.force ) {
391-
/** @type {Tuple[]} */
389+
/** @type {import('./format').Tuple[]} */
392390
const info = [];
393391

394392
if ( options.app ) {

src/lib/cli/config.ts

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import debugLib from 'debug';
2+
import { readFileSync } from 'node:fs'; // I don't like using synchronous versions, but until we migrate to ESM, we have to.
3+
import path from 'node:path';
24

35
interface Config {
46
tracksUserType: string;
@@ -9,19 +11,35 @@ interface Config {
911

1012
const debug = debugLib( '@automattic/vip:lib:cli:config' );
1113

12-
let configFromFile: Config;
13-
try {
14-
// Get `local` config first; this will only exist in dev as it's npmignore-d.
15-
// eslint-disable-next-line @typescript-eslint/no-var-requires
16-
configFromFile = require( '../../../config/config.local.json' ) as Config;
14+
export function loadConfigFile(): Config | null {
15+
const paths = [
16+
// Get `local` config first; this will only exist in dev as it's npmignore-d.
17+
path.join( __dirname, '../../../config/config.local.json' ),
18+
path.join( __dirname, '../../../config/config.publish.json' ),
19+
];
1720

18-
debug( 'Loaded config data from config.local.json' );
19-
} catch {
20-
// Fall back to `publish` config file.
21-
// eslint-disable-next-line @typescript-eslint/no-var-requires
22-
configFromFile = require( '../../../config/config.publish.json' ) as Config;
21+
for ( const filePath of paths ) {
22+
try {
23+
const data = readFileSync( filePath, 'utf-8' );
24+
debug( `Found config file at ${ filePath }` );
25+
return JSON.parse( data ) as Config;
26+
} catch ( err ) {
27+
if ( ! ( err instanceof Error ) || ! ( 'code' in err ) || err.code !== 'ENOENT' ) {
28+
debug( `Error reading config file at ${ filePath }:`, err );
29+
}
30+
}
31+
}
2332

24-
debug( 'Loaded config data from config.publish.json' );
33+
return null;
2534
}
2635

27-
export default configFromFile;
36+
const configFromFile = loadConfigFile();
37+
if ( null === configFromFile ) {
38+
// This should not happen because `config/config.publish.json` is always present.
39+
console.error( 'FATAL ERROR: Could not find a valid configuration file' );
40+
process.exit( 1 );
41+
}
42+
43+
// Without this, TypeScript will export `configFromFile` as `Config | null`
44+
const exportedConfig: Config = configFromFile;
45+
export default exportedConfig;

src/lib/cli/format.ts

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -118,17 +118,10 @@ export function keyValue( values: Tuple[] ): string {
118118

119119
for ( const { key, value } of values ) {
120120
let formattedValue: string;
121-
122-
switch (
123-
key.toLowerCase() // NOSONAR
124-
) {
125-
case 'environment':
126-
formattedValue = formatEnvironment( value );
127-
break;
128-
129-
default:
130-
formattedValue = value;
131-
break;
121+
if ( key.toLowerCase() === 'environment' ) {
122+
formattedValue = formatEnvironment( value );
123+
} else {
124+
formattedValue = value;
132125
}
133126

134127
lines.push( `+ ${ key }: ${ formattedValue }` );

src/lib/config/software.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,8 @@ export const formatSoftwareSettings = (
441441
.map( option => option.value );
442442

443443
if ( format !== 'json' ) {
444-
result.available_versions = result.available_versions.sort().join( ',' );
444+
result.available_versions.sort( ( lhs, rhs ) => lhs.localeCompare( rhs ) );
445+
result.available_versions = result.available_versions.join( ',' );
445446
}
446447
}
447448

src/lib/keychain.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,20 @@ import Insecure from './keychain/insecure';
44

55
import type { Keychain, KeychainConstructor } from './keychain/keychain';
66

7-
let exportValue: Keychain;
7+
let keychain: Keychain;
88
const debug = debugLib( '@automattic/vip:keychain' );
99

1010
try {
1111
// Try using Secure keychain ("keytar") first
1212
// eslint-disable-next-line @typescript-eslint/no-var-requires
1313
const Secure = require( './keychain/secure' ) as KeychainConstructor;
14-
exportValue = new Secure();
14+
keychain = new Secure();
1515
} catch ( error ) {
1616
debug( 'Cannot use Secure keychain; falling back to Insecure keychain (Details: %o)', error );
1717

1818
// Fallback to Insecure keychain if we can't
19-
exportValue = new Insecure( 'vip-go-cli' );
19+
keychain = new Insecure( 'vip-go-cli' );
2020
}
2121

22-
export default exportValue;
22+
const exportedKeychain = keychain;
23+
export default exportedKeychain;

src/lib/validations/line-by-line.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export async function fileLineValidations(
6565
return Promise.all(
6666
validations.map( ( validation: PerLineValidationObject ) => {
6767
if (
68-
Object.prototype.hasOwnProperty.call( validation, 'postLineExecutionProcessing' ) &&
68+
Object.hasOwn( validation, 'postLineExecutionProcessing' ) &&
6969
typeof validation.postLineExecutionProcessing === 'function'
7070
) {
7171
return validation.postLineExecutionProcessing( {

0 commit comments

Comments
 (0)