SQSCANGHA-115 Migrate sanity checks

This commit is contained in:
Jeremy Davis 2025-09-08 12:20:35 +02:00
parent ce747ea817
commit c6be16c2be
12 changed files with 27704 additions and 11 deletions

View file

@ -25,12 +25,18 @@ inputs:
runs:
using: "composite"
steps:
# - name: Checkout
# uses: actions/checkout@v5
# with:
# ref: "jay/js-rewrite"
- name: Sanity checks
run: ${GITHUB_ACTION_PATH}/scripts/sanity-checks.sh
run: node ./dist/index.js
shell: bash
env:
INPUT_PROJECTBASEDIR: ${{ inputs.projectBaseDir }}
INPUT_SCANNERVERSION: ${{ inputs.scannerVersion }}
- name: Load Sonar Scanner CLI from cache
id: sonar-scanner-cli
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 #v4.2.4

27347
dist/index.js vendored

File diff suppressed because one or more lines are too long

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

47
dist/sanity-checks.js vendored Normal file
View file

@ -0,0 +1,47 @@
import fs from 'fs';
import { join } from 'path';
function validateScannerVersion(version) {
if (!version) {
return;
}
const versionRegex = /^\d+\.\d+\.\d+\.\d+$/;
if (!versionRegex.test(version)) {
throw new Error(
"Invalid scannerVersion format. Expected format: x.y.z.w (e.g., 7.1.0.4889)"
);
}
}
function checkSonarToken(core) {
if (!process.env.SONAR_TOKEN) {
core.warning(
"Running this GitHub Action without SONAR_TOKEN is not recommended"
);
}
}
function checkMavenProject(core, projectBaseDir) {
const pomPath = join(projectBaseDir.replace(/\/$/, ""), "pom.xml");
if (fs.existsSync(pomPath)) {
core.warning(
"Maven project detected. Sonar recommends running the 'org.sonarsource.scanner.maven:sonar-maven-plugin:sonar' goal during the build process instead of using this GitHub Action to get more accurate results."
);
}
}
function checkGradleProject(core, projectBaseDir) {
const baseDir = projectBaseDir.replace(/\/$/, "");
const gradlePath = join(baseDir, "build.gradle");
const gradleKtsPath = join(baseDir, "build.gradle.kts");
if (fs.existsSync(gradlePath) || fs.existsSync(gradleKtsPath)) {
core.warning(
"Gradle project detected. Sonar recommends using the SonarQube plugin for Gradle during the build process instead of using this GitHub Action to get more accurate results."
);
}
}
export { checkGradleProject, checkMavenProject, checkSonarToken, validateScannerVersion };
//# sourceMappingURL=sanity-checks.js.map

1
dist/sanity-checks.js.map vendored Normal file
View file

@ -0,0 +1 @@
{"version":3,"file":"sanity-checks.js","sources":["../src/sanity-checks.js"],"sourcesContent":["import fs from \"fs\";\nimport { join } from \"path\";\n\nexport function validateScannerVersion(version) {\n if (!version) {\n return;\n }\n\n const versionRegex = /^\\d+\\.\\d+\\.\\d+\\.\\d+$/;\n if (!versionRegex.test(version)) {\n throw new Error(\n \"Invalid scannerVersion format. Expected format: x.y.z.w (e.g., 7.1.0.4889)\"\n );\n }\n}\n\nexport function checkSonarToken(core) {\n if (!process.env.SONAR_TOKEN) {\n core.warning(\n \"Running this GitHub Action without SONAR_TOKEN is not recommended\"\n );\n }\n}\n\nexport function checkMavenProject(core, projectBaseDir) {\n const pomPath = join(projectBaseDir.replace(/\\/$/, \"\"), \"pom.xml\");\n if (fs.existsSync(pomPath)) {\n core.warning(\n \"Maven project detected. Sonar recommends running the 'org.sonarsource.scanner.maven:sonar-maven-plugin:sonar' goal during the build process instead of using this GitHub Action to get more accurate results.\"\n );\n }\n}\n\nexport function checkGradleProject(core, projectBaseDir) {\n const baseDir = projectBaseDir.replace(/\\/$/, \"\");\n const gradlePath = join(baseDir, \"build.gradle\");\n const gradleKtsPath = join(baseDir, \"build.gradle.kts\");\n\n if (fs.existsSync(gradlePath) || fs.existsSync(gradleKtsPath)) {\n core.warning(\n \"Gradle project detected. Sonar recommends using the SonarQube plugin for Gradle during the build process instead of using this GitHub Action to get more accurate results.\"\n );\n }\n}\n"],"names":[],"mappings":";;;AAGO,SAAS,sBAAsB,CAAC,OAAO,EAAE;AAChD,EAAE,IAAI,CAAC,OAAO,EAAE;AAChB,IAAI;AACJ,EAAE;;AAEF,EAAE,MAAM,YAAY,GAAG,sBAAsB;AAC7C,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AACnC,IAAI,MAAM,IAAI,KAAK;AACnB,MAAM;AACN,KAAK;AACL,EAAE;AACF;;AAEO,SAAS,eAAe,CAAC,IAAI,EAAE;AACtC,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE;AAChC,IAAI,IAAI,CAAC,OAAO;AAChB,MAAM;AACN,KAAK;AACL,EAAE;AACF;;AAEO,SAAS,iBAAiB,CAAC,IAAI,EAAE,cAAc,EAAE;AACxD,EAAE,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,SAAS,CAAC;AACpE,EAAE,IAAI,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE;AAC9B,IAAI,IAAI,CAAC,OAAO;AAChB,MAAM;AACN,KAAK;AACL,EAAE;AACF;;AAEO,SAAS,kBAAkB,CAAC,IAAI,EAAE,cAAc,EAAE;AACzD,EAAE,MAAM,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;AACnD,EAAE,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC;AAClD,EAAE,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,EAAE,kBAAkB,CAAC;;AAEzD,EAAE,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE;AACjE,IAAI,IAAI,CAAC,OAAO;AAChB,MAAM;AACN,KAAK;AACL,EAAE;AACF;;;;"}

21
package-lock.json generated
View file

@ -9,13 +9,14 @@
"version": "6.0.0",
"license": "LGPL-3.0-only",
"dependencies": {
"@actions/core": "^1.11.1",
"@actions/github": "^6.0.1"
"@actions/core": "1.11.1",
"@actions/github": "6.0.1"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^28.0.6",
"@rollup/plugin-node-resolve": "^16.0.1",
"rollup": "^4.50.1"
"@rollup/plugin-commonjs": "28.0.6",
"@rollup/plugin-node-resolve": "16.0.1",
"mock-fs": "^5.5.0",
"rollup": "4.50.1"
}
},
"node_modules/@actions/core": {
@ -760,6 +761,16 @@
"@jridgewell/sourcemap-codec": "^1.5.5"
}
},
"node_modules/mock-fs": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-5.5.0.tgz",
"integrity": "sha512-d/P1M/RacgM3dB0sJ8rjeRNXxtapkPCUnMGmIN0ixJ16F/E4GUZCvWcSGfWGz8eaXYvn1s9baUwNjI4LOPEjiA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",

View file

@ -6,7 +6,7 @@
"main": "src/index.js",
"scripts": {
"build": "rollup --config rollup.config.js",
"test": "echo \"Error: no test specified\" && exit 1"
"test": "node --test"
},
"license": "LGPL-3.0-only",
"dependencies": {
@ -16,6 +16,7 @@
"devDependencies": {
"@rollup/plugin-commonjs": "28.0.6",
"@rollup/plugin-node-resolve": "16.0.1",
"mock-fs": "^5.5.0",
"rollup": "4.50.1"
}
}

View file

@ -5,7 +5,7 @@ const config = {
input: "src/index.js",
output: {
esModule: true,
file: "dist/index.js",
dir: "dist",
format: "es",
sourcemap: true,
},

7
src/__tests__/mocks.js Normal file
View file

@ -0,0 +1,7 @@
export function mockCore(overrides = {}) {
return {
setFailed: (msg) => console.error(msg),
warning: (msg) => console.log(msg),
...overrides,
};
}

View file

@ -0,0 +1,193 @@
import mockfs from "mock-fs";
import assert from "node:assert/strict";
import { describe, it, mock } from "node:test";
import {
checkGradleProject,
checkMavenProject,
checkSonarToken,
validateScannerVersion,
} from "../sanity-checks.js";
import { mockCore } from "./mocks.js";
describe("validateScannerVersion", () => {
const expected =
"Invalid scannerVersion format. Expected format: x.y.z.w (e.g., 7.1.0.4889)";
const validVersions = [undefined, "", "7.1.0.4889", "1.2.3.4"];
const invalidVersions = [
"wrong",
"4.2.",
"7.1.0",
"7.1.0.abc",
"7.1.0.4889.5",
"7.1",
"7",
"7.1.0.",
".7.1.0.4889",
"7..1.0.4889",
"7.1..0.4889",
"7.1.0..4889",
"a.b.c.d",
"7.1.0.4889-SNAPSHOT",
"v7.1.0.4889",
"7.1.0.4889.0.0",
"-7.1.0.4889",
"7.-1.0.4889",
"7.1.-0.4889",
"7.1.0.-4889",
"7.1.0.4889 ",
" 7.1.0.4889",
"7.1.0.4889\n",
"7,1,0,4889",
];
validVersions.forEach((version) => {
it(`accepts ${version}`, () => {
assert.equal(validateScannerVersion(version), undefined);
});
});
invalidVersions.forEach((version) =>
it(`throws for ${version}`, () => {
assert.throws(
() => validateScannerVersion(version),
{
message: expected,
},
`should have thrown for ${version}`
);
})
);
});
describe("checkSonarToken", () => {
it("calls core.warning when SONAR_TOKEN is not set", () => {
const originalToken = process.env.SONAR_TOKEN;
delete process.env.SONAR_TOKEN;
const warning = mock.fn();
checkSonarToken(mockCore({ warning }));
assert.equal(warning.mock.calls.length, 1);
assert.equal(
warning.mock.calls[0].arguments[0],
"Running this GitHub Action without SONAR_TOKEN is not recommended"
);
if (originalToken) {
process.env.SONAR_TOKEN = originalToken;
}
});
it("does not call core.warning when SONAR_TOKEN is set", () => {
const originalToken = process.env.SONAR_TOKEN;
process.env.SONAR_TOKEN = "test-token";
const warning = mock.fn();
checkSonarToken(mockCore({ warning }));
assert.equal(warning.mock.calls.length, 0);
if (originalToken) {
process.env.SONAR_TOKEN = originalToken;
} else {
delete process.env.SONAR_TOKEN;
}
});
});
describe("checkMavenProject", () => {
it("calls core.warning when pom.xml exists", async () => {
mockfs({ "/test/project/": { "pom.xml": "" } });
const warning = mock.fn();
checkMavenProject({ warning }, "/test/project");
assert.equal(warning.mock.calls.length, 1);
assert.equal(
warning.mock.calls[0].arguments[0],
"Maven project detected. Sonar recommends running the 'org.sonarsource.scanner.maven:sonar-maven-plugin:sonar' goal during the build process instead of using this GitHub Action to get more accurate results."
);
mockfs.restore();
});
it("does not call core.warning when pom.xml does not exist", async () => {
mockfs({ "/test/project/": {} });
const warning = mock.fn();
checkMavenProject(mockCore({ warning }), "/test/project");
assert.equal(warning.mock.calls.length, 0);
mockfs.restore();
});
it("handles project base dir with trailing slash", async () => {
mockfs({ "/test/project/": { "pom.xml": "" } });
const warning = mock.fn();
checkMavenProject(mockCore({ warning }), "/test/project/");
assert.equal(warning.mock.calls.length, 1);
mockfs.restore();
});
});
describe("checkGradleProject", () => {
it("calls core.warning when build.gradle exists", async () => {
mockfs({ "/test/project/": { "build.gradle": "" } });
const warning = mock.fn();
checkGradleProject(mockCore({ warning }), "/test/project");
assert.equal(warning.mock.calls.length, 1);
assert.equal(
warning.mock.calls[0].arguments[0],
"Gradle project detected. Sonar recommends using the SonarQube plugin for Gradle during the build process instead of using this GitHub Action to get more accurate results."
);
mockfs.restore();
});
it("calls core.warning when build.gradle.kts exists", async () => {
mockfs({ "/test/project/": { "build.gradle.kts": "" } });
const warning = mock.fn();
checkGradleProject(mockCore({ warning }), "/test/project");
assert.equal(warning.mock.calls.length, 1);
assert.equal(
warning.mock.calls[0].arguments[0],
"Gradle project detected. Sonar recommends using the SonarQube plugin for Gradle during the build process instead of using this GitHub Action to get more accurate results."
);
mockfs.restore();
});
it("does not call core.warning when neither gradle file exists", async () => {
mockfs({ "/test/project/": {} });
const warning = mock.fn();
checkGradleProject(mockCore({ warning }), "/test/project");
assert.equal(warning.mock.calls.length, 0);
mockfs.restore();
});
it("handles project base dir with trailing slash", async () => {
mockfs({ "/test/project/": { "build.gradle": "" } });
const warning = mock.fn();
checkGradleProject(mockCore({ warning }), "/test/project/");
assert.equal(warning.mock.calls.length, 1);
});
});

View file

@ -1 +1,39 @@
console.log("Hi there");
import * as core from "@actions/core";
import {
checkGradleProject,
checkMavenProject,
checkSonarToken,
validateScannerVersion,
} from "./sanity-checks";
function getInputs() {
//FIXME: should not rely on ENV vars
const scannerVersion = process.env.INPUT_SCANNERVERSION; // core.getInput("scannerVersion");
const projectBaseDir = process.env.INPUT_PROJECTBASEDIR; // core.getInput("projectBaseDir") || ".";
console.log("scannerVersion: ", scannerVersion);
return { scannerVersion, projectBaseDir };
}
function runSanityChecks(inputs) {
try {
const { scannerVersion, projectBaseDir } = inputs;
validateScannerVersion(scannerVersion);
checkSonarToken(core);
checkMavenProject(core, projectBaseDir);
checkGradleProject(core, projectBaseDir);
} catch (error) {
core.setFailed(`Sanity checks failed: ${error.message}`);
process.exit(1);
}
}
function run() {
const inputs = getInputs();
runSanityChecks(inputs);
}
run();

44
src/sanity-checks.js Normal file
View file

@ -0,0 +1,44 @@
import fs from "fs";
import { join } from "path";
export function validateScannerVersion(version) {
if (!version) {
return;
}
const versionRegex = /^\d+\.\d+\.\d+\.\d+$/;
if (!versionRegex.test(version)) {
throw new Error(
"Invalid scannerVersion format. Expected format: x.y.z.w (e.g., 7.1.0.4889)"
);
}
}
export function checkSonarToken(core) {
if (!process.env.SONAR_TOKEN) {
core.warning(
"Running this GitHub Action without SONAR_TOKEN is not recommended"
);
}
}
export function checkMavenProject(core, projectBaseDir) {
const pomPath = join(projectBaseDir.replace(/\/$/, ""), "pom.xml");
if (fs.existsSync(pomPath)) {
core.warning(
"Maven project detected. Sonar recommends running the 'org.sonarsource.scanner.maven:sonar-maven-plugin:sonar' goal during the build process instead of using this GitHub Action to get more accurate results."
);
}
}
export function checkGradleProject(core, projectBaseDir) {
const baseDir = projectBaseDir.replace(/\/$/, "");
const gradlePath = join(baseDir, "build.gradle");
const gradleKtsPath = join(baseDir, "build.gradle.kts");
if (fs.existsSync(gradlePath) || fs.existsSync(gradleKtsPath)) {
core.warning(
"Gradle project detected. Sonar recommends using the SonarQube plugin for Gradle during the build process instead of using this GitHub Action to get more accurate results."
);
}
}