Implement feature versionSpec using SemVer for setup Maven

This commit is contained in:
Thach Nguyen 2022-07-29 04:37:38 +07:00
parent c970051976
commit 7a818935c0
10 changed files with 319 additions and 58 deletions

1
.gitignore vendored
View File

@ -16,6 +16,7 @@ lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.*.*.*.*.json
.scannerwork/
# Runtime data
pids

View File

@ -10,7 +10,7 @@ jobs:
- name: Set up Maven
uses: stCarolas/setup-maven@v5
with:
maven-version: 3.8.2
maven-version: 3.8
```
### Development using [Docker](https://docs.docker.com/)
@ -41,5 +41,5 @@ Run `SonarScanner` from [the Docker image](https://hub.docker.com/r/sonarsource/
```batch
docker run --rm -it --link docker-sonarqube -v "%PWD%:/usr/src/app" -w /usr/src/app ^
-e "SONAR_HOST_URL=http://docker-sonarqube:9000" -e "SONAR_LOGIN=<projectToken>" sonarsource/sonar-scanner-cli ^
-Dsonar.projectKey=setup-maven -Dsonar.language=js -Dsonar.sources=. "-Dsonar.exclusions=dist/**"
-Dsonar.projectKey=setup-maven -Dsonar.sources=. "-Dsonar.exclusions=dist/**,lib/**"
```

View File

@ -1,5 +1,10 @@
describe('maven installer tests', () => {
it('square root of 4 to equal 2', () => {
expect(Math.sqrt(4)).toBe(2);
import * as installer from '../src/installer';
describe('getAvailableVersions', () => {
it('load real available versions', async () => {
const availableVersions = await installer.getAvailableVersions();
expect(availableVersions).toBeTruthy();
expect(availableVersions).toEqual(expect.arrayContaining(['3.2.5', '3.3.3', '3.8.2']));
});
});

View File

@ -5,7 +5,10 @@ inputs:
maven-version:
description: 'Version Spec of the version to use. Examples: 3.x, 3.1.1, >=3.8.0'
required: false
default: '3.8.2'
default: '3'
outputs:
version:
description: 'Actual version of Apache Maven that has been installed'
runs:
using: 'node16'
main: 'dist/index.js'

197
dist/index.js generated vendored
View File

@ -4965,37 +4965,81 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
});
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.getMaven = void 0;
exports.findVersionForDownload = exports.downloadMaven = exports.getAvailableVersions = exports.setupMaven = void 0;
const path = __importStar(__nccwpck_require__(17));
const core = __importStar(__nccwpck_require__(186));
const tc = __importStar(__nccwpck_require__(784));
const path = __importStar(__nccwpck_require__(17));
function getMaven(version) {
const http_client_1 = __nccwpck_require__(925);
const semver = __importStar(__nccwpck_require__(911));
const utils_1 = __nccwpck_require__(314);
function setupMaven(versionSpec, installedVersion) {
return __awaiter(this, void 0, void 0, function* () {
let toolPath = tc.find('maven', version);
if (!toolPath) {
toolPath = yield downloadMaven(version);
let toolPath = tc.find('maven', versionSpec);
let resolvedVersion = utils_1.getVersionFromToolcachePath(toolPath);
if (installedVersion) {
if (!toolPath || semver.gte(installedVersion, resolvedVersion)) {
core.info(`Use system Maven version ${installedVersion} instead of the cached one: ${resolvedVersion}`);
return installedVersion;
}
}
else if (!toolPath) {
resolvedVersion = yield findVersionForDownload(versionSpec);
toolPath = yield downloadMaven(resolvedVersion);
}
core.addPath(path.join(toolPath, 'bin'));
return resolvedVersion;
});
}
exports.getMaven = getMaven;
exports.setupMaven = setupMaven;
const DOWNLOAD_BASE_URL = 'https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven';
function downloadMaven(version) {
function getAvailableVersions() {
return __awaiter(this, void 0, void 0, function* () {
const toolDirectoryName = `apache-maven-${version}`;
const downloadUrl = `${DOWNLOAD_BASE_URL}/${version}/${toolDirectoryName}-bin.tar.gz`;
core.info(`Downloading Maven ${version} from ${downloadUrl} ...`);
const resourceUrl = `${DOWNLOAD_BASE_URL}/maven-metadata.xml`;
const http = new http_client_1.HttpClient('setup-maven', undefined, { allowRetries: true });
core.info(`Downloading Maven versions manifest from ${resourceUrl} ...`);
const response = yield http.get(resourceUrl);
const body = yield response.readBody();
if (response.message.statusCode !== http_client_1.HttpCodes.OK || !body) {
throw new Error(`Unable to get available versions from ${resourceUrl}`);
}
const availableVersions = body.match(/(?<=<version>)[^<>]+(?=<\/version>)/g) || [];
core.debug(`Available Maven versions: [${availableVersions}]`);
return availableVersions;
});
}
exports.getAvailableVersions = getAvailableVersions;
/**
* Download and extract a specified Maven version to the tool-cache.
*/
function downloadMaven(fullVersion) {
return __awaiter(this, void 0, void 0, function* () {
const toolDirectoryName = `apache-maven-${fullVersion}`;
const downloadUrl = `${DOWNLOAD_BASE_URL}/${fullVersion}/${toolDirectoryName}-bin.tar.gz`;
core.info(`Downloading Maven ${fullVersion} from ${downloadUrl} ...`);
const downloadPath = yield tc.downloadTool(downloadUrl);
const extractedPath = yield tc.extractTar(downloadPath);
const toolRoot = path.join(extractedPath, toolDirectoryName);
return tc.cacheDir(toolRoot, 'maven', version);
return tc.cacheDir(toolRoot, 'maven', fullVersion);
});
}
exports.downloadMaven = downloadMaven;
function findVersionForDownload(versionSpec) {
return __awaiter(this, void 0, void 0, function* () {
const availableVersions = yield getAvailableVersions();
const resolvedVersion = semver.maxSatisfying(availableVersions, versionSpec);
if (!resolvedVersion) {
throw new Error(`Could not find satisfied version for SemVer ${versionSpec}`);
}
core.debug(`Resolved version for download: ${resolvedVersion}`);
return resolvedVersion;
});
}
exports.findVersionForDownload = findVersionForDownload;
/***/ }),
/***/ 587:
/***/ 399:
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
"use strict";
@ -5029,23 +5073,115 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
});
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.run = void 0;
const core = __importStar(__nccwpck_require__(186));
const installer = __importStar(__nccwpck_require__(574));
const semver = __importStar(__nccwpck_require__(911));
const utils_1 = __nccwpck_require__(314);
const installer_1 = __nccwpck_require__(574);
function run() {
return __awaiter(this, void 0, void 0, function* () {
try {
const version = core.getInput('maven-version');
if (version) {
yield installer.getMaven(version);
const versionSpec = core.getInput('maven-version') || '3';
if (!semver.validRange(versionSpec)) {
core.setFailed(`Invalid SemVer notation '${versionSpec}' for a Maven version`);
return;
}
let installedVersion = yield utils_1.getActiveMavenVersion();
if (installedVersion && !semver.satisfies(installedVersion, versionSpec)) {
installedVersion = undefined;
}
installedVersion = yield installer_1.setupMaven(versionSpec, installedVersion);
core.setOutput('version', installedVersion);
}
catch (error) {
core.setFailed(error.message);
core.setFailed(error.toString());
}
});
}
// noinspection JSIgnoredPromiseFromCall
run();
exports.run = run;
/***/ }),
/***/ 314:
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.getExecOutput = exports.getActiveMavenVersion = exports.getVersionFromToolcachePath = void 0;
const path = __importStar(__nccwpck_require__(17));
const core = __importStar(__nccwpck_require__(186));
const exec = __importStar(__nccwpck_require__(514));
function getVersionFromToolcachePath(toolPath) {
return !toolPath ? toolPath : path.basename(path.dirname(toolPath));
}
exports.getVersionFromToolcachePath = getVersionFromToolcachePath;
/**
* Determine version of the current used Maven.
*/
function getActiveMavenVersion() {
return __awaiter(this, void 0, void 0, function* () {
try {
const { output } = yield getExecOutput('mvn', ['-v']);
const found = output.match(/^[^\d]*(\S+)/);
const installedVersion = !found ? '' : found[1];
core.debug(`Retrieved activated Maven version: ${installedVersion}`);
return installedVersion;
}
catch (error) {
core.info(`Failed to get activated Maven version. ${error}`);
}
return undefined;
});
}
exports.getActiveMavenVersion = getActiveMavenVersion;
/**
* Exec a command and get the standard output.
*
* @throws {Error} If the exit-code is non-zero.
*/
function getExecOutput(command, args) {
return __awaiter(this, void 0, void 0, function* () {
let output = '';
const exitCode = yield exec.exec(command, args, {
silent: true,
listeners: {
stdout: (data) => (output += data.toString())
}
});
return { exitCode, output };
});
}
exports.getExecOutput = getExecOutput;
/***/ }),
@ -5192,12 +5328,19 @@ module.exports = require("util");
/******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = __dirname + "/";
/******/
/************************************************************************/
/******/
/******/ // startup
/******/ // Load entry module and return exports
/******/ // This entry module is referenced by other modules so it can't be inlined
/******/ var __webpack_exports__ = __nccwpck_require__(587);
/******/ module.exports = __webpack_exports__;
/******/
var __webpack_exports__ = {};
// This entry need to be wrapped in an IIFE because it need to be in strict mode.
(() => {
"use strict";
var exports = __webpack_exports__;
Object.defineProperty(exports, "__esModule", ({ value: true }));
const main_1 = __nccwpck_require__(399);
// noinspection JSIgnoredPromiseFromCall
main_1.run();
})();
module.exports = __webpack_exports__;
/******/ })()
;

View File

@ -38,9 +38,10 @@
"typescript": "^4.2.3"
},
"prettier": {
"printWidth": 100,
"semi": true,
"singleQuote": true,
"trailingComma": "none",
"bracketSpacing": true,
"arrowParens": "avoid"
},
"jest": {

View File

@ -1,29 +1,77 @@
import * as path from 'path';
import * as core from '@actions/core';
import * as tc from '@actions/tool-cache';
import { HttpClient, HttpCodes } from '@actions/http-client';
import * as semver from 'semver';
import * as path from 'path';
import { getVersionFromToolcachePath } from './utils';
export async function getMaven(version: string) {
let toolPath = tc.find('maven', version);
export async function setupMaven(versionSpec: string, installedVersion?: string): Promise<string> {
let toolPath = tc.find('maven', versionSpec);
let resolvedVersion = getVersionFromToolcachePath(toolPath);
if (!toolPath) {
toolPath = await downloadMaven(version);
if (installedVersion) {
if (!toolPath || semver.gte(installedVersion, resolvedVersion)) {
core.info(
`Use system Maven version ${installedVersion} instead of the cached one: ${resolvedVersion}`
);
return installedVersion;
}
} else if (!toolPath) {
resolvedVersion = await findVersionForDownload(versionSpec);
toolPath = await downloadMaven(resolvedVersion);
}
core.addPath(path.join(toolPath, 'bin'));
return resolvedVersion;
}
const DOWNLOAD_BASE_URL = 'https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven';
async function downloadMaven(version: string): Promise<string> {
const toolDirectoryName = `apache-maven-${version}`;
const downloadUrl = `${DOWNLOAD_BASE_URL}/${version}/${toolDirectoryName}-bin.tar.gz`;
export async function getAvailableVersions(): Promise<string[]> {
const resourceUrl = `${DOWNLOAD_BASE_URL}/maven-metadata.xml`;
const http = new HttpClient('setup-maven', undefined, { allowRetries: true });
core.info(`Downloading Maven ${version} from ${downloadUrl} ...`);
core.info(`Downloading Maven versions manifest from ${resourceUrl} ...`);
const response = await http.get(resourceUrl);
const body = await response.readBody();
if (response.message.statusCode !== HttpCodes.OK || !body) {
throw new Error(`Unable to get available versions from ${resourceUrl}`);
}
const availableVersions = body.match(/(?<=<version>)[^<>]+(?=<\/version>)/g) || [];
core.debug(`Available Maven versions: [${availableVersions}]`);
return availableVersions;
}
/**
* Download and extract a specified Maven version to the tool-cache.
*/
export async function downloadMaven(fullVersion: string): Promise<string> {
const toolDirectoryName = `apache-maven-${fullVersion}`;
const downloadUrl = `${DOWNLOAD_BASE_URL}/${fullVersion}/${toolDirectoryName}-bin.tar.gz`;
core.info(`Downloading Maven ${fullVersion} from ${downloadUrl} ...`);
const downloadPath = await tc.downloadTool(downloadUrl);
const extractedPath = await tc.extractTar(downloadPath);
const toolRoot = path.join(extractedPath, toolDirectoryName);
return tc.cacheDir(toolRoot, 'maven', version);
return tc.cacheDir(toolRoot, 'maven', fullVersion);
}
export async function findVersionForDownload(versionSpec: string): Promise<string> {
const availableVersions = await getAvailableVersions();
const resolvedVersion = semver.maxSatisfying(availableVersions, versionSpec);
if (!resolvedVersion) {
throw new Error(`Could not find satisfied version for SemVer ${versionSpec}`);
}
core.debug(`Resolved version for download: ${resolvedVersion}`);
return resolvedVersion;
}

26
src/main.ts Normal file
View File

@ -0,0 +1,26 @@
import * as core from '@actions/core';
import * as semver from 'semver';
import { getActiveMavenVersion } from './utils';
import { setupMaven } from './installer';
export async function run() {
try {
const versionSpec = core.getInput('maven-version') || '3';
if (!semver.validRange(versionSpec)) {
core.setFailed(`Invalid SemVer notation '${versionSpec}' for a Maven version`);
return;
}
let installedVersion = await getActiveMavenVersion();
if (installedVersion && !semver.satisfies(installedVersion, versionSpec)) {
installedVersion = undefined;
}
installedVersion = await setupMaven(versionSpec, installedVersion);
core.setOutput('version', installedVersion);
} catch (error) {
core.setFailed(error.toString());
}
}

View File

@ -1,17 +1,4 @@
import * as core from '@actions/core';
import * as installer from './installer';
async function run() {
try {
const version = core.getInput('maven-version');
if (version) {
await installer.getMaven(version);
}
} catch (error) {
core.setFailed(error.message);
}
}
import { run } from './main';
// noinspection JSIgnoredPromiseFromCall
run();

47
src/utils.ts Normal file
View File

@ -0,0 +1,47 @@
import * as path from 'path';
import * as core from '@actions/core';
import * as exec from '@actions/exec';
export function getVersionFromToolcachePath(toolPath: string) {
return !toolPath ? toolPath : path.basename(path.dirname(toolPath));
}
/**
* Determine version of the current used Maven.
*/
export async function getActiveMavenVersion(): Promise<string | undefined> {
try {
const { output } = await getExecOutput('mvn', ['-v']);
const found = output.match(/^[^\d]*(\S+)/);
const installedVersion = !found ? '' : found[1];
core.debug(`Retrieved activated Maven version: ${installedVersion}`);
return installedVersion;
} catch (error) {
core.info(`Failed to get activated Maven version. ${error}`);
}
return undefined;
}
/**
* Exec a command and get the standard output.
*
* @throws {Error} If the exit-code is non-zero.
*/
export async function getExecOutput(
command: string,
args?: string[]
): Promise<{ exitCode: number; output: string }> {
let output = '';
const exitCode = await exec.exec(command, args, {
silent: true,
listeners: {
stdout: (data: Buffer) => (output += data.toString())
}
});
return { exitCode, output };
}