Add support for maven/gradle versions

- Essentially use same concepts as jdk install to switch
  maven and gradle versions if those are defined with config.
- Bump to tool-cache 1.3.0 as 1.0.0 tries to use
  node_modules/@actions/tool-cache/scripts/externals/unzip which doesn't have
  execute flag so you'd get `Permission denied`
- `extractZipNix` in toolkit no longer support relative path so needs to
  resolve absolute path before passing file to these methods.
- Commit has my local build for `index.js` which probably should get
  recreated but makes it easier to test this from a PR branch.
- Fixes #40
This commit is contained in:
Janne Valkealahti 2020-01-17 12:58:57 +00:00
parent b52cd69bd2
commit 7b8939ae83
11 changed files with 801 additions and 33 deletions

View File

@ -32,11 +32,25 @@ steps:
- uses: actions/setup-java@v1
with:
java-version: '4.0.0'
architecture: x64
jdkFile: <path to jdkFile> # Optional - jdkFile to install java from. Useful for versions not found on Zulu Community CDN
- run: java -cp java HelloWorldApp
```
## Maven/Gradle Versions
```yaml
steps:
- uses: actions/checkout@v1
- uses: actions/setup-java@v1
with:
java-version: '9.0.4'
maven-version: '3.6.2'
maven-mirror: <uri to maven mirror directory> # Optional - defaults to https://archive.apache.org/dist/maven/maven-3/
maven-file: <path to maven-file> # Optional - to install maven from.
gradle-version: '5.6.2'
gradle-file: <path to gradle-file> # Optional - to install gradle from.
- run: java -cp java HelloWorldApp
```
## Matrix Testing
```yaml
jobs:

View File

@ -0,0 +1,127 @@
import io = require('@actions/io');
import fs = require('fs');
import path = require('path');
import child_process = require('child_process');
const toolDir = path.join(__dirname, 'runnerg', 'tools');
const tempDir = path.join(__dirname, 'runnerg', 'temp');
const gradleDir = path.join(__dirname, 'runnerg', 'gradle');
process.env['RUNNER_TOOL_CACHE'] = toolDir;
process.env['RUNNER_TEMP'] = tempDir;
import * as installer from '../src/gradle-installer';
let gradleFilePath = '';
let gradleUrl = '';
if (process.platform === 'win32') {
gradleFilePath = path.join(gradleDir, 'gradle_win.zip');
gradleUrl = 'https://services.gradle.org/distributions/gradle-6.0.1-bin.zip';
} else if (process.platform === 'darwin') {
gradleFilePath = path.join(gradleDir, 'gradle_mac.zip');
gradleUrl = 'https://services.gradle.org/distributions/gradle-6.0.1-bin.zip';
} else {
gradleFilePath = path.join(gradleDir, 'gradle_linux.zip');
gradleUrl = 'https://services.gradle.org/distributions/gradle-6.0.1-bin.zip';
}
describe('gradle installer tests', () => {
beforeAll(async () => {
await io.rmRF(toolDir);
await io.rmRF(tempDir);
await io.rmRF(gradleDir);
if (!fs.existsSync(`${gradleFilePath}.complete`)) {
// Download gradle
await io.mkdirP(gradleDir);
console.log('Downloading gradle');
child_process.execSync(`curl -L "${gradleUrl}" > "${gradleFilePath}"`);
// Write complete file so we know it was successful
fs.writeFileSync(`${gradleFilePath}.complete`, 'content');
}
}, 300000);
afterAll(async () => {
try {
await io.rmRF(toolDir);
await io.rmRF(tempDir);
await io.rmRF(gradleDir);
} catch {
console.log('Failed to remove test directories');
}
}, 100000);
it('Installs version of Gradle from gradleFile if no matching version is installed', async () => {
await installer.getGradle('6.0.1', gradleFilePath);
const gradleDir = path.join(toolDir, 'gradle', '6.0.1', 'x64');
expect(fs.existsSync(`${gradleDir}.complete`)).toBe(true);
expect(fs.existsSync(path.join(gradleDir, 'bin'))).toBe(true);
}, 100000);
it('Throws if invalid directory to gradle', async () => {
let thrown = false;
try {
await installer.getGradle('1000', 'bad path');
} catch {
thrown = true;
}
expect(thrown).toBe(true);
});
it('Downloads gradle if no file given', async () => {
await installer.getGradle('5.6.3', '');
const gradleDir = path.join(toolDir, 'gradle', '5.6.3', 'x64');
expect(fs.existsSync(`${gradleDir}.complete`)).toBe(true);
expect(fs.existsSync(path.join(gradleDir, 'bin'))).toBe(true);
}, 100000);
it('Downloads gradle with 1.x syntax', async () => {
await installer.getGradle('4.10', '');
const gradleDir = path.join(toolDir, 'gradle', '4.10.3', 'x64');
expect(fs.existsSync(`${gradleDir}.complete`)).toBe(true);
expect(fs.existsSync(path.join(gradleDir, 'bin'))).toBe(true);
}, 100000);
it('Downloads gradle with normal semver syntax', async () => {
await installer.getGradle('4.8.x', '');
const gradleDir = path.join(toolDir, 'gradle', '4.8.1', 'x64');
expect(fs.existsSync(`${gradleDir}.complete`)).toBe(true);
expect(fs.existsSync(path.join(gradleDir, 'bin'))).toBe(true);
}, 100000);
it('Throws if invalid directory to gradle', async () => {
let thrown = false;
try {
await installer.getGradle('1000', 'bad path');
} catch {
thrown = true;
}
expect(thrown).toBe(true);
});
it('Uses version of gradle installed in cache', async () => {
const gradleDir: string = path.join(toolDir, 'gradle', '250.0.0', 'x64');
await io.mkdirP(gradleDir);
fs.writeFileSync(`${gradleDir}.complete`, 'hello');
// This will throw if it doesn't find it in the cache (because no such version exists)
await installer.getGradle('250', 'path shouldnt matter, found in cache');
return;
});
it('Doesnt use version of gradle that was only partially installed in cache', async () => {
const gradleDir: string = path.join(toolDir, 'gradle', '251.0.0', 'x64');
await io.mkdirP(gradleDir);
let thrown = false;
try {
// This will throw if it doesn't find it in the cache (because no such version exists)
await installer.getGradle('251', 'bad path');
} catch {
thrown = true;
}
expect(thrown).toBe(true);
return;
});
});

View File

@ -0,0 +1,134 @@
import io = require('@actions/io');
import fs = require('fs');
import path = require('path');
import child_process = require('child_process');
const toolDir = path.join(__dirname, 'runnerm', 'tools');
const tempDir = path.join(__dirname, 'runnerm', 'temp');
const mavenDir = path.join(__dirname, 'runnerm', 'maven');
process.env['RUNNER_TOOL_CACHE'] = toolDir;
process.env['RUNNER_TEMP'] = tempDir;
import * as installer from '../src/maven-installer';
let mavenFilePath = '';
let mavenUrl = '';
if (process.platform === 'win32') {
mavenFilePath = path.join(mavenDir, 'maven_win.zip');
mavenUrl =
'https://archive.apache.org/dist/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.zip';
} else if (process.platform === 'darwin') {
mavenFilePath = path.join(mavenDir, 'maven_mac.tar.gz');
mavenUrl =
'https://archive.apache.org/dist/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz';
} else {
mavenFilePath = path.join(mavenDir, 'maven_linux.tar.gz');
mavenUrl =
'https://archive.apache.org/dist/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz';
}
describe('maven installer tests', () => {
beforeAll(async () => {
await io.rmRF(toolDir);
await io.rmRF(tempDir);
await io.rmRF(mavenDir);
if (!fs.existsSync(`${mavenFilePath}.complete`)) {
// Download maven
await io.mkdirP(mavenDir);
console.log('Downloading maven');
child_process.execSync(`curl "${mavenUrl}" > "${mavenFilePath}"`);
// Write complete file so we know it was successful
fs.writeFileSync(`${mavenFilePath}.complete`, 'content');
}
}, 300000);
afterAll(async () => {
try {
await io.rmRF(toolDir);
await io.rmRF(tempDir);
await io.rmRF(mavenDir);
} catch {
console.log('Failed to remove test directories');
}
}, 100000);
it('Installs version of Maven from maven-file if no matching version is installed', async () => {
await installer.getMaven(
'3.6.3',
mavenFilePath,
'https://archive.apache.org/dist/maven/maven-3/'
);
const mavenDir = path.join(toolDir, 'maven', '3.6.3', 'x64');
expect(fs.existsSync(`${mavenDir}.complete`)).toBe(true);
expect(fs.existsSync(path.join(mavenDir, 'bin'))).toBe(true);
}, 100000);
it('Throws if invalid directory to maven', async () => {
let thrown = false;
try {
await installer.getMaven('1000', 'bad path');
} catch {
thrown = true;
}
expect(thrown).toBe(true);
});
it('Downloads maven if no file given', async () => {
await installer.getMaven('3.6.2', '');
const mavenDir = path.join(toolDir, 'maven', '3.6.2', 'x64');
expect(fs.existsSync(`${mavenDir}.complete`)).toBe(true);
expect(fs.existsSync(path.join(mavenDir, 'bin'))).toBe(true);
}, 100000);
it('Downloads maven with 1.x syntax', async () => {
await installer.getMaven('3.1', '');
const mavenDir = path.join(toolDir, 'maven', '3.1.1', 'x64');
expect(fs.existsSync(`${mavenDir}.complete`)).toBe(true);
expect(fs.existsSync(path.join(mavenDir, 'bin'))).toBe(true);
}, 100000);
it('Downloads maven with normal semver syntax', async () => {
await installer.getMaven('3.5.x', '');
const mavenDir = path.join(toolDir, 'maven', '3.5.4', 'x64');
expect(fs.existsSync(`${mavenDir}.complete`)).toBe(true);
expect(fs.existsSync(path.join(mavenDir, 'bin'))).toBe(true);
}, 100000);
it('Throws if invalid directory to maven', async () => {
let thrown = false;
try {
await installer.getMaven('1000', 'bad path');
} catch {
thrown = true;
}
expect(thrown).toBe(true);
});
it('Uses version of Maven installed in cache', async () => {
const mavenDir: string = path.join(toolDir, 'maven', '250.0.0', 'x64');
await io.mkdirP(mavenDir);
fs.writeFileSync(`${mavenDir}.complete`, 'hello');
// This will throw if it doesn't find it in the cache (because no such version exists)
await installer.getMaven('250', 'path shouldnt matter, found in cache');
return;
});
it('Doesnt use version of Maven that was only partially installed in cache', async () => {
const mavenDir: string = path.join(toolDir, 'maven', '251.0.0', 'x64');
await io.mkdirP(mavenDir);
let thrown = false;
try {
// This will throw if it doesn't find it in the cache (because no such version exists)
await installer.getMaven('251', 'bad path');
} catch {
thrown = true;
}
expect(thrown).toBe(true);
return;
});
});

View File

@ -34,6 +34,26 @@ inputs:
settings-path:
description: 'Path to where the settings.xml file will be written. Default is ~/.m2.'
required: false
maven-version:
description: 'The Maven version to make available on the path. Takes a whole
or semver Maven version, or 3.x syntax (e.g. 3.6 => Maven 3.x)'
required: false
maven-file:
description: 'Path to where the compressed Maven is located. The path could
be in your source repository or a local path on the agent.'
required: false
maven-mirror:
description: 'Uri hosting Maven3 mirror packages.'
required: false
default: 'https://archive.apache.org/dist/maven/maven-3/'
gradle-version:
description: 'The Gradle version to make available on the path. Takes a whole
or semver Gradle version, or 6.x syntax (e.g. 6.0 => Gradle 6.x)'
required: false
gradle-file:
description: 'Path to where the compressed Gradle is located. The path could
be in your source repository or a local path on the agent.'
required: false
runs:
using: 'node12'
main: 'dist/index.js'

BIN
dist/index.js generated vendored

Binary file not shown.

82
package-lock.json generated
View File

@ -5,31 +5,48 @@
"requires": true,
"dependencies": {
"@actions/core": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.0.0.tgz",
"integrity": "sha512-aMIlkx96XH4E/2YZtEOeyrYQfhlas9jIRkfGPqMwXD095Rdkzo4lB6ZmbxPQSzD+e1M+Xsm98ZhuSMYGv/AlqA=="
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.1.tgz",
"integrity": "sha512-xD+CQd9p4lU7ZfRqmUcbJpqR+Ss51rJRVeXMyOLrZQImN9/8Sy/BEUBnHO/UKD3z03R686PVTLfEPmkropGuLw=="
},
"@actions/exec": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.0.0.tgz",
"integrity": "sha512-nquH0+XKng+Ll7rZfCojN7NWSbnGh+ltwUJhzfbLkmOJgxocGX2/yXcZLMyT9fa7+tByEow/NSTrBExNlEj9fw=="
},
"@actions/http-client": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.1.tgz",
"integrity": "sha512-vy5DhqTJ1gtEkpRrD/6BHhUlkeyccrOX0BT9KmtO5TWxe5KSSwVHFE+J15Z0dG+tJwZJ/nHC4slUIyqpkahoMg=="
},
"@actions/io": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.0.0.tgz",
"integrity": "sha512-ezrJSRdqtXtdx1WXlfYL85+40F7gB39jCK9P0jZVODW3W6xUYmu6ZOEc/UmmElUwhRyDRm1R4yNZu1Joq2kuQg=="
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.0.2.tgz",
"integrity": "sha512-J8KuFqVPr3p6U8W93DOXlXW6zFvrQAJANdS+vw0YhusLIq+bszW8zmK2Fh1C2kDPX8FMvwIl1OUcFgvJoXLbAg=="
},
"@actions/tool-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-1.0.0.tgz",
"integrity": "sha512-l3zT0IfDfi5Ik5aMpnXqGHGATxN8xa9ls4ue+X/CBXpPhRMRZS4vcuh5Q9T98WAGbkysRCfhpbksTPHIcKnNwQ==",
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-1.3.0.tgz",
"integrity": "sha512-pbv32I89niDShw1YTDo0OFQmWPkZPElE7e3So1jfEzjIyzGRfYIzshwOVhemJZLcDtzo3kxO3GFDAmuVvub/6w==",
"requires": {
"@actions/core": "^1.0.0",
"@actions/core": "^1.2.0",
"@actions/exec": "^1.0.0",
"@actions/io": "^1.0.0",
"@actions/http-client": "^1.0.1",
"@actions/io": "^1.0.1",
"semver": "^6.1.0",
"typed-rest-client": "^1.4.0",
"uuid": "^3.3.2"
},
"dependencies": {
"@actions/core": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.1.tgz",
"integrity": "sha512-xD+CQd9p4lU7ZfRqmUcbJpqR+Ss51rJRVeXMyOLrZQImN9/8Sy/BEUBnHO/UKD3z03R686PVTLfEPmkropGuLw=="
},
"@actions/io": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.0.2.tgz",
"integrity": "sha512-J8KuFqVPr3p6U8W93DOXlXW6zFvrQAJANdS+vw0YhusLIq+bszW8zmK2Fh1C2kDPX8FMvwIl1OUcFgvJoXLbAg=="
}
}
},
"@babel/code-frame": {
@ -1711,7 +1728,8 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"aproba": {
"version": "1.2.0",
@ -1732,12 +1750,14 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -1752,17 +1772,20 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
@ -1879,7 +1902,8 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"ini": {
"version": "1.3.5",
@ -1891,6 +1915,7 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@ -1905,6 +1930,7 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@ -1912,12 +1938,14 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"minipass": {
"version": "2.3.5",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@ -1936,6 +1964,7 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@ -2016,7 +2045,8 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
@ -2028,6 +2058,7 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@ -2113,7 +2144,8 @@
"safe-buffer": {
"version": "5.1.2",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
@ -2149,6 +2181,7 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@ -2168,6 +2201,7 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@ -2211,12 +2245,14 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"yallist": {
"version": "3.0.3",
"bundled": true,
"dev": true
"dev": true,
"optional": true
}
}
},

View File

@ -24,10 +24,10 @@
"author": "GitHub",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.0.0",
"@actions/core": "^1.2.1",
"@actions/exec": "^1.0.0",
"@actions/io": "^1.0.0",
"@actions/tool-cache": "^1.0.0",
"@actions/io": "^1.0.2",
"@actions/tool-cache": "^1.3.0",
"semver": "^6.1.1",
"typed-rest-client": "1.5.0"
},

204
src/gradle-installer.ts Normal file
View File

@ -0,0 +1,204 @@
let tempDirectory = process.env['RUNNER_TEMP'] || '';
import * as core from '@actions/core';
import * as io from '@actions/io';
import * as tc from '@actions/tool-cache';
import * as fs from 'fs';
import * as path from 'path';
import * as semver from 'semver';
import * as httpm from 'typed-rest-client/HttpClient';
const IS_WINDOWS = process.platform === 'win32';
if (!tempDirectory) {
let baseLocation;
if (IS_WINDOWS) {
// On windows use the USERPROFILE env variable
baseLocation = process.env['USERPROFILE'] || 'C:\\';
} else {
if (process.platform === 'darwin') {
baseLocation = '/Users';
} else {
baseLocation = '/home';
}
}
tempDirectory = path.join(baseLocation, 'actions', 'temp');
}
export async function getGradle(
version: string,
gradleFile: string,
gradleMirror: string = 'https://services.gradle.org/distributions/'
): Promise<void> {
const toolName = 'gradle';
let toolPath = tc.find(toolName, version);
if (toolPath) {
core.debug(`Tool found in cache ${toolPath}`);
} else {
let compressedFileExtension = '';
if (!gradleFile) {
core.debug('Downloading Gradle from gradle.org');
let http: httpm.HttpClient = new httpm.HttpClient('spring-build-action');
let contents = await (await http.get(gradleMirror)).readBody();
let refs: string[] = [];
const regex = /<span class=\"name\">gradle-([\d\.]+)-bin\.zip<\/span>/g;
let match = regex.exec(contents);
while (match != null) {
refs.push(match[1]);
match = regex.exec(contents);
}
core.debug(`Found refs ${refs}`);
const downloadInfo = getDownloadInfo(refs, version, gradleMirror);
gradleFile = await tc.downloadTool(downloadInfo.url);
version = downloadInfo.version;
compressedFileExtension = '.zip';
} else {
core.debug('Retrieving Gradle from local path');
}
compressedFileExtension =
compressedFileExtension || getFileEnding(gradleFile);
let tempDir: string = path.join(
tempDirectory,
'temp_' + Math.floor(Math.random() * 2000000000)
);
const gradleDir = await unzipGradleDownload(
gradleFile,
compressedFileExtension,
tempDir
);
core.debug(`gradle extracted to ${gradleDir}`);
toolPath = await tc.cacheDir(
gradleDir,
toolName,
getCacheVersionString(version)
);
}
core.exportVariable('GRADLE_HOME', toolPath);
core.addPath(path.join(toolPath, 'bin'));
}
function getCacheVersionString(version: string) {
const versionArray = version.split('.');
const major = versionArray[0];
const minor = versionArray.length > 1 ? versionArray[1] : '0';
const patch = versionArray.length > 2 ? versionArray[2] : '0';
return `${major}.${minor}.${patch}`;
}
function getFileEnding(file: string): string {
let fileEnding = '';
if (file.endsWith('.zip')) {
fileEnding = '.zip';
} else {
throw new Error(`${file} has an unsupported file extension`);
}
return fileEnding;
}
async function extractFiles(
file: string,
fileEnding: string,
destinationFolder: string
): Promise<void> {
const stats = fs.statSync(file);
if (!stats) {
throw new Error(`Failed to extract ${file} - it doesn't exist`);
} else if (stats.isDirectory()) {
throw new Error(`Failed to extract ${file} - it is a directory`);
}
if ('.zip' === fileEnding) {
await tc.extractZip(file, destinationFolder);
} else {
throw new Error(`Failed to extract ${file} - only .zip supported`);
}
}
async function unzipGradleDownload(
repoRoot: string,
fileEnding: string,
destinationFolder: string
): Promise<string> {
// Create the destination folder if it doesn't exist
await io.mkdirP(destinationFolder);
const gradleFile = path.normalize(repoRoot);
const stats = fs.statSync(gradleFile);
if (stats.isFile()) {
await extractFiles(path.resolve(gradleFile), fileEnding, destinationFolder);
const gradleDirectory = path.join(
destinationFolder,
fs.readdirSync(destinationFolder)[0]
);
return gradleDirectory;
} else {
throw new Error(`Gradle argument ${gradleFile} is not a file`);
}
}
function getDownloadInfo(
refs: string[],
version: string,
gradleMirror: string
): {version: string; url: string} {
version = normalizeVersion(version);
const extension = '.zip';
// Maps version to url
let versionMap = new Map();
// Filter by platform
refs.forEach(ref => {
if (semver.satisfies(ref, version)) {
core.debug(`VersionMap add ${ref} ${version}`);
versionMap.set(ref, `${gradleMirror}gradle-${ref}-bin${extension}`);
}
});
// Choose the most recent satisfying version
let curVersion = '0.0.0';
let curUrl = '';
for (const entry of versionMap.entries()) {
const entryVersion = entry[0];
const entryUrl = entry[1];
core.debug(`VersionMap Entry ${entryVersion} ${entryUrl}`);
if (semver.gt(entryVersion, curVersion)) {
core.debug(`VersionMap semver gt ${entryVersion} ${entryUrl}`);
curUrl = entryUrl;
curVersion = entryVersion;
}
}
if (curUrl == '') {
throw new Error(
`No valid download found for version ${version}. Check ${gradleMirror} for a list of valid versions or download your own gradle file and add the gradleFile argument`
);
}
return {version: curVersion, url: curUrl};
}
function normalizeVersion(version: string): string {
if (version.slice(0, 2) === '1.') {
// Trim leading 1. for versions like 1.8
version = version.slice(2);
if (!version) {
throw new Error('1. is not a valid version');
}
}
if (version.split('.').length < 3) {
// Add trailing .x if it is missing
if (version[version.length - 1] != 'x') {
version = version + '.x';
}
}
return version;
}

View File

@ -118,12 +118,12 @@ async function extractFiles(
}
if ('.tar' === fileEnding || '.tar.gz' === fileEnding) {
await tc.extractTar(file, destinationFolder);
await tc.extractTar(path.resolve(file), destinationFolder);
} else if ('.zip' === fileEnding) {
await tc.extractZip(file, destinationFolder);
await tc.extractZip(path.resolve(file), destinationFolder);
} else {
// fall through and use sevenZip
await tc.extract7z(file, destinationFolder);
await tc.extract7z(path.resolve(file), destinationFolder);
}
}

218
src/maven-installer.ts Normal file
View File

@ -0,0 +1,218 @@
let tempDirectory = process.env['RUNNER_TEMP'] || '';
import * as core from '@actions/core';
import * as io from '@actions/io';
import * as tc from '@actions/tool-cache';
import * as fs from 'fs';
import * as path from 'path';
import * as semver from 'semver';
import * as httpm from 'typed-rest-client/HttpClient';
const IS_WINDOWS = process.platform === 'win32';
if (!tempDirectory) {
let baseLocation;
if (IS_WINDOWS) {
// On windows use the USERPROFILE env variable
baseLocation = process.env['USERPROFILE'] || 'C:\\';
} else {
if (process.platform === 'darwin') {
baseLocation = '/Users';
} else {
baseLocation = '/home';
}
}
tempDirectory = path.join(baseLocation, 'actions', 'temp');
}
export async function getMaven(
version: string,
mavenFile: string,
mavenMirror: string = 'https://archive.apache.org/dist/maven/maven-3/'
): Promise<void> {
const toolName = 'maven';
let toolPath = tc.find(toolName, version);
if (toolPath) {
core.debug(`Tool found in cache ${toolPath}`);
} else {
let compressedFileExtension = '';
if (!mavenFile) {
core.debug('Downloading Maven from Apache Mirror');
let http: httpm.HttpClient = new httpm.HttpClient('spring-build-action');
let contents = await (await http.get(mavenMirror)).readBody();
let refs: string[] = [];
const regex = /<a href=\"\d.*\">([\d\.]+)\/<\/a>/g;
let match = regex.exec(contents);
while (match != null) {
refs.push(match[1]);
match = regex.exec(contents);
}
core.debug(`Found refs ${refs}`);
const downloadInfo = getDownloadInfo(refs, version, mavenMirror);
mavenFile = await tc.downloadTool(downloadInfo.url);
version = downloadInfo.version;
compressedFileExtension = IS_WINDOWS ? '.zip' : '.tar.gz';
} else {
core.debug('Retrieving Maven from local path');
}
compressedFileExtension =
compressedFileExtension || getFileEnding(mavenFile);
let tempDir: string = path.join(
tempDirectory,
'temp_' + Math.floor(Math.random() * 2000000000)
);
const mavenDir = await unzipMavenDownload(
mavenFile,
compressedFileExtension,
tempDir
);
core.debug(`maven extracted to ${mavenDir}`);
toolPath = await tc.cacheDir(
mavenDir,
toolName,
getCacheVersionString(version)
);
}
core.exportVariable('M2_HOME', toolPath);
core.addPath(path.join(toolPath, 'bin'));
}
function getCacheVersionString(version: string) {
const versionArray = version.split('.');
const major = versionArray[0];
const minor = versionArray.length > 1 ? versionArray[1] : '0';
const patch = versionArray.length > 2 ? versionArray[2] : '0';
return `${major}.${minor}.${patch}`;
}
function getFileEnding(file: string): string {
let fileEnding = '';
if (file.endsWith('.tar.gz')) {
fileEnding = '.tar.gz';
} else if (file.endsWith('.zip')) {
fileEnding = '.zip';
} else {
throw new Error(`${file} has an unsupported file extension`);
}
return fileEnding;
}
async function extractFiles(
file: string,
fileEnding: string,
destinationFolder: string
): Promise<void> {
const stats = fs.statSync(file);
if (!stats) {
throw new Error(`Failed to extract ${file} - it doesn't exist`);
} else if (stats.isDirectory()) {
throw new Error(`Failed to extract ${file} - it is a directory`);
}
if ('.tar.gz' === fileEnding) {
await tc.extractTar(file, destinationFolder);
} else if ('.zip' === fileEnding) {
await tc.extractZip(file, destinationFolder);
} else {
throw new Error(
`Failed to extract ${file} - only .zip or .tar.gz supported`
);
}
}
async function unzipMavenDownload(
repoRoot: string,
fileEnding: string,
destinationFolder: string
): Promise<string> {
// Create the destination folder if it doesn't exist
await io.mkdirP(destinationFolder);
const mavenFile = path.normalize(repoRoot);
const stats = fs.statSync(mavenFile);
if (stats.isFile()) {
await extractFiles(path.resolve(mavenFile), fileEnding, destinationFolder);
const mavenDirectory = path.join(
destinationFolder,
fs.readdirSync(destinationFolder)[0]
);
return mavenDirectory;
} else {
throw new Error(`Maven argument ${mavenFile} is not a file`);
}
}
function getDownloadInfo(
refs: string[],
version: string,
mavenMirror: string
): {version: string; url: string} {
version = normalizeVersion(version);
let extension = '';
if (IS_WINDOWS) {
extension = `.zip`;
} else {
extension = `.tar.gz`;
}
// Maps version to url
let versionMap = new Map();
// Filter by platform
refs.forEach(ref => {
if (semver.satisfies(ref, version)) {
core.debug(`VersionMap add ${ref} ${version}`);
versionMap.set(
ref,
`${mavenMirror}${ref}/binaries/apache-maven-${ref}-bin${extension}`
);
}
});
// Choose the most recent satisfying version
let curVersion = '0.0.0';
let curUrl = '';
for (const entry of versionMap.entries()) {
const entryVersion = entry[0];
const entryUrl = entry[1];
core.debug(`VersionMap Entry ${entryVersion} ${entryUrl}`);
if (semver.gt(entryVersion, curVersion)) {
core.debug(`VersionMap semver gt ${entryVersion} ${entryUrl}`);
curUrl = entryUrl;
curVersion = entryVersion;
}
}
if (curUrl == '') {
throw new Error(
`No valid download found for version ${version}. Check ${mavenMirror} for a list of valid versions or download your own maven file and add the mavenFile argument`
);
}
return {version: curVersion, url: curUrl};
}
function normalizeVersion(version: string): string {
if (version.slice(0, 2) === '1.') {
// Trim leading 1. for versions like 1.8
version = version.slice(2);
if (!version) {
throw new Error('1. is not a valid version');
}
}
if (version.split('.').length < 3) {
// Add trailing .x if it is missing
if (version[version.length - 1] != 'x') {
version = version + '.x';
}
}
return version;
}

View File

@ -1,5 +1,7 @@
import * as core from '@actions/core';
import * as installer from './installer';
import * as mavenInstaller from './maven-installer';
import * as gradleInstaller from './gradle-installer';
import * as auth from './auth';
import * as path from 'path';
@ -15,6 +17,19 @@ async function run() {
await installer.getJava(version, arch, jdkFile, javaPackage);
const mavenVersion = core.getInput('maven-version', {required: false});
const mavenFile = core.getInput('maven-file', {required: false}) || '';
const mavenMirror = core.getInput('maven-mirror', {required: false});
if (mavenVersion) {
await mavenInstaller.getMaven(mavenVersion, mavenFile, mavenMirror);
}
const gradleVersion = core.getInput('gradle-version', {required: false});
const gradleFile = core.getInput('gradle-file', {required: false}) || '';
if (gradleVersion) {
await gradleInstaller.getGradle(gradleVersion, gradleFile);
}
const matchersPath = path.join(__dirname, '..', '.github');
console.log(`##[add-matcher]${path.join(matchersPath, 'java.json')}`);