diff --git a/README.md b/README.md index d416f8334..23d182055 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ The `setup-java` action provides the following functionality for GitHub Actions - Caching dependencies managed by Gradle - Caching dependencies managed by sbt - [Maven Toolchains declaration](https://maven.apache.org/guides/mini/guide-using-toolchains.html) for specified JDK versions +- support for enterpries that are using a system that is proxying a repository located on a remote server. This action allows you to work with Java and Scala projects. @@ -60,6 +61,12 @@ This action allows you to work with Java and Scala projects. - `mvn-toolchain-vendor`: Name of Maven Toolchain Vendor if the default name of `${distribution}` is not wanted. + - `remote-repository-base-url`: The base url to the solution which houses and manages all the artifacts (ex: artifactory, nexus, etc.). If `remote-repository-base-url` is specified you also need to specify the `replace-download-link-base-url`. + + - `replace-download-link-base-url`: The base url of the download link, extracted from the metadata file, which must be substituted with the remote-repository-base-url. + + - `download-link-context`: Because the proxying of the artifacts it is higly dependent on the admin doing it, it might be that a context is needed to be postpended to the remote-repository-base-url. + ### Basic Configuration #### Eclipse Temurin @@ -231,6 +238,8 @@ In the example above multiple JDKs are installed for the same job. The result af - [Publishing using Gradle](docs/advanced-usage.md#Publishing-using-Gradle) - [Hosted Tool Cache](docs/advanced-usage.md#Hosted-Tool-Cache) - [Modifying Maven Toolchains](docs/advanced-usage.md#Modifying-Maven-Toolchains) +- [Modifying Maven Toolchains](docs/advanced-usage.md#Modifying-Maven-Toolchains) +- [Fetch binaries from the artifact proxy repository](docs/advanced-usage.md#Proxy-repositores) ## License diff --git a/__tests__/distributors/adopt-installer.test.ts b/__tests__/distributors/adopt-installer.test.ts index a900f858c..673b7065c 100644 --- a/__tests__/distributors/adopt-installer.test.ts +++ b/__tests__/distributors/adopt-installer.test.ts @@ -217,3 +217,302 @@ describe('findPackageForDownload', () => { ); }); }); + +describe('getAvailableVersionsFromProxy', () => { + let spyHttpClient: jest.SpyInstance; + + beforeEach(() => { + spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); + spyHttpClient.mockReturnValue({ + statusCode: 200, + headers: {}, + result: [] + }); + }); + + afterEach(() => { + jest.resetAllMocks(); + jest.clearAllMocks(); + jest.restoreAllMocks(); + }); + + it.each([ + [ + { + version: '11', + architecture: 'x64', + packageType: 'jdk', + checkLatest: false, + remoteRepositoryBaseUrl: 'https://test.artifactory.com' + }, + AdoptImplementation.Hotspot, + 'os=mac&architecture=x64&image_type=jdk&release_type=ga&jvm_impl=hotspot&page_size=20&page=0' + ], + [ + { + version: '11', + architecture: 'x86', + packageType: 'jdk', + checkLatest: false, + remoteRepositoryBaseUrl: 'https://test.artifactory.com' + }, + AdoptImplementation.Hotspot, + 'os=mac&architecture=x86&image_type=jdk&release_type=ga&jvm_impl=hotspot&page_size=20&page=0' + ], + [ + { + version: '11', + architecture: 'x64', + packageType: 'jre', + checkLatest: false, + remoteRepositoryBaseUrl: 'https://test.artifactory.com' + }, + AdoptImplementation.Hotspot, + 'os=mac&architecture=x64&image_type=jre&release_type=ga&jvm_impl=hotspot&page_size=20&page=0' + ], + [ + { + version: '11-ea', + architecture: 'x64', + packageType: 'jdk', + checkLatest: false, + remoteRepositoryBaseUrl: 'https://test.artifactory.com' + }, + AdoptImplementation.Hotspot, + 'os=mac&architecture=x64&image_type=jdk&release_type=ea&jvm_impl=hotspot&page_size=20&page=0' + ], + [ + { + version: '11', + architecture: 'x64', + packageType: 'jdk', + checkLatest: false, + remoteRepositoryBaseUrl: 'https://test.artifactory.com' + }, + AdoptImplementation.OpenJ9, + 'os=mac&architecture=x64&image_type=jdk&release_type=ga&jvm_impl=openj9&page_size=20&page=0' + ], + [ + { + version: '11', + architecture: 'x86', + packageType: 'jdk', + checkLatest: false, + remoteRepositoryBaseUrl: 'https://test.artifactory.com' + }, + AdoptImplementation.OpenJ9, + 'os=mac&architecture=x86&image_type=jdk&release_type=ga&jvm_impl=openj9&page_size=20&page=0' + ], + [ + { + version: '11', + architecture: 'x64', + packageType: 'jre', + checkLatest: false, + remoteRepositoryBaseUrl: 'https://test.artifactory.com' + }, + AdoptImplementation.OpenJ9, + 'os=mac&architecture=x64&image_type=jre&release_type=ga&jvm_impl=openj9&page_size=20&page=0' + ], + [ + { + version: '11-ea', + architecture: 'x64', + packageType: 'jdk', + checkLatest: false, + remoteRepositoryBaseUrl: 'https://test.artifactory.com' + }, + AdoptImplementation.OpenJ9, + 'os=mac&architecture=x64&image_type=jdk&release_type=ea&jvm_impl=openj9&page_size=20&page=0' + ] + ])( + 'build correct url for %s', + async ( + installerOptions: JavaInstallerOptions, + impl: AdoptImplementation, + expectedParameters + ) => { + const distribution = new AdoptDistribution(installerOptions, impl); + const baseUrl = 'https://test.artifactory.com/v3/assets/version/%5B1.0,100.0%5D'; + const expectedUrl = `${baseUrl}?project=jdk&vendor=adoptopenjdk&heap_size=normal&sort_method=DEFAULT&sort_order=DESC&${expectedParameters}`; + distribution['getPlatformOption'] = () => 'mac'; + + await distribution['getAvailableVersions'](); + + expect(spyHttpClient.mock.calls).toHaveLength(1); + expect(spyHttpClient.mock.calls[0][0]).toBe(expectedUrl); + } + ); + + it('load available versions', async () => { + spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); + spyHttpClient + .mockReturnValueOnce({ + statusCode: 200, + headers: {}, + result: manifestData + }) + .mockReturnValueOnce({ + statusCode: 200, + headers: {}, + result: manifestData + }) + .mockReturnValueOnce({ + statusCode: 200, + headers: {}, + result: [] + }); + + const distribution = new AdoptDistribution( + { + version: '11', + architecture: 'x64', + packageType: 'jdk', + checkLatest: false, + remoteRepositoryBaseUrl: 'https://test.artifactory.com' + }, + AdoptImplementation.Hotspot + ); + const availableVersions = await distribution['getAvailableVersions'](); + expect(availableVersions).not.toBeNull(); + expect(availableVersions.length).toBe(manifestData.length * 2); + }); + + it.each([ + [AdoptImplementation.Hotspot, 'jdk', 'Java_Adopt_jdk'], + [AdoptImplementation.Hotspot, 'jre', 'Java_Adopt_jre'], + [AdoptImplementation.OpenJ9, 'jdk', 'Java_Adopt-OpenJ9_jdk'], + [AdoptImplementation.OpenJ9, 'jre', 'Java_Adopt-OpenJ9_jre'] + ])( + 'find right toolchain folder', + (impl: AdoptImplementation, packageType: string, expected: string) => { + const distribution = new AdoptDistribution( + { + version: '11', + architecture: 'x64', + packageType: packageType, + checkLatest: false, + remoteRepositoryBaseUrl: 'https://test.artifactory.com' + }, + impl + ); + + // @ts-ignore - because it is protected + expect(distribution.toolcacheFolderName).toBe(expected); + } + ); + + it.each([ + ['amd64', 'x64'], + ['arm64', 'aarch64'] + ])( + 'defaults to os.arch(): %s mapped to distro arch: %s', + async (osArch: string, distroArch: string) => { + jest.spyOn(os, 'arch').mockReturnValue(osArch); + + const installerOptions: JavaInstallerOptions = { + version: '17', + architecture: '', // to get default value + packageType: 'jdk', + checkLatest: false, + remoteRepositoryBaseUrl: 'https://test.artifactory.com' + }; + + const expectedParameters = `os=mac&architecture=${distroArch}&image_type=jdk&release_type=ga&jvm_impl=hotspot&page_size=20&page=0`; + + const distribution = new AdoptDistribution(installerOptions, AdoptImplementation.Hotspot); + const baseUrl = 'https://test.artifactory.com/v3/assets/version/%5B1.0,100.0%5D'; + const expectedUrl = `${baseUrl}?project=jdk&vendor=adoptopenjdk&heap_size=normal&sort_method=DEFAULT&sort_order=DESC&${expectedParameters}`; + distribution['getPlatformOption'] = () => 'mac'; + + await distribution['getAvailableVersions'](); + + expect(spyHttpClient.mock.calls).toHaveLength(1); + expect(spyHttpClient.mock.calls[0][0]).toBe(expectedUrl); + } + ); +}); + +describe('findPackageForDownload', () => { + it.each([ + ['9', '9.0.7+10'], + ['15', '15.0.2+7'], + ['15.0', '15.0.2+7'], + ['15.0.2', '15.0.2+7'], + ['15.0.1', '15.0.1+9.1'], + ['11.x', '11.0.10+9'], + ['x', '15.0.2+7'], + ['12', '12.0.2+10.3'], // make sure that '12.0.2+10.1', '12.0.2+10.3', '12.0.2+10.2' are sorted correctly + ['12.0.2+10.1', '12.0.2+10.1'], + ['15.0.1+9', '15.0.1+9'], + ['15.0.1+9.1', '15.0.1+9.1'] + ])('version is resolved correctly %s -> %s', async (input, expected) => { + const distribution = new AdoptDistribution( + { + version: '11', + architecture: 'x64', + packageType: 'jdk', + checkLatest: false, + remoteRepositoryBaseUrl: 'https://test.artifactory.com', + replaceDownloadLinkBaseUrl: 'https://github.com/AdoptOpenJDK', + downloadLinkContext: '/AdoptOpenJDK' + }, + AdoptImplementation.Hotspot + ); + distribution['getAvailableVersions'] = async () => manifestData; + const resolvedVersion = await distribution['findPackageForDownload'](input); + expect(resolvedVersion.version).toBe(expected); + expect(resolvedVersion.url).toContain('https://test.artifactory.com/AdoptOpenJDK'); + }); + + it('version is found but binaries list is empty', async () => { + const distribution = new AdoptDistribution( + { + version: '11', + architecture: 'x64', + packageType: 'jdk', + checkLatest: false, + remoteRepositoryBaseUrl: 'https://test.artifactory.com' + }, + AdoptImplementation.Hotspot + ); + distribution['getAvailableVersions'] = async () => manifestData; + await expect(distribution['findPackageForDownload']('9.0.8')).rejects.toThrowError( + /Could not find satisfied version for SemVer */ + ); + }); + + it('version is not found', async () => { + const distribution = new AdoptDistribution( + { + version: '11', + architecture: 'x64', + packageType: 'jdk', + checkLatest: false, + remoteRepositoryBaseUrl: 'https://test.artifactory.com' + }, + AdoptImplementation.Hotspot + ); + distribution['getAvailableVersions'] = async () => manifestData; + await expect(distribution['findPackageForDownload']('7.x')).rejects.toThrowError( + /Could not find satisfied version for SemVer */ + ); + }); + + it('version list is empty', async () => { + const distribution = new AdoptDistribution( + { + version: '11', + architecture: 'x64', + packageType: 'jdk', + checkLatest: false, + remoteRepositoryBaseUrl: 'https://test.artifactory.com' + }, + AdoptImplementation.Hotspot + ); + distribution['getAvailableVersions'] = async () => []; + await expect(distribution['findPackageForDownload']('11')).rejects.toThrowError( + /Could not find satisfied version for SemVer */ + ); + }); +}); diff --git a/__tests__/distributors/base-installer.test.ts b/__tests__/distributors/base-installer.test.ts index 44ec50bb7..52948065b 100644 --- a/__tests__/distributors/base-installer.test.ts +++ b/__tests__/distributors/base-installer.test.ts @@ -15,6 +15,8 @@ import { import os from 'os'; class EmptyJavaBase extends JavaBase { + protected remoteMetadataBaseUrl = 'MUST STAY EMPTY'; + protected remoteBaseUrl = 'MUST STAY EMPTY'; constructor(installerOptions: JavaInstallerOptions) { super('Empty', installerOptions); } @@ -37,6 +39,10 @@ class EmptyJavaBase extends JavaBase { url: `some/random_url/java/${availableVersion}` }; } + + protected baseUrl(): string { + throw new Error('Method already tested in all distribution installers'); + } } describe('findInToolcache', () => { diff --git a/action.yml b/action.yml index 2c0f7aba3..55c7b5601 100644 --- a/action.yml +++ b/action.yml @@ -68,6 +68,15 @@ inputs: mvn-toolchain-vendor: description: 'Name of Maven Toolchain Vendor if the default name of "${distribution}" is not wanted. See examples of supported syntax in Advanced Usage file' required: false + remote-repository-base-url: + description: 'The base url to the solution which houses and manages all the artifacts (ex: artifactory, nexus, etc.)' + required: false + replace-download-link-base-url: + description: 'The base url of the download link, extracted from the metadata file, which must be substituted with the remote-repository-base-url. Sometimes you might need to specify the download link context to have a proper download link of the distribution.' + required: false + download-link-context: + description: 'Because the proxying of the artifacts it is higly dependent on the admin doing it, it might be that a context is needed to be postpended to the remote-repository-base-url.' + required: false outputs: distribution: description: 'Distribution of Java that has been installed' diff --git a/dist/cleanup/index.js b/dist/cleanup/index.js index 7a4f37bde..df9f611ec 100644 --- a/dist/cleanup/index.js +++ b/dist/cleanup/index.js @@ -68480,7 +68480,7 @@ else { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.DISTRIBUTIONS_ONLY_MAJOR_VERSION = exports.INPUT_MVN_TOOLCHAIN_VENDOR = exports.INPUT_MVN_TOOLCHAIN_ID = exports.MVN_TOOLCHAINS_FILE = exports.MVN_SETTINGS_FILE = exports.M2_DIR = exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = exports.INPUT_JOB_STATUS = exports.INPUT_CACHE = exports.INPUT_DEFAULT_GPG_PASSPHRASE = exports.INPUT_DEFAULT_GPG_PRIVATE_KEY = exports.INPUT_GPG_PASSPHRASE = exports.INPUT_GPG_PRIVATE_KEY = exports.INPUT_OVERWRITE_SETTINGS = exports.INPUT_SETTINGS_PATH = exports.INPUT_SERVER_PASSWORD = exports.INPUT_SERVER_USERNAME = exports.INPUT_SERVER_ID = exports.INPUT_CHECK_LATEST = exports.INPUT_JDK_FILE = exports.INPUT_DISTRIBUTION = exports.INPUT_JAVA_PACKAGE = exports.INPUT_ARCHITECTURE = exports.INPUT_JAVA_VERSION_FILE = exports.INPUT_JAVA_VERSION = exports.MACOS_JAVA_CONTENT_POSTFIX = void 0; +exports.DOWNLOAD_LINK_CONTEXT = exports.REPLACE_DOWNLOAD_LINK_BASE_URL = exports.REMOTE_REPOSITORY_BASE_URL = exports.DISTRIBUTIONS_ONLY_MAJOR_VERSION = exports.INPUT_MVN_TOOLCHAIN_VENDOR = exports.INPUT_MVN_TOOLCHAIN_ID = exports.MVN_TOOLCHAINS_FILE = exports.MVN_SETTINGS_FILE = exports.M2_DIR = exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = exports.INPUT_JOB_STATUS = exports.INPUT_CACHE = exports.INPUT_DEFAULT_GPG_PASSPHRASE = exports.INPUT_DEFAULT_GPG_PRIVATE_KEY = exports.INPUT_GPG_PASSPHRASE = exports.INPUT_GPG_PRIVATE_KEY = exports.INPUT_OVERWRITE_SETTINGS = exports.INPUT_SETTINGS_PATH = exports.INPUT_SERVER_PASSWORD = exports.INPUT_SERVER_USERNAME = exports.INPUT_SERVER_ID = exports.INPUT_CHECK_LATEST = exports.INPUT_JDK_FILE = exports.INPUT_DISTRIBUTION = exports.INPUT_JAVA_PACKAGE = exports.INPUT_ARCHITECTURE = exports.INPUT_JAVA_VERSION_FILE = exports.INPUT_JAVA_VERSION = exports.MACOS_JAVA_CONTENT_POSTFIX = void 0; exports.MACOS_JAVA_CONTENT_POSTFIX = 'Contents/Home'; exports.INPUT_JAVA_VERSION = 'java-version'; exports.INPUT_JAVA_VERSION_FILE = 'java-version-file'; @@ -68507,6 +68507,9 @@ exports.MVN_TOOLCHAINS_FILE = 'toolchains.xml'; exports.INPUT_MVN_TOOLCHAIN_ID = 'mvn-toolchain-id'; exports.INPUT_MVN_TOOLCHAIN_VENDOR = 'mvn-toolchain-vendor'; exports.DISTRIBUTIONS_ONLY_MAJOR_VERSION = ['corretto']; +exports.REMOTE_REPOSITORY_BASE_URL = 'remote-repository-base-url'; +exports.REPLACE_DOWNLOAD_LINK_BASE_URL = 'replace-download-link-base-url'; +exports.DOWNLOAD_LINK_CONTEXT = 'download-link-context'; /***/ }), diff --git a/dist/setup/index.js b/dist/setup/index.js index 3b8eb7455..57c97ac04 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -103582,7 +103582,7 @@ function isProbablyGradleDaemonProblem(packageManager, error) { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.DISTRIBUTIONS_ONLY_MAJOR_VERSION = exports.INPUT_MVN_TOOLCHAIN_VENDOR = exports.INPUT_MVN_TOOLCHAIN_ID = exports.MVN_TOOLCHAINS_FILE = exports.MVN_SETTINGS_FILE = exports.M2_DIR = exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = exports.INPUT_JOB_STATUS = exports.INPUT_CACHE = exports.INPUT_DEFAULT_GPG_PASSPHRASE = exports.INPUT_DEFAULT_GPG_PRIVATE_KEY = exports.INPUT_GPG_PASSPHRASE = exports.INPUT_GPG_PRIVATE_KEY = exports.INPUT_OVERWRITE_SETTINGS = exports.INPUT_SETTINGS_PATH = exports.INPUT_SERVER_PASSWORD = exports.INPUT_SERVER_USERNAME = exports.INPUT_SERVER_ID = exports.INPUT_CHECK_LATEST = exports.INPUT_JDK_FILE = exports.INPUT_DISTRIBUTION = exports.INPUT_JAVA_PACKAGE = exports.INPUT_ARCHITECTURE = exports.INPUT_JAVA_VERSION_FILE = exports.INPUT_JAVA_VERSION = exports.MACOS_JAVA_CONTENT_POSTFIX = void 0; +exports.DOWNLOAD_LINK_CONTEXT = exports.REPLACE_DOWNLOAD_LINK_BASE_URL = exports.REMOTE_REPOSITORY_BASE_URL = exports.DISTRIBUTIONS_ONLY_MAJOR_VERSION = exports.INPUT_MVN_TOOLCHAIN_VENDOR = exports.INPUT_MVN_TOOLCHAIN_ID = exports.MVN_TOOLCHAINS_FILE = exports.MVN_SETTINGS_FILE = exports.M2_DIR = exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = exports.INPUT_JOB_STATUS = exports.INPUT_CACHE = exports.INPUT_DEFAULT_GPG_PASSPHRASE = exports.INPUT_DEFAULT_GPG_PRIVATE_KEY = exports.INPUT_GPG_PASSPHRASE = exports.INPUT_GPG_PRIVATE_KEY = exports.INPUT_OVERWRITE_SETTINGS = exports.INPUT_SETTINGS_PATH = exports.INPUT_SERVER_PASSWORD = exports.INPUT_SERVER_USERNAME = exports.INPUT_SERVER_ID = exports.INPUT_CHECK_LATEST = exports.INPUT_JDK_FILE = exports.INPUT_DISTRIBUTION = exports.INPUT_JAVA_PACKAGE = exports.INPUT_ARCHITECTURE = exports.INPUT_JAVA_VERSION_FILE = exports.INPUT_JAVA_VERSION = exports.MACOS_JAVA_CONTENT_POSTFIX = void 0; exports.MACOS_JAVA_CONTENT_POSTFIX = 'Contents/Home'; exports.INPUT_JAVA_VERSION = 'java-version'; exports.INPUT_JAVA_VERSION_FILE = 'java-version-file'; @@ -103609,6 +103609,9 @@ exports.MVN_TOOLCHAINS_FILE = 'toolchains.xml'; exports.INPUT_MVN_TOOLCHAIN_ID = 'mvn-toolchain-id'; exports.INPUT_MVN_TOOLCHAIN_VENDOR = 'mvn-toolchain-vendor'; exports.DISTRIBUTIONS_ONLY_MAJOR_VERSION = ['corretto']; +exports.REMOTE_REPOSITORY_BASE_URL = 'remote-repository-base-url'; +exports.REPLACE_DOWNLOAD_LINK_BASE_URL = 'replace-download-link-base-url'; +exports.DOWNLOAD_LINK_CONTEXT = 'download-link-context'; /***/ }), @@ -103667,6 +103670,7 @@ class AdoptDistribution extends base_installer_1.JavaBase { constructor(installerOptions, jvmImpl) { super(`Adopt-${jvmImpl}`, installerOptions); this.jvmImpl = jvmImpl; + this.remoteMetadataBaseUrl = 'https://api.adoptopenjdk.net'; } findPackageForDownload(version) { return __awaiter(this, void 0, void 0, function* () { @@ -103676,7 +103680,7 @@ class AdoptDistribution extends base_installer_1.JavaBase { .map(item => { return { version: item.version_data.semver, - url: item.binaries[0].package.link + url: this.buildDownloadLink(item.binaries[0].package.link) }; }); const satisfiedVersions = availableVersionsWithBinaries @@ -103747,7 +103751,7 @@ class AdoptDistribution extends base_installer_1.JavaBase { const availableVersions = []; while (true) { const requestArguments = `${baseRequestArguments}&page_size=20&page=${page_index}`; - const availableVersionsUrl = `https://api.adoptopenjdk.net/v3/assets/version/${versionRange}?${requestArguments}`; + const availableVersionsUrl = `${this.baseUrl()}/v3/assets/version/${versionRange}?${requestArguments}`; if (core.isDebug() && page_index === 0) { // url is identical except page_index so print it once for debug core.debug(`Gathering available versions from '${availableVersionsUrl}'`); @@ -103845,6 +103849,9 @@ class JavaBase { this.architecture = installerOptions.architecture || os_1.default.arch(); this.packageType = installerOptions.packageType; this.checkLatest = installerOptions.checkLatest; + this.remoteRepositoryBaseUrl = installerOptions.remoteRepositoryBaseUrl; + this.replaceDownloadLinkBaseUrl = installerOptions.replaceDownloadLinkBaseUrl; + this.downloadLinkContext = installerOptions.downloadLinkContext; } setupJava() { return __awaiter(this, void 0, void 0, function* () { @@ -103971,6 +103978,28 @@ class JavaBase { return this.architecture; } } + /** + * This is a method used to generate a proper URL which is used to fetch the metadata.json file + * which contains all the information about all supported versions and the location where to download the binary. + * + * @returns the remoteRepositoryBaseUrl specified in the action.yml or the hardcoded remoteMetadataBaseUrl in each concret implementation. + */ + // return + baseUrl() { + return this.remoteRepositoryBaseUrl || this.remoteMetadataBaseUrl; + } + /** + * + * @param url The download link which is specified in the metdata.json file pointing to the location accessible via internet. + * @returns An updated download link which uses the private artifacts proxy to download the binnaries. + */ + buildDownloadLink(url) { + // means that the user wants to use the prox repository + if (this.remoteRepositoryBaseUrl && this.replaceDownloadLinkBaseUrl) { + return url.replace(this.replaceDownloadLinkBaseUrl, `${this.remoteRepositoryBaseUrl}${this.downloadLinkContext || ''}`); + } + return url; + } } exports.JavaBase = JavaBase; @@ -104024,6 +104053,7 @@ const base_installer_1 = __nccwpck_require__(9741); class CorrettoDistribution extends base_installer_1.JavaBase { constructor(installerOptions) { super('Corretto', installerOptions); + this.remoteMetadataBaseUrl = 'https://corretto.github.io'; } downloadTool(javaRelease) { return __awaiter(this, void 0, void 0, function* () { @@ -104075,7 +104105,7 @@ class CorrettoDistribution extends base_installer_1.JavaBase { if (core.isDebug()) { console.time('corretto-retrieve-available-versions'); } - const availableVersionsUrl = 'https://corretto.github.io/corretto-downloads/latest_links/indexmap_with_checksum.json'; + const availableVersionsUrl = `${this.baseUrl}/corretto-downloads/latest_links/indexmap_with_checksum.json`; const fetchCurrentVersions = yield this.http.getJson(availableVersionsUrl); const fetchedCurrentVersions = fetchCurrentVersions.result; if (!fetchedCurrentVersions) { @@ -104249,6 +104279,7 @@ const supportedArchitectures = `'x86', 'x64', 'armv7', 'aarch64', 'ppc64le'`; class LibericaDistributions extends base_installer_1.JavaBase { constructor(installerOptions) { super('Liberica', installerOptions); + this.remoteMetadataBaseUrl = 'https://api.bell-sw.com'; } downloadTool(javaRelease) { return __awaiter(this, void 0, void 0, function* () { @@ -104307,7 +104338,7 @@ class LibericaDistributions extends base_installer_1.JavaBase { prepareAvailableVersionsUrl() { const urlOptions = Object.assign(Object.assign({ os: this.getPlatformOption(), 'bundle-type': this.getBundleType() }, this.getArchitectureOptions()), { 'build-type': this.stable ? 'all' : 'ea', 'installation-type': 'archive', fields: 'downloadUrl,version,featureVersion,interimVersion,updateVersion,buildVersion' }); const searchParams = new URLSearchParams(urlOptions).toString(); - return `https://api.bell-sw.com/v1/liberica/releases?${searchParams}`; + return `${this.baseUrl()}/v1/liberica/releases?${searchParams}`; } getBundleType() { const [bundleType, feature] = this.packageType.split('+'); @@ -104420,6 +104451,7 @@ class LocalDistribution extends base_installer_1.JavaBase { constructor(installerOptions, jdkFile) { super('jdkfile', installerOptions); this.jdkFile = jdkFile; + this.remoteMetadataBaseUrl = 'MUST STAY EMPTY'; } setupJava() { return __awaiter(this, void 0, void 0, function* () { @@ -104463,6 +104495,9 @@ class LocalDistribution extends base_installer_1.JavaBase { throw new Error('This method should not be implemented in local file provider'); }); } + baseUrl() { + throw new Error('This method should not be implemented in local file provider'); + } downloadTool(javaRelease) { return __awaiter(this, void 0, void 0, function* () { throw new Error('This method should not be implemented in local file provider'); @@ -104521,6 +104556,7 @@ const path_1 = __importDefault(__nccwpck_require__(1017)); class MicrosoftDistributions extends base_installer_1.JavaBase { constructor(installerOptions) { super('Microsoft', installerOptions); + this.remoteMetadataBaseUrl = 'https://api.github.com'; } downloadTool(javaRelease) { return __awaiter(this, void 0, void 0, function* () { @@ -104571,7 +104607,7 @@ class MicrosoftDistributions extends base_installer_1.JavaBase { const branch = 'main'; const filePath = 'src/distributions/microsoft/microsoft-openjdk-versions.json'; let releases = null; - const fileUrl = `https://api.github.com/repos/${owner}/${repository}/contents/${filePath}?ref=${branch}`; + const fileUrl = `${this.baseUrl()}/repos/${owner}/${repository}/contents/${filePath}?ref=${branch}`; const headers = { authorization: auth, accept: 'application/vnd.github.VERSION.raw' @@ -104652,6 +104688,7 @@ class TemurinDistribution extends base_installer_1.JavaBase { constructor(installerOptions, jvmImpl) { super(`Temurin-${jvmImpl}`, installerOptions); this.jvmImpl = jvmImpl; + this.remoteMetadataBaseUrl = 'https://api.adoptium.net'; } findPackageForDownload(version) { return __awaiter(this, void 0, void 0, function* () { @@ -104731,7 +104768,7 @@ class TemurinDistribution extends base_installer_1.JavaBase { const availableVersions = []; while (true) { const requestArguments = `${baseRequestArguments}&page_size=20&page=${page_index}`; - const availableVersionsUrl = `https://api.adoptium.net/v3/assets/version/${versionRange}?${requestArguments}`; + const availableVersionsUrl = `${this.baseUrl()}/v3/assets/version/${versionRange}?${requestArguments}`; if (core.isDebug() && page_index === 0) { // url is identical except page_index so print it once for debug core.debug(`Gathering available versions from '${availableVersionsUrl}'`); @@ -104819,6 +104856,7 @@ const util_1 = __nccwpck_require__(2629); class ZuluDistribution extends base_installer_1.JavaBase { constructor(installerOptions) { super('Zulu', installerOptions); + this.remoteMetadataBaseUrl = 'https://api.azul.com'; } findPackageForDownload(version) { return __awaiter(this, void 0, void 0, function* () { @@ -104894,7 +104932,7 @@ class ZuluDistribution extends base_installer_1.JavaBase { ] .filter(Boolean) .join('&'); - const availableVersionsUrl = `https://api.azul.com/zulu/download/community/v1.0/bundles/?${requestArguments}`; + const availableVersionsUrl = `${this.baseUrl()}/zulu/download/community/v1.0/bundles/?${requestArguments}`; if (core.isDebug()) { core.debug(`Gathering available versions from '${availableVersionsUrl}'`); } @@ -105083,6 +105121,9 @@ function run() { const cache = core.getInput(constants.INPUT_CACHE); const checkLatest = util_1.getBooleanInput(constants.INPUT_CHECK_LATEST, false); let toolchainIds = core.getMultilineInput(constants.INPUT_MVN_TOOLCHAIN_ID); + let remoteRepositoryBaseUrl = core.getInput(constants.REMOTE_REPOSITORY_BASE_URL); + let replaceDownloadLinkBaseUrl = core.getInput(constants.REPLACE_DOWNLOAD_LINK_BASE_URL); + let downloadLinkContext = core.getInput(constants.DOWNLOAD_LINK_CONTEXT); core.startGroup('Installed distributions'); if (versions.length !== toolchainIds.length) { toolchainIds = []; @@ -105090,13 +105131,19 @@ function run() { if (!versions.length && !versionFile) { throw new Error('java-version or java-version-file input expected'); } + if (remoteRepositoryBaseUrl && !replaceDownloadLinkBaseUrl) { + throw new Error("You are trying to download binaries through an artifacts proxy. You must set the 'replace-download-link-base-url'. PS: Check if it is necessary to specify 'download-link-context' to generate a valid download link."); + } const installerInputsOptions = { architecture, packageType, checkLatest, distributionName, jdkFile, - toolchainIds + toolchainIds, + remoteRepositoryBaseUrl, + replaceDownloadLinkBaseUrl, + downloadLinkContext }; if (!versions.length) { core.debug('java-version input is empty, looking for java-version-file input'); @@ -105130,12 +105177,15 @@ function run() { run(); function installVersion(version, options, toolchainId = 0) { return __awaiter(this, void 0, void 0, function* () { - const { distributionName, jdkFile, architecture, packageType, checkLatest, toolchainIds } = options; + const { distributionName, jdkFile, architecture, packageType, checkLatest, toolchainIds, remoteRepositoryBaseUrl, replaceDownloadLinkBaseUrl, downloadLinkContext } = options; const installerOptions = { architecture, packageType, checkLatest, - version + version, + remoteRepositoryBaseUrl, + replaceDownloadLinkBaseUrl, + downloadLinkContext }; const distribution = distribution_factory_1.getJavaDistribution(distributionName, installerOptions, jdkFile); if (!distribution) { diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md index f5463bb77..a2b819dc3 100644 --- a/docs/advanced-usage.md +++ b/docs/advanced-usage.md @@ -16,6 +16,7 @@ - [Hosted Tool Cache](#Hosted-Tool-Cache) - [Modifying Maven Toolchains](#Modifying-Maven-Toolchains) - [Java-version file](#Java-version-file) +- [Fetch binaries from the artifact proxy repository](#Proxy-repositores) See [action.yml](../action.yml) for more details on task inputs. @@ -477,3 +478,21 @@ early access (EA) versions: 15-ea, 15.0.0-ea, 15.0.0-ea.2, 15.0.0+2-ea versions with specified distribution: openjdk64-11.0.2 ``` If the file contains multiple versions, only the first one will be recognized. + + +## Proxy repositores + +This example shows the usage of `setup-java` action which downloads all the artifacts from a artifact proxy repository. The assumtion is that the you are proxing the `https://github.com/adoptium` + +```yaml +steps: +- uses: actions/checkout@v3 +- uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '11' + remote-repository-base-url: 'https://test.artifactory.com' + download-link-context: '/adoptium' + replace-download-link-base-url: 'https://github.com/adoptium' +- run: java -cp java HelloWorldApp +``` \ No newline at end of file diff --git a/src/constants.ts b/src/constants.ts index 9aa213fa9..c3c3a640c 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -29,3 +29,7 @@ export const INPUT_MVN_TOOLCHAIN_ID = 'mvn-toolchain-id'; export const INPUT_MVN_TOOLCHAIN_VENDOR = 'mvn-toolchain-vendor'; export const DISTRIBUTIONS_ONLY_MAJOR_VERSION = ['corretto']; + +export const REMOTE_REPOSITORY_BASE_URL = 'remote-repository-base-url'; +export const REPLACE_DOWNLOAD_LINK_BASE_URL = 'replace-download-link-base-url'; +export const DOWNLOAD_LINK_CONTEXT = 'download-link-context'; diff --git a/src/distributions/adopt/installer.ts b/src/distributions/adopt/installer.ts index 52b64c6a0..f751e7676 100644 --- a/src/distributions/adopt/installer.ts +++ b/src/distributions/adopt/installer.ts @@ -16,6 +16,8 @@ export enum AdoptImplementation { } export class AdoptDistribution extends JavaBase { + protected remoteMetadataBaseUrl = 'https://api.adoptopenjdk.net'; + constructor( installerOptions: JavaInstallerOptions, private readonly jvmImpl: AdoptImplementation @@ -30,7 +32,7 @@ export class AdoptDistribution extends JavaBase { .map(item => { return { version: item.version_data.semver, - url: item.binaries[0].package.link + url: this.buildDownloadLink(item.binaries[0].package.link) } as JavaDownloadRelease; }); @@ -116,7 +118,7 @@ export class AdoptDistribution extends JavaBase { const availableVersions: IAdoptAvailableVersions[] = []; while (true) { const requestArguments = `${baseRequestArguments}&page_size=20&page=${page_index}`; - const availableVersionsUrl = `https://api.adoptopenjdk.net/v3/assets/version/${versionRange}?${requestArguments}`; + const availableVersionsUrl = `${this.baseUrl()}/v3/assets/version/${versionRange}?${requestArguments}`; if (core.isDebug() && page_index === 0) { // url is identical except page_index so print it once for debug core.debug(`Gathering available versions from '${availableVersionsUrl}'`); diff --git a/src/distributions/base-installer.ts b/src/distributions/base-installer.ts index 1a31ffaa9..efc37f656 100644 --- a/src/distributions/base-installer.ts +++ b/src/distributions/base-installer.ts @@ -16,6 +16,10 @@ export abstract class JavaBase { protected packageType: string; protected stable: boolean; protected checkLatest: boolean; + protected remoteRepositoryBaseUrl?: string; + protected replaceDownloadLinkBaseUrl?: string; + protected downloadLinkContext?: string; + protected abstract remoteMetadataBaseUrl: string; constructor(protected distribution: string, installerOptions: JavaInstallerOptions) { this.http = new httpm.HttpClient('actions/setup-java', undefined, { @@ -29,6 +33,9 @@ export abstract class JavaBase { this.architecture = installerOptions.architecture || os.arch(); this.packageType = installerOptions.packageType; this.checkLatest = installerOptions.checkLatest; + this.remoteRepositoryBaseUrl = installerOptions.remoteRepositoryBaseUrl; + this.replaceDownloadLinkBaseUrl = installerOptions.replaceDownloadLinkBaseUrl; + this.downloadLinkContext = installerOptions.downloadLinkContext; } protected abstract downloadTool(javaRelease: JavaDownloadRelease): Promise; @@ -171,4 +178,31 @@ export abstract class JavaBase { return this.architecture; } } + + /** + * This is a method used to generate a proper URL which is used to fetch the metadata.json file + * which contains all the information about all supported versions and the location where to download the binary. + * + * @returns the remoteRepositoryBaseUrl specified in the action.yml or the hardcoded remoteMetadataBaseUrl in each concret implementation. + */ + // return + protected baseUrl(): string { + return this.remoteRepositoryBaseUrl || this.remoteMetadataBaseUrl; + } + + /** + * + * @param url The download link which is specified in the metdata.json file pointing to the location accessible via internet. + * @returns An updated download link which uses the private artifacts proxy to download the binnaries. + */ + protected buildDownloadLink(url: string): string { + // means that the user wants to use the prox repository + if (this.remoteRepositoryBaseUrl && this.replaceDownloadLinkBaseUrl) { + return url.replace( + this.replaceDownloadLinkBaseUrl, + `${this.remoteRepositoryBaseUrl}${this.downloadLinkContext || ''}` + ); + } + return url; + } } diff --git a/src/distributions/base-models.ts b/src/distributions/base-models.ts index 82344d585..1691a9c55 100644 --- a/src/distributions/base-models.ts +++ b/src/distributions/base-models.ts @@ -3,6 +3,9 @@ export interface JavaInstallerOptions { architecture: string; packageType: string; checkLatest: boolean; + remoteRepositoryBaseUrl?: string; + replaceDownloadLinkBaseUrl?: string; + downloadLinkContext?: string; } export interface JavaInstallerResults { diff --git a/src/distributions/corretto/installer.ts b/src/distributions/corretto/installer.ts index 6b4872d85..e3c2b371d 100644 --- a/src/distributions/corretto/installer.ts +++ b/src/distributions/corretto/installer.ts @@ -8,6 +8,8 @@ import { JavaDownloadRelease, JavaInstallerOptions, JavaInstallerResults } from import { ICorrettoAllAvailableVersions, ICorrettoAvailableVersions } from './models'; export class CorrettoDistribution extends JavaBase { + protected remoteMetadataBaseUrl = 'https://corretto.github.io'; + constructor(installerOptions: JavaInstallerOptions) { super('Corretto', installerOptions); } @@ -75,8 +77,7 @@ export class CorrettoDistribution extends JavaBase { console.time('corretto-retrieve-available-versions'); } - const availableVersionsUrl = - 'https://corretto.github.io/corretto-downloads/latest_links/indexmap_with_checksum.json'; + const availableVersionsUrl = `${this.baseUrl}/corretto-downloads/latest_links/indexmap_with_checksum.json`; const fetchCurrentVersions = await this.http.getJson( availableVersionsUrl ); diff --git a/src/distributions/liberica/installer.ts b/src/distributions/liberica/installer.ts index f06e56ee4..964fb639d 100644 --- a/src/distributions/liberica/installer.ts +++ b/src/distributions/liberica/installer.ts @@ -13,6 +13,8 @@ const supportedPlatform = `'linux', 'linux-musl', 'macos', 'solaris', 'windows'` const supportedArchitectures = `'x86', 'x64', 'armv7', 'aarch64', 'ppc64le'`; export class LibericaDistributions extends JavaBase { + protected remoteMetadataBaseUrl = 'https://api.bell-sw.com'; + constructor(installerOptions: JavaInstallerOptions) { super('Liberica', installerOptions); } @@ -100,7 +102,7 @@ export class LibericaDistributions extends JavaBase { const searchParams = new URLSearchParams(urlOptions).toString(); - return `https://api.bell-sw.com/v1/liberica/releases?${searchParams}`; + return `${this.baseUrl()}/v1/liberica/releases?${searchParams}`; } private getBundleType(): string { diff --git a/src/distributions/local/installer.ts b/src/distributions/local/installer.ts index 1402bc85b..dc99c8267 100644 --- a/src/distributions/local/installer.ts +++ b/src/distributions/local/installer.ts @@ -11,6 +11,8 @@ import { extractJdkFile } from '../../util'; import { MACOS_JAVA_CONTENT_POSTFIX } from '../../constants'; export class LocalDistribution extends JavaBase { + protected remoteMetadataBaseUrl = 'MUST STAY EMPTY'; + constructor(installerOptions: JavaInstallerOptions, private jdkFile?: string) { super('jdkfile', installerOptions); } @@ -70,6 +72,10 @@ export class LocalDistribution extends JavaBase { throw new Error('This method should not be implemented in local file provider'); } + protected baseUrl(): string { + throw new Error('This method should not be implemented in local file provider'); + } + protected async downloadTool(javaRelease: JavaDownloadRelease): Promise { throw new Error('This method should not be implemented in local file provider'); } diff --git a/src/distributions/microsoft/installer.ts b/src/distributions/microsoft/installer.ts index 8625fb423..8b0dab7a4 100644 --- a/src/distributions/microsoft/installer.ts +++ b/src/distributions/microsoft/installer.ts @@ -9,6 +9,8 @@ import path from 'path'; import { ITypedResponse } from '@actions/http-client/interfaces'; export class MicrosoftDistributions extends JavaBase { + protected remoteMetadataBaseUrl = 'https://api.github.com'; + constructor(installerOptions: JavaInstallerOptions) { super('Microsoft', installerOptions); } @@ -80,7 +82,7 @@ export class MicrosoftDistributions extends JavaBase { const filePath = 'src/distributions/microsoft/microsoft-openjdk-versions.json'; let releases: tc.IToolRelease[] | null = null; - const fileUrl = `https://api.github.com/repos/${owner}/${repository}/contents/${filePath}?ref=${branch}`; + const fileUrl = `${this.baseUrl()}/repos/${owner}/${repository}/contents/${filePath}?ref=${branch}`; const headers: OutgoingHttpHeaders = { authorization: auth, diff --git a/src/distributions/temurin/installer.ts b/src/distributions/temurin/installer.ts index 4cd3e667b..c1f685e3b 100644 --- a/src/distributions/temurin/installer.ts +++ b/src/distributions/temurin/installer.ts @@ -15,6 +15,8 @@ export enum TemurinImplementation { } export class TemurinDistribution extends JavaBase { + protected remoteMetadataBaseUrl = 'https://api.adoptium.net'; + constructor( installerOptions: JavaInstallerOptions, private readonly jvmImpl: TemurinImplementation @@ -114,7 +116,7 @@ export class TemurinDistribution extends JavaBase { const availableVersions: ITemurinAvailableVersions[] = []; while (true) { const requestArguments = `${baseRequestArguments}&page_size=20&page=${page_index}`; - const availableVersionsUrl = `https://api.adoptium.net/v3/assets/version/${versionRange}?${requestArguments}`; + const availableVersionsUrl = `${this.baseUrl()}/v3/assets/version/${versionRange}?${requestArguments}`; if (core.isDebug() && page_index === 0) { // url is identical except page_index so print it once for debug core.debug(`Gathering available versions from '${availableVersionsUrl}'`); diff --git a/src/distributions/zulu/installer.ts b/src/distributions/zulu/installer.ts index 0ca6571a5..528a434d3 100644 --- a/src/distributions/zulu/installer.ts +++ b/src/distributions/zulu/installer.ts @@ -11,6 +11,8 @@ import { extractJdkFile, getDownloadArchiveExtension, isVersionSatisfies } from import { JavaDownloadRelease, JavaInstallerOptions, JavaInstallerResults } from '../base-models'; export class ZuluDistribution extends JavaBase { + protected remoteMetadataBaseUrl = 'https://api.azul.com'; + constructor(installerOptions: JavaInstallerOptions) { super('Zulu', installerOptions); } @@ -107,7 +109,7 @@ export class ZuluDistribution extends JavaBase { .filter(Boolean) .join('&'); - const availableVersionsUrl = `https://api.azul.com/zulu/download/community/v1.0/bundles/?${requestArguments}`; + const availableVersionsUrl = `${this.baseUrl()}/zulu/download/community/v1.0/bundles/?${requestArguments}`; if (core.isDebug()) { core.debug(`Gathering available versions from '${availableVersionsUrl}'`); } diff --git a/src/setup-java.ts b/src/setup-java.ts index 1d6dc15b4..dc32e9ede 100644 --- a/src/setup-java.ts +++ b/src/setup-java.ts @@ -20,6 +20,9 @@ async function run() { const cache = core.getInput(constants.INPUT_CACHE); const checkLatest = getBooleanInput(constants.INPUT_CHECK_LATEST, false); let toolchainIds = core.getMultilineInput(constants.INPUT_MVN_TOOLCHAIN_ID); + let remoteRepositoryBaseUrl = core.getInput(constants.REMOTE_REPOSITORY_BASE_URL); + let replaceDownloadLinkBaseUrl = core.getInput(constants.REPLACE_DOWNLOAD_LINK_BASE_URL); + let downloadLinkContext = core.getInput(constants.DOWNLOAD_LINK_CONTEXT); core.startGroup('Installed distributions'); @@ -31,13 +34,22 @@ async function run() { throw new Error('java-version or java-version-file input expected'); } + if (remoteRepositoryBaseUrl && !replaceDownloadLinkBaseUrl) { + throw new Error( + "You are trying to download binaries through an artifacts proxy. You must set the 'replace-download-link-base-url'. PS: Check if it is necessary to specify 'download-link-context' to generate a valid download link." + ); + } + const installerInputsOptions: installerInputsOptions = { architecture, packageType, checkLatest, distributionName, jdkFile, - toolchainIds + toolchainIds, + remoteRepositoryBaseUrl, + replaceDownloadLinkBaseUrl, + downloadLinkContext }; if (!versions.length) { @@ -82,14 +94,20 @@ async function installVersion(version: string, options: installerInputsOptions, architecture, packageType, checkLatest, - toolchainIds + toolchainIds, + remoteRepositoryBaseUrl, + replaceDownloadLinkBaseUrl, + downloadLinkContext } = options; const installerOptions: JavaInstallerOptions = { architecture, packageType, checkLatest, - version + version, + remoteRepositoryBaseUrl, + replaceDownloadLinkBaseUrl, + downloadLinkContext }; const distribution = getJavaDistribution(distributionName, installerOptions, jdkFile); @@ -120,4 +138,7 @@ interface installerInputsOptions { distributionName: string; jdkFile: string; toolchainIds: Array; + remoteRepositoryBaseUrl: string; + replaceDownloadLinkBaseUrl: string; + downloadLinkContext: string; }