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

feat(sonar-scanner): Allow users to specify the dotnet-scanner version #486

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
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
9 changes: 3 additions & 6 deletions setup-gcloud/test/setup-gcloud.test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const path = require('path');

const mockFs = require('mock-fs');

// Mock out tools download
Expand All @@ -10,7 +12,6 @@ jest.mock('@actions/core');

const core = require('@actions/core');
const exec = require('@actions/exec');
const os = require('os');
const setupGcloud = require('../src/setup-gcloud');

const jsonKey = {
Expand Down Expand Up @@ -72,10 +73,6 @@ describe('Setup Gcloud', () => {
exec.exec.mockResolvedValueOnce(0);
await setupGcloud(base64Key, 'latest', true);
expect(core.exportVariable.mock.calls[0][0]).toEqual('GOOGLE_APPLICATION_CREDENTIALS');
if (os.platform() === 'win32') {
expect(core.exportVariable.mock.calls[0][1]).toContain('\\workspace\\');
} else {
expect(core.exportVariable.mock.calls[0][1]).toContain('/workspace/');
}
expect(core.exportVariable.mock.calls[0][1]).toContain(`${path.sep}workspace${path.sep}`);
});
});
2 changes: 2 additions & 0 deletions sonar-scanner/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ inputs:
description: |
The sonar scanner to use. Valid values are 'auto', 'maven', 'gradle', 'node' and 'dotnet'.
The default value 'auto' will attempt to perform auto-discovery. Auto-discovery does not work for 'dotnet'.
For 'dotnet' it is possible to pin the scanner to a specific version, for example 'dotnet-5.6.0'. Only pin the
dotnet scanner version if you are using an old dotnet version that is no longer supported by the latest version.
required: true
default: auto
main-branch:
Expand Down
20 changes: 14 additions & 6 deletions sonar-scanner/dist/index.js

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

4 changes: 2 additions & 2 deletions sonar-scanner/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ const action = async () => {

let waitForQualityGate = false;

if (sonarScanner === 'dotnet') {
if (sonarScanner.startsWith('dotnet')) {
// MSBuild scanning
waitForQualityGate = await scanMsBuild(hostUrl, mainBranch, scanCommands.dotnet);
waitForQualityGate = await scanMsBuild(hostUrl, mainBranch, sonarScanner, scanCommands.dotnet);
} else {
// Perform the scanning for everything else.
await core.group('Run Sonar analysis', async () => scan(hostUrl, mainBranch, sonarScanner, scanCommands));
Expand Down
16 changes: 12 additions & 4 deletions sonar-scanner/src/scan-msbuild.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,17 @@ const scanWithJavaHome = async (args) => {
return exec.exec(scanner, args, { env });
};

const beginScan = async (hostUrl, mainBranch, customArgs = '') => {
const beginScan = async (hostUrl, mainBranch, sonarScanner, customArgs = '') => {
await core.group('Install dotnet-sonarscanner', async () => {
await exec.exec(`dotnet tool install -g dotnet-sonarscanner ${hostUrl.startsWith('https://sonar.extenda.io') ? '--version 4.10.0' : ''}`);
const [, scannerVersion = ''] = sonarScanner.split('-');
let versionArg = '';
if (scannerVersion !== '') {
core.warning(`Using pinned dotnet-scanner version ${scannerVersion}`);
versionArg = `--version ${scannerVersion}`;
} else if (hostUrl.startsWith('https://sonar.extenda.io')) {
versionArg = '--version 4.10.0';
}
await exec.exec(`dotnet tool install -g dotnet-sonarscanner ${versionArg}`);
});

const version = await getBuildVersion(`-${process.env.GITHUB_SHA}`);
Expand All @@ -66,11 +74,11 @@ const finishScan = async (hostUrl) => {
});
};

const scanMsBuild = async (hostUrl, mainBranch, customArgs = '') => {
const scanMsBuild = async (hostUrl, mainBranch, sonarScanner, customArgs = '') => {
if (!fs.existsSync(markerFile)) {
// Create marker and begin scan
fs.closeSync(fs.openSync(markerFile, 'w'));
await beginScan(hostUrl, mainBranch, customArgs);
await beginScan(hostUrl, mainBranch, sonarScanner, customArgs);
return false;
}

Expand Down
2 changes: 1 addition & 1 deletion sonar-scanner/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ describe('Sonar-Scanner Action', () => {
checkQualityGate.mockResolvedValueOnce(0);
scanMsBuild.mockResolvedValueOnce(true);
await action();
expect(scanMsBuild).toHaveBeenCalledWith('https://sonarcloud.io', 'master', '');
expect(scanMsBuild).toHaveBeenCalledWith('https://sonarcloud.io', 'master', 'dotnet', '');
expect(checkQualityGate).toHaveBeenCalled();
});

Expand Down
69 changes: 44 additions & 25 deletions sonar-scanner/test/scan-msbuild.test.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
const mockFs = require('mock-fs');
const exec = require('@actions/exec');
const path = require('path');
const fs = require('fs');
const os = require('os');
const { getBuildVersion } = require('../../utils/src/versions');

jest.mock('@actions/exec');

jest.mock('../src/sonar-credentials');
jest.mock('../../utils/src/pull-request-info');
jest.mock('../../utils/src/versions');

const { scanMsBuild, markerFile } = require('../src/scan-msbuild');

Expand All @@ -20,18 +22,18 @@ describe('Scan MSBuild', () => {
process.env.GITHUB_REPOSITORY = 'extenda/actions';
process.env.SONAR_TOKEN = 'x';
process.env.GITHUB_EVENT_PATH = path.join(__dirname, 'push-event.json');
getBuildVersion.mockReturnValueOnce('0.0.1-local');
});

afterEach(() => {
if (fs.existsSync(markerFile)) {
fs.unlinkSync(markerFile);
}
mockFs.restore();
process.env = orgEnv;
jest.resetAllMocks();
});

test('It begins to scan when marker file is missing', async () => {
const output = await scanMsBuild('https://sonar.extenda.io', 'master');
mockFs({});
const output = await scanMsBuild('https://sonar.extenda.io', 'master', 'dotnet');
expect(output).toEqual(false);
expect(fs.existsSync(markerFile)).toEqual(true);
expect(exec.exec.mock.calls.length).toEqual(2);
Expand All @@ -40,11 +42,19 @@ describe('Scan MSBuild', () => {
expect(exec.exec.mock.calls[1][0]).toContain('begin');
});

test('It can install a pinned dotnet-scanner version', async () => {
mockFs({});
await scanMsBuild('https://sonarcloud.io', 'master', 'dotnet-5.6.0');
expect(exec.exec.mock.calls[0][0]).toEqual('dotnet tool install -g dotnet-sonarscanner --version 5.6.0');
});

test('It ends scan when marker file exists', async () => {
// Create marker file
fs.closeSync(fs.openSync(markerFile, 'w'));
const files = {};
files[markerFile] = '';
mockFs(files);

const output = await scanMsBuild('https://sonar.extenda.io', 'master');
const output = await scanMsBuild('https://sonar.extenda.io', 'master', 'dotnet');

expect(output).toEqual(true);
expect(exec.exec.mock.calls.length).toEqual(1);
Expand All @@ -54,35 +64,44 @@ describe('Scan MSBuild', () => {

test('It will skip JAVA_HOME on Windows', async () => {
// Create marker file
fs.closeSync(fs.openSync(markerFile, 'w'));
const files = {};
files[markerFile] = '';
mockFs(files);

const platformSpy = jest.spyOn(os, 'platform').mockReturnValue('win32');
await scanMsBuild('https://sonar.extenda.io', 'master');
const platformSpy = jest.spyOn(os, 'platform').mockReturnValueOnce('win32');
await scanMsBuild('https://sonar.extenda.io', 'master', 'dotnet');
expect(Object.keys(exec.exec.mock.calls[0][2].env)).not.toContain('JAVA_HOME');
platformSpy.mockRestore();
});

test('It can handle missing JDK', async () => {
// Create marker fil
fs.closeSync(fs.openSync(markerFile, 'w'));
// Create marker file
const files = {};
files[markerFile] = '';
mockFs(files);

process.env.JDK_BASEDIR = '/tmp/missing';

const platformSpy = jest.spyOn(os, 'platform').mockReturnValue('linux');
await scanMsBuild('https://sonar.extenda.io', 'master');
const platformSpy = jest.spyOn(os, 'platform').mockReturnValueOnce('linux');
await scanMsBuild('https://sonar.extenda.io', 'master', 'dotnet');
expect(Object.keys(exec.exec.mock.calls[0][2].env)).not.toContain('JAVA_HOME');
platformSpy.mockRestore();
});

if (fs.existsSync('/usr/lib/jvm')) {
test('It can set JAVA_HOME', async () => {
fs.closeSync(fs.openSync(markerFile, 'w'));
const platformSpy = jest.spyOn(os, 'platform').mockReturnValue('linux');
await scanMsBuild('https://sonar.extenda.io', 'master');
expect(Object.keys(exec.exec.mock.calls[0][2].env)).toContain('JAVA_HOME');
expect(exec.exec.mock.calls[0][2].env).toMatchObject({
JAVA_HOME: '/usr/lib/jvm/adoptopenjdk-11-hotspot-amd64',
});
platformSpy.mockRestore();
test('It can set JAVA_HOME', async () => {
// Create marker file
const files = {
'/usr/lib/jvm/adoptopenjdk-11-hotspot-amd64/bin': '',
};
files[markerFile] = '';
mockFs(files);

const platformSpy = jest.spyOn(os, 'platform').mockReturnValueOnce('linux');
await scanMsBuild('https://sonar.extenda.io', 'master', 'dotnet');
expect(Object.keys(exec.exec.mock.calls[0][2].env)).toContain('JAVA_HOME');
expect(exec.exec.mock.calls[0][2].env).toMatchObject({
JAVA_HOME: '/usr/lib/jvm/adoptopenjdk-11-hotspot-amd64',
});
}
platformSpy.mockRestore();
});
});