From b6dbbd52325d3661aaf57d019849e21e4e91ba22 Mon Sep 17 00:00:00 2001 From: Danny McCormick Date: Thu, 18 Jul 2019 16:00:58 -0400 Subject: [PATCH] Handle semver (#8) * Handle semver * Clean up --- README.md | 4 +- __tests__/installer.test.ts | 16 ++++++ action.yml | 2 +- lib/installer.js | 96 ++++++++++++++++++++++++--------- src/installer.ts | 105 ++++++++++++++++++++++++++++-------- 5 files changed, 172 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index 18a6f66b..7b86512f 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Basic: actions: - uses: actions/setup-java@latest with: - version: 9.0.4 // The JDK version to make available on the path. Use a whole version, such as 9.0.4, not a semver version + version: 9.0.4 // The JDK version to make available on the path. Takes a whole or semver Jdk version, or 1.x syntax (e.g. 1.8 => Jdk 8.x) architecture: x64 // (x64 or x86) - defaults to x64 - run: java -cp java HelloWorldApp ``` @@ -36,7 +36,7 @@ jobs: build: strategy: matrix: - java: [ 6.0.119, 9.0.4, 12.0.2 ] + java: [ 1.6, 9.0.x, 12.0.2 ] name: Java ${{ matrix.java }} sample actions: - name: Setup java diff --git a/__tests__/installer.test.ts b/__tests__/installer.test.ts index 4e891e90..4298dde0 100644 --- a/__tests__/installer.test.ts +++ b/__tests__/installer.test.ts @@ -77,6 +77,22 @@ describe('installer tests', () => { expect(fs.existsSync(path.join(JavaDir, 'bin'))).toBe(true); }, 100000); + it('Downloads java with 1.x syntax', async () => { + await installer.getJava('1.10', 'x64', ''); + const JavaDir = path.join(toolDir, 'Java', '10.0.2', 'x64'); + + expect(fs.existsSync(`${JavaDir}.complete`)).toBe(true); + expect(fs.existsSync(path.join(JavaDir, 'bin'))).toBe(true); + }, 100000); + + it('Downloads java with normal semver syntax', async () => { + await installer.getJava('9.0.x', 'x64', ''); + const JavaDir = path.join(toolDir, 'Java', '9.0.7', 'x64'); + + expect(fs.existsSync(`${JavaDir}.complete`)).toBe(true); + expect(fs.existsSync(path.join(JavaDir, 'bin'))).toBe(true); + }, 100000); + it('Throws if invalid directory to jdk', async () => { let thrown = false; try { diff --git a/action.yml b/action.yml index 8fd8ec6d..d8891ca4 100644 --- a/action.yml +++ b/action.yml @@ -3,7 +3,7 @@ description: 'Setup your runner with Java' author: 'GitHub' inputs: version: - description: 'The JDK version to make available on the path. Use a whole version, such as 9.0.4' + description: 'The JDK version to make available on the path. Takes a whole or semver Jdk version, or 1.x syntax (e.g. 1.8 => Jdk 8.x)' required: true architecture: description: 'The architecture (x86, x64) of the JDK.' diff --git a/lib/installer.js b/lib/installer.js index 14bfd136..8fd3a272 100644 --- a/lib/installer.js +++ b/lib/installer.js @@ -22,6 +22,7 @@ const exec = __importStar(require("@actions/exec")); const tc = __importStar(require("@actions/tool-cache")); const fs = __importStar(require("fs")); const path = __importStar(require("path")); +const semver = __importStar(require("semver")); const httpm = __importStar(require("typed-rest-client/HttpClient")); const IS_WINDOWS = process.platform === 'win32'; if (!tempDirectory) { @@ -50,7 +51,12 @@ function getJava(version, arch, jdkFile) { let compressedFileExtension = ''; if (!jdkFile) { core.debug('Downloading Jdk from Azul'); - jdkFile = yield downloadJava(version); + let http = new httpm.HttpClient('setup-java'); + let contents = yield (yield http.get('https://static.azul.com/zulu/bin/')).readBody(); + let refs = contents.match(//gi) || []; + const downloadInfo = getDownloadInfo(refs, version); + jdkFile = yield tc.downloadTool(downloadInfo.url); + version = downloadInfo.version; compressedFileExtension = IS_WINDOWS ? '.zip' : '.tar.gz'; } else { @@ -60,7 +66,7 @@ function getJava(version, arch, jdkFile) { let tempDir = path.join(tempDirectory, 'temp_' + Math.floor(Math.random() * 2000000000)); const jdkDir = yield unzipJavaDownload(jdkFile, compressedFileExtension, tempDir); core.debug(`jdk extracted to ${jdkDir}`); - toolPath = yield tc.cacheDir(jdkDir, 'Java', normalizeVersion(version), arch); + toolPath = yield tc.cacheDir(jdkDir, 'Java', getCacheVersionString(version), arch); } let extendedJavaHome = 'JAVA_HOME_' + version + '_' + arch; core.exportVariable('JAVA_HOME', toolPath); @@ -69,7 +75,7 @@ function getJava(version, arch, jdkFile) { }); } exports.getJava = getJava; -function normalizeVersion(version) { +function getCacheVersionString(version) { const versionArray = version.split('.'); const major = versionArray[0]; const minor = versionArray.length > 1 ? versionArray[1] : '0'; @@ -156,32 +162,70 @@ function unzipJavaDownload(repoRoot, fileEnding, destinationFolder, extension) { } }); } -function downloadJava(version) { - return __awaiter(this, void 0, void 0, function* () { - let filterString = ''; - if (IS_WINDOWS) { - filterString = `jdk${version}-win_x64.zip`; +function getDownloadInfo(refs, version) { + version = normalizeVersion(version); + let extension = ''; + if (IS_WINDOWS) { + extension = `-win_x64.zip`; + } + else { + if (process.platform === 'darwin') { + extension = `-macosx_x64.tar.gz`; } else { - if (process.platform === 'darwin') { - filterString = `jdk${version}-macosx_x64.tar.gz`; - } - else { - filterString = `jdk${version}-linux_x64.tar.gz`; - } + extension = `-linux_x64.tar.gz`; } - let http = new httpm.HttpClient('setup-java'); - let contents = yield (yield http.get('https://static.azul.com/zulu/bin/')).readBody(); - let refs = contents.match(//gi) || []; - refs = refs.filter(val => { - if (val.indexOf(filterString) > -1) { - return true; - } - }); - if (refs.length == 0) { - throw new Error(`No valid download found for version ${version}. Check https://static.azul.com/zulu/bin/ for a list of valid versions or download your own jdk file and add the jdkFile argument`); + } + // Maps version to url + let versionMap = new Map(); + // Filter by platform + refs.forEach(ref => { + if (ref.indexOf(extension) < 0) { + return; + } + // If we haven't returned, means we're looking at the correct platform + let versions = ref.match(/jdk.*-/gi) || []; + if (versions.length > 1) { + throw new Error(`Invalid ref received from https://static.azul.com/zulu/bin/: ${ref}`); + } + if (versions.length == 0) { + return; + } + const refVersion = versions[0].slice('jdk'.length, versions[0].length - 1); + if (semver.satisfies(refVersion, version)) { + versionMap.set(refVersion, 'https://static.azul.com/zulu/bin/' + + ref.slice(''.length)); } - const fileName = refs[0].slice(''.length); - return yield tc.downloadTool(`https://static.azul.com/zulu/bin/${fileName}`); }); + // 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]; + if (semver.gt(entryVersion, curVersion)) { + curUrl = entryUrl; + curVersion = entryVersion; + } + } + if (curUrl == '') { + throw new Error(`No valid download found for version ${version}. Check https://static.azul.com/zulu/bin/ for a list of valid versions or download your own jdk file and add the jdkFile argument`); + } + return { version: curVersion, url: curUrl }; +} +function normalizeVersion(version) { + 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'); + } + } + // Add trailing .x if it is missing + if (version.split('.').length != 3) { + if (version[version.length - 1] != 'x') { + version = version + '.x'; + } + } + return version; } diff --git a/src/installer.ts b/src/installer.ts index cb0ee0e1..a9b5f4f9 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -6,6 +6,7 @@ import * as exec from '@actions/exec'; 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'; @@ -38,7 +39,16 @@ export async function getJava( let compressedFileExtension = ''; if (!jdkFile) { core.debug('Downloading Jdk from Azul'); - jdkFile = await downloadJava(version); + let http: httpm.HttpClient = new httpm.HttpClient('setup-java'); + let contents = await (await http.get( + 'https://static.azul.com/zulu/bin/' + )).readBody(); + let refs = contents.match(//gi) || []; + + const downloadInfo = getDownloadInfo(refs, version); + + jdkFile = await tc.downloadTool(downloadInfo.url); + version = downloadInfo.version; compressedFileExtension = IS_WINDOWS ? '.zip' : '.tar.gz'; } else { core.debug('Retrieving Jdk from local path'); @@ -57,7 +67,7 @@ export async function getJava( toolPath = await tc.cacheDir( jdkDir, 'Java', - normalizeVersion(version), + getCacheVersionString(version), arch ); } @@ -68,7 +78,7 @@ export async function getJava( core.addPath(path.join(toolPath, 'bin')); } -function normalizeVersion(version: string) { +function getCacheVersionString(version: string) { const versionArray = version.split('.'); const major = versionArray[0]; const minor = versionArray.length > 1 ? versionArray[1] : '0'; @@ -161,37 +171,88 @@ async function unzipJavaDownload( } } -async function downloadJava(version: string): Promise { - let filterString = ''; +function getDownloadInfo( + refs: string[], + version: string +): {version: string; url: string} { + version = normalizeVersion(version); + let extension = ''; if (IS_WINDOWS) { - filterString = `jdk${version}-win_x64.zip`; + extension = `-win_x64.zip`; } else { if (process.platform === 'darwin') { - filterString = `jdk${version}-macosx_x64.tar.gz`; + extension = `-macosx_x64.tar.gz`; } else { - filterString = `jdk${version}-linux_x64.tar.gz`; + extension = `-linux_x64.tar.gz`; } } - let http: httpm.HttpClient = new httpm.HttpClient('setup-java'); - let contents = await (await http.get( - 'https://static.azul.com/zulu/bin/' - )).readBody(); - let refs = contents.match(//gi) || []; - refs = refs.filter(val => { - if (val.indexOf(filterString) > -1) { - return true; + + // Maps version to url + let versionMap = new Map(); + + // Filter by platform + refs.forEach(ref => { + if (ref.indexOf(extension) < 0) { + return; + } + + // If we haven't returned, means we're looking at the correct platform + let versions = ref.match(/jdk.*-/gi) || []; + if (versions.length > 1) { + throw new Error( + `Invalid ref received from https://static.azul.com/zulu/bin/: ${ref}` + ); + } + if (versions.length == 0) { + return; + } + const refVersion = versions[0].slice('jdk'.length, versions[0].length - 1); + + if (semver.satisfies(refVersion, version)) { + versionMap.set( + refVersion, + 'https://static.azul.com/zulu/bin/' + + ref.slice(''.length) + ); } }); - if (refs.length == 0) { + // 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]; + if (semver.gt(entryVersion, curVersion)) { + curUrl = entryUrl; + curVersion = entryVersion; + } + } + + if (curUrl == '') { throw new Error( `No valid download found for version ${version}. Check https://static.azul.com/zulu/bin/ for a list of valid versions or download your own jdk file and add the jdkFile argument` ); } - const fileName = refs[0].slice( - ''.length - ); - return await tc.downloadTool(`https://static.azul.com/zulu/bin/${fileName}`); + 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'); + } + } + + // Add trailing .x if it is missing + if (version.split('.').length != 3) { + if (version[version.length - 1] != 'x') { + version = version + '.x'; + } + } + + return version; }