mirror of
https://github.com/SonarSource/sonarqube-scan-action.git
synced 2026-06-08 10:13:06 +03:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0368e05ab1 | |||
| a30e39dd44 | |||
| 751b8e8c7a |
Vendored
+17
-15
@@ -10,7 +10,6 @@ import { ok } from 'assert';
|
|||||||
import 'string_decoder';
|
import 'string_decoder';
|
||||||
import * as events from 'events';
|
import * as events from 'events';
|
||||||
import { setTimeout as setTimeout$1 } from 'timers';
|
import { setTimeout as setTimeout$1 } from 'timers';
|
||||||
import * as fs$2 from 'node:fs/promises';
|
|
||||||
import * as os$1 from 'node:os';
|
import * as os$1 from 'node:os';
|
||||||
import * as path$1 from 'node:path';
|
import * as path$1 from 'node:path';
|
||||||
import { join } from 'node:path';
|
import { join } from 'node:path';
|
||||||
@@ -3863,6 +3862,19 @@ function getScannerDownloadURL({
|
|||||||
const scannerDirName = (version, flavor) =>
|
const scannerDirName = (version, flavor) =>
|
||||||
`sonar-scanner-${version}-${flavor}`;
|
`sonar-scanner-${version}-${flavor}`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a 4-part version string (e.g. "8.0.1.6346") to a SemVer 2.0 compatible
|
||||||
|
* string (e.g. "8.0.1-build.6346") for use with GitHub's tool-cache library,
|
||||||
|
* which requires SemVer-compliant version strings.
|
||||||
|
*/
|
||||||
|
function toSemVer(version) {
|
||||||
|
const parts = version.split(".");
|
||||||
|
if (parts.length === 4) {
|
||||||
|
return `${parts[0]}.${parts[1]}.${parts[2]}-build.${parts[3]}`;
|
||||||
|
}
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sonarqube-scan-action
|
* sonarqube-scan-action
|
||||||
* Copyright (C) 2025 SonarSource SA
|
* Copyright (C) 2025 SonarSource SA
|
||||||
@@ -4142,15 +4154,6 @@ function cleanupGpgHome(gpgHome) {
|
|||||||
|
|
||||||
const TOOLNAME = "sonar-scanner-cli";
|
const TOOLNAME = "sonar-scanner-cli";
|
||||||
|
|
||||||
async function ensureZipExtension(filePath) {
|
|
||||||
if (filePath.endsWith(".zip")) {
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
const zipPath = `${filePath}.zip`;
|
|
||||||
await fs$2.rename(filePath, zipPath);
|
|
||||||
return zipPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download the Sonar Scanner CLI for the current environment and cache it.
|
* Download the Sonar Scanner CLI for the current environment and cache it.
|
||||||
*/
|
*/
|
||||||
@@ -4161,9 +4164,10 @@ async function installSonarScanner({
|
|||||||
skipSignatureVerification = false,
|
skipSignatureVerification = false,
|
||||||
}) {
|
}) {
|
||||||
const flavor = getPlatformFlavor(os$1.platform(), os$1.arch());
|
const flavor = getPlatformFlavor(os$1.platform(), os$1.arch());
|
||||||
|
const semVerVersion = toSemVer(scannerVersion);
|
||||||
|
|
||||||
// Check if tool is already cached
|
// Check if tool is already cached
|
||||||
let toolDir = find(TOOLNAME, scannerVersion, flavor);
|
let toolDir = find(TOOLNAME, semVerVersion, flavor);
|
||||||
|
|
||||||
if (!toolDir) {
|
if (!toolDir) {
|
||||||
info(
|
info(
|
||||||
@@ -4198,9 +4202,7 @@ async function installSonarScanner({
|
|||||||
await verifySignature(downloadPath, signaturePath);
|
await verifySignature(downloadPath, signaturePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// PowerShell 5.1 (used on some Windows agents) requires the .zip extension for Expand-Archive
|
const extractedPath = await extractZip(downloadPath);
|
||||||
const extractInput = await ensureZipExtension(downloadPath);
|
|
||||||
const extractedPath = await extractZip(extractInput);
|
|
||||||
|
|
||||||
// Find the actual scanner directory inside the extracted folder
|
// Find the actual scanner directory inside the extracted folder
|
||||||
const scannerPath = path$1.join(
|
const scannerPath = path$1.join(
|
||||||
@@ -4208,7 +4210,7 @@ async function installSonarScanner({
|
|||||||
scannerDirName(scannerVersion, flavor)
|
scannerDirName(scannerVersion, flavor)
|
||||||
);
|
);
|
||||||
|
|
||||||
toolDir = await cacheDir(scannerPath, TOOLNAME, scannerVersion, flavor);
|
toolDir = await cacheDir(scannerPath, TOOLNAME, semVerVersion, flavor);
|
||||||
|
|
||||||
info(`Sonar Scanner CLI cached to: ${toolDir}`);
|
info(`Sonar Scanner CLI cached to: ${toolDir}`);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -20,9 +20,9 @@
|
|||||||
|
|
||||||
import assert from "node:assert/strict";
|
import assert from "node:assert/strict";
|
||||||
import { describe, it, mock } from "node:test";
|
import { describe, it, mock } from "node:test";
|
||||||
import nodeFsPromises from "node:fs/promises";
|
|
||||||
|
|
||||||
const SCANNER_VERSION = "6.2.0.4584";
|
const SCANNER_VERSION = "6.2.0.4584";
|
||||||
|
const SCANNER_SEMVER_VERSION = "6.2.0-build.4584";
|
||||||
const BINARIES_URL = "https://my.artifactory.example.com/sonar-scanner-cli";
|
const BINARIES_URL = "https://my.artifactory.example.com/sonar-scanner-cli";
|
||||||
const BINARY_DOWNLOAD_URL = `${BINARIES_URL}/sonar-scanner-cli-${SCANNER_VERSION}-linux-x64.zip`;
|
const BINARY_DOWNLOAD_URL = `${BINARIES_URL}/sonar-scanner-cli-${SCANNER_VERSION}-linux-x64.zip`;
|
||||||
|
|
||||||
@@ -32,15 +32,7 @@ function mockUtils(t) {
|
|||||||
getPlatformFlavor: mock.fn(() => "linux-x64"),
|
getPlatformFlavor: mock.fn(() => "linux-x64"),
|
||||||
getScannerDownloadURL: mock.fn(() => BINARY_DOWNLOAD_URL),
|
getScannerDownloadURL: mock.fn(() => BINARY_DOWNLOAD_URL),
|
||||||
scannerDirName: mock.fn(() => `sonar-scanner-${SCANNER_VERSION}-linux-x64`),
|
scannerDirName: mock.fn(() => `sonar-scanner-${SCANNER_VERSION}-linux-x64`),
|
||||||
},
|
toSemVer: mock.fn(() => SCANNER_SEMVER_VERSION),
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function mockFsPromises(t) {
|
|
||||||
t.mock.module("node:fs/promises", {
|
|
||||||
namedExports: {
|
|
||||||
...nodeFsPromises,
|
|
||||||
rename: mock.fn(async () => {}),
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -54,7 +46,6 @@ describe("installSonarScanner", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
mockUtils(t);
|
mockUtils(t);
|
||||||
mockFsPromises(t);
|
|
||||||
|
|
||||||
t.mock.module("@actions/tool-cache", {
|
t.mock.module("@actions/tool-cache", {
|
||||||
namedExports: {
|
namedExports: {
|
||||||
@@ -103,7 +94,6 @@ describe("installSonarScanner", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
mockUtils(t);
|
mockUtils(t);
|
||||||
mockFsPromises(t);
|
|
||||||
|
|
||||||
t.mock.module("@actions/tool-cache", {
|
t.mock.module("@actions/tool-cache", {
|
||||||
namedExports: {
|
namedExports: {
|
||||||
@@ -150,7 +140,6 @@ describe("installSonarScanner", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
mockUtils(t);
|
mockUtils(t);
|
||||||
mockFsPromises(t);
|
|
||||||
|
|
||||||
t.mock.module("@actions/tool-cache", {
|
t.mock.module("@actions/tool-cache", {
|
||||||
namedExports: {
|
namedExports: {
|
||||||
@@ -184,30 +173,18 @@ describe("installSonarScanner", () => {
|
|||||||
assert.equal(downloadCalls[0].auth, "Bearer mytoken");
|
assert.equal(downloadCalls[0].auth, "Bearer mytoken");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should rename downloaded file to add .zip extension before extraction", async (t) => {
|
it("should use semver-compatible version for tool-cache find and cacheDir", async (t) => {
|
||||||
const renameCalls = [];
|
const findFn = mock.fn(() => null);
|
||||||
const extractZipCalls = [];
|
const cacheDirFn = mock.fn(async () => "/tmp/cached");
|
||||||
|
|
||||||
mockUtils(t);
|
mockUtils(t);
|
||||||
|
|
||||||
t.mock.module("node:fs/promises", {
|
|
||||||
namedExports: {
|
|
||||||
...nodeFsPromises,
|
|
||||||
rename: mock.fn(async (src, dest) => {
|
|
||||||
renameCalls.push({ src, dest });
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
t.mock.module("@actions/tool-cache", {
|
t.mock.module("@actions/tool-cache", {
|
||||||
namedExports: {
|
namedExports: {
|
||||||
find: mock.fn(() => null),
|
find: findFn,
|
||||||
downloadTool: mock.fn(async () => "/tmp/downloaded-file"),
|
downloadTool: mock.fn(async () => "/tmp/downloaded"),
|
||||||
extractZip: mock.fn(async (p) => {
|
extractZip: mock.fn(async () => "/tmp/extracted"),
|
||||||
extractZipCalls.push(p);
|
cacheDir: cacheDirFn,
|
||||||
return "/tmp/extracted";
|
|
||||||
}),
|
|
||||||
cacheDir: mock.fn(async () => "/tmp/cached"),
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -226,76 +203,18 @@ describe("installSonarScanner", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const { installSonarScanner } = await import(
|
const { installSonarScanner } = await import(
|
||||||
`../install-sonar-scanner.js?test=rename-zip`
|
`../install-sonar-scanner.js?test=semver-version`
|
||||||
);
|
);
|
||||||
|
|
||||||
await installSonarScanner({
|
await installSonarScanner({
|
||||||
scannerVersion: SCANNER_VERSION,
|
scannerVersion: SCANNER_VERSION,
|
||||||
scannerBinariesUrl: BINARIES_URL,
|
scannerBinariesUrl: BINARIES_URL,
|
||||||
skipSignatureVerification: true,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.equal(renameCalls.length, 1, "Should rename downloaded file");
|
assert.equal(findFn.mock.calls[0].arguments[1], SCANNER_SEMVER_VERSION,
|
||||||
assert.equal(renameCalls[0].src, "/tmp/downloaded-file");
|
"tc.find should be called with semver-compatible version");
|
||||||
assert.equal(renameCalls[0].dest, "/tmp/downloaded-file.zip");
|
assert.equal(cacheDirFn.mock.calls[0].arguments[2], SCANNER_SEMVER_VERSION,
|
||||||
assert.equal(extractZipCalls.length, 1, "Should call extractZip once");
|
"tc.cacheDir should be called with semver-compatible version");
|
||||||
assert.equal(extractZipCalls[0], "/tmp/downloaded-file.zip", "Should extract the renamed file");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not rename downloaded file when it already has .zip extension", async (t) => {
|
|
||||||
const renameCalls = [];
|
|
||||||
const extractZipCalls = [];
|
|
||||||
|
|
||||||
mockUtils(t);
|
|
||||||
|
|
||||||
t.mock.module("node:fs/promises", {
|
|
||||||
namedExports: {
|
|
||||||
...nodeFsPromises,
|
|
||||||
rename: mock.fn(async (src, dest) => {
|
|
||||||
renameCalls.push({ src, dest });
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
t.mock.module("@actions/tool-cache", {
|
|
||||||
namedExports: {
|
|
||||||
find: mock.fn(() => null),
|
|
||||||
downloadTool: mock.fn(async () => "/tmp/downloaded-file.zip"),
|
|
||||||
extractZip: mock.fn(async (p) => {
|
|
||||||
extractZipCalls.push(p);
|
|
||||||
return "/tmp/extracted";
|
|
||||||
}),
|
|
||||||
cacheDir: mock.fn(async () => "/tmp/cached"),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
t.mock.module("@actions/core", {
|
|
||||||
namedExports: {
|
|
||||||
info: mock.fn(),
|
|
||||||
warning: mock.fn(),
|
|
||||||
addPath: mock.fn(),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
t.mock.module("../gpg-verification.js", {
|
|
||||||
namedExports: {
|
|
||||||
verifySignature: mock.fn(async () => {}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const { installSonarScanner } = await import(
|
|
||||||
`../install-sonar-scanner.js?test=no-rename-zip`
|
|
||||||
);
|
|
||||||
|
|
||||||
await installSonarScanner({
|
|
||||||
scannerVersion: SCANNER_VERSION,
|
|
||||||
scannerBinariesUrl: BINARIES_URL,
|
|
||||||
skipSignatureVerification: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.equal(renameCalls.length, 0, "Should not rename when already .zip");
|
|
||||||
assert.equal(extractZipCalls.length, 1, "Should call extractZip once");
|
|
||||||
assert.equal(extractZipCalls[0], "/tmp/downloaded-file.zip", "Should extract original file");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should use cached tool when available and skip download", async (t) => {
|
it("should use cached tool when available and skip download", async (t) => {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import {
|
|||||||
getPlatformFlavor,
|
getPlatformFlavor,
|
||||||
getScannerDownloadURL,
|
getScannerDownloadURL,
|
||||||
scannerDirName,
|
scannerDirName,
|
||||||
|
toSemVer,
|
||||||
} from "../utils.js";
|
} from "../utils.js";
|
||||||
|
|
||||||
describe("getPlatformFlavor", () => {
|
describe("getPlatformFlavor", () => {
|
||||||
@@ -97,3 +98,22 @@ describe("scannerDirName", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("toSemVer", () => {
|
||||||
|
it("converts 4-part version to semver pre-release format", () => {
|
||||||
|
assert.equal(toSemVer("8.0.1.6346"), "8.0.1-build.6346");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("leaves 3-part semver version unchanged", () => {
|
||||||
|
assert.equal(toSemVer("8.0.1"), "8.0.1");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("leaves version with pre-release identifier unchanged", () => {
|
||||||
|
assert.equal(toSemVer("7.2.0-SNAPSHOT"), "7.2.0-SNAPSHOT");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("converts different 4-part versions correctly", () => {
|
||||||
|
assert.equal(toSemVer("6.2.0.4584"), "6.2.0-build.4584");
|
||||||
|
assert.equal(toSemVer("8.1.0.6389"), "8.1.0-build.6389");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -18,27 +18,18 @@
|
|||||||
|
|
||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
import * as tc from "@actions/tool-cache";
|
import * as tc from "@actions/tool-cache";
|
||||||
import * as fs from "node:fs/promises";
|
|
||||||
import * as os from "node:os";
|
import * as os from "node:os";
|
||||||
import * as path from "node:path";
|
import * as path from "node:path";
|
||||||
import {
|
import {
|
||||||
getPlatformFlavor,
|
getPlatformFlavor,
|
||||||
getScannerDownloadURL,
|
getScannerDownloadURL,
|
||||||
scannerDirName,
|
scannerDirName,
|
||||||
|
toSemVer,
|
||||||
} from "./utils.js";
|
} from "./utils.js";
|
||||||
import { verifySignature } from "./gpg-verification.js";
|
import { verifySignature } from "./gpg-verification.js";
|
||||||
|
|
||||||
const TOOLNAME = "sonar-scanner-cli";
|
const TOOLNAME = "sonar-scanner-cli";
|
||||||
|
|
||||||
async function ensureZipExtension(filePath) {
|
|
||||||
if (filePath.endsWith(".zip")) {
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
const zipPath = `${filePath}.zip`;
|
|
||||||
await fs.rename(filePath, zipPath);
|
|
||||||
return zipPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download the Sonar Scanner CLI for the current environment and cache it.
|
* Download the Sonar Scanner CLI for the current environment and cache it.
|
||||||
*/
|
*/
|
||||||
@@ -49,9 +40,10 @@ export async function installSonarScanner({
|
|||||||
skipSignatureVerification = false,
|
skipSignatureVerification = false,
|
||||||
}) {
|
}) {
|
||||||
const flavor = getPlatformFlavor(os.platform(), os.arch());
|
const flavor = getPlatformFlavor(os.platform(), os.arch());
|
||||||
|
const semVerVersion = toSemVer(scannerVersion);
|
||||||
|
|
||||||
// Check if tool is already cached
|
// Check if tool is already cached
|
||||||
let toolDir = tc.find(TOOLNAME, scannerVersion, flavor);
|
let toolDir = tc.find(TOOLNAME, semVerVersion, flavor);
|
||||||
|
|
||||||
if (!toolDir) {
|
if (!toolDir) {
|
||||||
core.info(
|
core.info(
|
||||||
@@ -86,9 +78,7 @@ export async function installSonarScanner({
|
|||||||
await verifySignature(downloadPath, signaturePath);
|
await verifySignature(downloadPath, signaturePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// PowerShell 5.1 (used on some Windows agents) requires the .zip extension for Expand-Archive
|
const extractedPath = await tc.extractZip(downloadPath);
|
||||||
const extractInput = await ensureZipExtension(downloadPath);
|
|
||||||
const extractedPath = await tc.extractZip(extractInput);
|
|
||||||
|
|
||||||
// Find the actual scanner directory inside the extracted folder
|
// Find the actual scanner directory inside the extracted folder
|
||||||
const scannerPath = path.join(
|
const scannerPath = path.join(
|
||||||
@@ -96,7 +86,7 @@ export async function installSonarScanner({
|
|||||||
scannerDirName(scannerVersion, flavor)
|
scannerDirName(scannerVersion, flavor)
|
||||||
);
|
);
|
||||||
|
|
||||||
toolDir = await tc.cacheDir(scannerPath, TOOLNAME, scannerVersion, flavor);
|
toolDir = await tc.cacheDir(scannerPath, TOOLNAME, semVerVersion, flavor);
|
||||||
|
|
||||||
core.info(`Sonar Scanner CLI cached to: ${toolDir}`);
|
core.info(`Sonar Scanner CLI cached to: ${toolDir}`);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -51,3 +51,16 @@ export function getScannerDownloadURL({
|
|||||||
|
|
||||||
export const scannerDirName = (version, flavor) =>
|
export const scannerDirName = (version, flavor) =>
|
||||||
`sonar-scanner-${version}-${flavor}`;
|
`sonar-scanner-${version}-${flavor}`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a 4-part version string (e.g. "8.0.1.6346") to a SemVer 2.0 compatible
|
||||||
|
* string (e.g. "8.0.1-build.6346") for use with GitHub's tool-cache library,
|
||||||
|
* which requires SemVer-compliant version strings.
|
||||||
|
*/
|
||||||
|
export function toSemVer(version) {
|
||||||
|
const parts = version.split(".");
|
||||||
|
if (parts.length === 4) {
|
||||||
|
return `${parts[0]}.${parts[1]}.${parts[2]}-build.${parts[3]}`;
|
||||||
|
}
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user