diff --git a/package-lock.json b/package-lock.json index a70cb28..11cd805 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "sonarqube-scanner", - "version": "4.2.4", + "version": "4.2.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "sonarqube-scanner", - "version": "4.2.4", + "version": "4.2.5", "license": "LGPL-3.0-only", "dependencies": { "adm-zip": "0.5.12", diff --git a/package.json b/package.json index 588555d..2f2e47a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "sonarqube-scanner", "description": "SonarQube/SonarCloud Scanner for the JavaScript world", - "version": "4.2.4", + "version": "4.2.5", "homepage": "https://github.com/SonarSource/sonar-scanner-npm", "author": { "name": "Fabrice Bellingard", diff --git a/src/scanner-cli.ts b/src/scanner-cli.ts index 8a40947..5fe96b8 100644 --- a/src/scanner-cli.ts +++ b/src/scanner-cli.ts @@ -52,31 +52,33 @@ export function normalizePlatformName(): 'windows' | 'linux' | 'macosx' { /** * Where to download the SonarScanner CLI */ -function getScannerCliUrl(properties: ScannerProperties, versionStr: string): URL { +function getScannerCliUrl( + properties: ScannerProperties, + versionStr: string, + archStr?: string, +): URL { // Get location to download scanner-cli from // Not in default to avoid populating it for non scanner-cli users const scannerCliMirror = properties[ScannerProperty.SonarScannerCliMirror] ?? SCANNER_CLI_MIRROR; - const version = semver.coerce(versionStr); - if (!version) { - throw new Error(`Version "${versionStr}" does not have a correct format."`); - } - const arch = version.compare('6.1.0') >= 0 ? '-x64' : ''; - const scannerCliFileName = - 'sonar-scanner-cli-' + versionStr + '-' + normalizePlatformName() + arch + '.zip'; + let archSuffix = archStr ? `-${archStr}` : ''; + const scannerCliFileName = `sonar-scanner-cli-${versionStr}-${normalizePlatformName()}${archSuffix}.zip`; return new URL(scannerCliFileName, scannerCliMirror); } export async function downloadScannerCli(properties: ScannerProperties): Promise { - const version = properties[ScannerProperty.SonarScannerCliVersion] ?? SCANNER_CLI_VERSION; - if (!/^[\d.]+$/.test(version)) { - throw new Error(`Version "${version}" does not have a correct format."`); + const versionStr = properties[ScannerProperty.SonarScannerCliVersion] ?? SCANNER_CLI_VERSION; + const version = semver.coerce(versionStr); + if (!version) { + throw new Error(`Version "${versionStr}" does not have a correct format."`); } + const archStr = version.compare('6.1.0') >= 0 ? 'x64' : undefined; + let archSuffix = archStr ? `-${archStr}` : ''; // Build paths const binExt = normalizePlatformName() === 'windows' ? '.bat' : ''; - const dirName = `sonar-scanner-${version}-${normalizePlatformName()}`; + const dirName = `sonar-scanner-${versionStr}-${normalizePlatformName()}${archSuffix}`; const installDir = path.join(properties[ScannerProperty.SonarUserHome], SCANNER_CLI_INSTALL_PATH); const archivePath = path.join(installDir, `${dirName}.zip`); const binPath = path.join(installDir, dirName, 'bin', `sonar-scanner${binExt}`); @@ -89,7 +91,7 @@ export async function downloadScannerCli(properties: ScannerProperties): Promise await fsExtra.ensureDir(installDir); // Add basic auth credentials when used in the UR - const scannerCliUrl = getScannerCliUrl(properties, version); + const scannerCliUrl = getScannerCliUrl(properties, versionStr, archStr); let overrides: AxiosRequestConfig | undefined; if (scannerCliUrl.username && scannerCliUrl.password) { overrides = { diff --git a/test/unit/scanner-cli.test.ts b/test/unit/scanner-cli.test.ts index e549ec7..6537a3e 100644 --- a/test/unit/scanner-cli.test.ts +++ b/test/unit/scanner-cli.test.ts @@ -47,6 +47,14 @@ const MOCK_PROPERTIES = { [ScannerProperty.SonarScannerCliVersion]: SCANNER_CLI_VERSION, }; +const SCANNER_CLI_VERSION_NO_ARCH = '6.0.0'; +const MOCK_PROPERTIES_NO_ARCH = { + [ScannerProperty.SonarToken]: 'token', + [ScannerProperty.SonarHostUrl]: 'http://localhost:9000', + [ScannerProperty.SonarUserHome]: 'path/to/user/home', + [ScannerProperty.SonarScannerCliVersion]: SCANNER_CLI_VERSION_NO_ARCH, +}; + beforeEach(() => { childProcessHandler.reset(); }); @@ -65,7 +73,7 @@ describe('scanner-cli', () => { const scannerBinPath = path.join( MOCK_PROPERTIES[ScannerProperty.SonarUserHome], SCANNER_CLI_INSTALL_PATH, - `sonar-scanner-${SCANNER_CLI_VERSION}-linux/bin/sonar-scanner`, + `sonar-scanner-${SCANNER_CLI_VERSION}-linux-x64/bin/sonar-scanner`, ); const stub = sinon.stub(process, 'platform').value('linux'); jest.spyOn(fsExtra, 'exists').mockImplementation(_path => Promise.resolve(true)); @@ -76,6 +84,21 @@ describe('scanner-cli', () => { stub.restore(); }); + it('should use already downloaded version without arch', async () => { + const scannerBinPath = path.join( + MOCK_PROPERTIES_NO_ARCH[ScannerProperty.SonarUserHome], + SCANNER_CLI_INSTALL_PATH, + `sonar-scanner-${SCANNER_CLI_VERSION_NO_ARCH}-linux/bin/sonar-scanner`, + ); + const stub = sinon.stub(process, 'platform').value('linux'); + jest.spyOn(fsExtra, 'exists').mockImplementation(_path => Promise.resolve(true)); + + expect(await downloadScannerCli(MOCK_PROPERTIES_NO_ARCH)).toBe(scannerBinPath); + expect(download).not.toHaveBeenCalled(); + + stub.restore(); + }); + it('should download SonarScanner CLI if it does not exist on Unix', async () => { jest.spyOn(fsExtra, 'exists').mockImplementation(_path => Promise.resolve(false)); const stub = sinon.stub(process, 'platform').value('linux'); @@ -86,7 +109,7 @@ describe('scanner-cli', () => { path.join( MOCK_PROPERTIES[ScannerProperty.SonarUserHome], SCANNER_CLI_INSTALL_PATH, - `sonar-scanner-${SCANNER_CLI_VERSION}-linux/bin/sonar-scanner`, + `sonar-scanner-${SCANNER_CLI_VERSION}-linux-x64/bin/sonar-scanner`, ), ); expect(download).toHaveBeenLastCalledWith( @@ -94,7 +117,7 @@ describe('scanner-cli', () => { path.join( MOCK_PROPERTIES[ScannerProperty.SonarUserHome], SCANNER_CLI_INSTALL_PATH, - `sonar-scanner-${SCANNER_CLI_VERSION}-linux.zip`, + `sonar-scanner-${SCANNER_CLI_VERSION}-linux-x64.zip`, ), undefined, ); @@ -102,7 +125,41 @@ describe('scanner-cli', () => { path.join( MOCK_PROPERTIES[ScannerProperty.SonarUserHome], SCANNER_CLI_INSTALL_PATH, - `sonar-scanner-${SCANNER_CLI_VERSION}-linux.zip`, + `sonar-scanner-${SCANNER_CLI_VERSION}-linux-x64.zip`, + ), + path.join(MOCK_PROPERTIES[ScannerProperty.SonarUserHome], SCANNER_CLI_INSTALL_PATH), + ); + + stub.restore(); + }); + + it('should download SonarScanner CLI if it does not exist on Unix without arch', async () => { + jest.spyOn(fsExtra, 'exists').mockImplementation(_path => Promise.resolve(false)); + const stub = sinon.stub(process, 'platform').value('linux'); + + const binPath = await downloadScannerCli(MOCK_PROPERTIES_NO_ARCH); + + expect(binPath).toBe( + path.join( + MOCK_PROPERTIES_NO_ARCH[ScannerProperty.SonarUserHome], + SCANNER_CLI_INSTALL_PATH, + `sonar-scanner-${SCANNER_CLI_VERSION_NO_ARCH}-linux/bin/sonar-scanner`, + ), + ); + expect(download).toHaveBeenLastCalledWith( + `https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SCANNER_CLI_VERSION_NO_ARCH}-linux.zip`, + path.join( + MOCK_PROPERTIES_NO_ARCH[ScannerProperty.SonarUserHome], + SCANNER_CLI_INSTALL_PATH, + `sonar-scanner-${SCANNER_CLI_VERSION_NO_ARCH}-linux.zip`, + ), + undefined, + ); + expect(extractArchive).toHaveBeenLastCalledWith( + path.join( + MOCK_PROPERTIES_NO_ARCH[ScannerProperty.SonarUserHome], + SCANNER_CLI_INSTALL_PATH, + `sonar-scanner-${SCANNER_CLI_VERSION_NO_ARCH}-linux.zip`, ), path.join(MOCK_PROPERTIES[ScannerProperty.SonarUserHome], SCANNER_CLI_INSTALL_PATH), ); @@ -121,7 +178,7 @@ describe('scanner-cli', () => { path.join( MOCK_PROPERTIES[ScannerProperty.SonarUserHome], SCANNER_CLI_INSTALL_PATH, - `sonar-scanner-${SCANNER_CLI_VERSION}-windows.zip`, + `sonar-scanner-${SCANNER_CLI_VERSION}-windows-x64.zip`, ), undefined, ); @@ -129,7 +186,7 @@ describe('scanner-cli', () => { path.join( MOCK_PROPERTIES[ScannerProperty.SonarUserHome], SCANNER_CLI_INSTALL_PATH, - `sonar-scanner-${SCANNER_CLI_VERSION}-windows.zip`, + `sonar-scanner-${SCANNER_CLI_VERSION}-windows-x64.zip`, ), path.join(MOCK_PROPERTIES[ScannerProperty.SonarUserHome], SCANNER_CLI_INSTALL_PATH), ); @@ -137,7 +194,7 @@ describe('scanner-cli', () => { path.join( MOCK_PROPERTIES[ScannerProperty.SonarUserHome], SCANNER_CLI_INSTALL_PATH, - `sonar-scanner-${SCANNER_CLI_VERSION}-windows/bin/sonar-scanner.bat`, + `sonar-scanner-${SCANNER_CLI_VERSION}-windows-x64/bin/sonar-scanner.bat`, ), ); @@ -157,7 +214,7 @@ describe('scanner-cli', () => { path.join( MOCK_PROPERTIES[ScannerProperty.SonarUserHome], SCANNER_CLI_INSTALL_PATH, - `sonar-scanner-${SCANNER_CLI_VERSION}-windows.zip`, + `sonar-scanner-${SCANNER_CLI_VERSION}-windows-x64.zip`, ), { headers: { Authorization: 'Basic bXlVc2VyOm15UGFzc3dvcmQ=' } }, );