Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SCANNPM-52 Fix scanner archive directory when having an architecture #174

Merged
merged 1 commit into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
32 changes: 17 additions & 15 deletions src/scanner-cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { AxiosRequestConfig } from 'axios';
import { spawn } from 'child_process';
import fsExtra from 'fs-extra';
import path from 'path';
import semver from 'semver';
import {
ENV_TO_PROPERTY_NAME,
ENV_VAR_PREFIX,
Expand All @@ -33,8 +35,6 @@ import { isLinux, isMac, isWindows } from './platform';
import { proxyUrlToJavaOptions } from './proxy';
import { download } from './request';
import { ScanOptions, ScannerProperties, ScannerProperty } from './types';
import { AxiosRequestConfig } from 'axios';
import semver from 'semver';

export function normalizePlatformName(): 'windows' | 'linux' | 'macosx' {
if (isWindows()) {
Expand All @@ -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';
const archSuffix = archStr ? `-${archStr}` : '';
const scannerCliFileName = `sonar-scanner-cli-${versionStr}-${normalizePlatformName()}${archSuffix}.zip`;
return new URL(scannerCliFileName, scannerCliMirror);
}

export async function downloadScannerCli(properties: ScannerProperties): Promise<string> {
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;
const 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}`);
Expand All @@ -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 = {
Expand Down
73 changes: 65 additions & 8 deletions test/unit/scanner-cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
});
Expand All @@ -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));
Expand All @@ -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');
Expand All @@ -86,23 +109,57 @@ 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(
`https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SCANNER_CLI_VERSION}-linux-x64.zip`,
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,
);
expect(extractArchive).toHaveBeenLastCalledWith(
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),
);
Expand All @@ -121,23 +178,23 @@ 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,
);
expect(extractArchive).toHaveBeenLastCalledWith(
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),
);
expect(binPath).toBe(
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`,
),
);

Expand All @@ -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=' } },
);
Expand Down