Skip to content

Commit

Permalink
add support for artifacts proxy repositories
Browse files Browse the repository at this point in the history
  • Loading branch information
denizhoxha committed Dec 22, 2022
1 parent 06db6c2 commit b23412e
Show file tree
Hide file tree
Showing 16 changed files with 432 additions and 11 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
299 changes: 299 additions & 0 deletions __tests__/distributors/adopt-installer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
);
});
});
6 changes: 6 additions & 0 deletions __tests__/distributors/base-installer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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', () => {
Expand Down
9 changes: 9 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
19 changes: 19 additions & 0 deletions docs/advanced-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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
```
Loading

0 comments on commit b23412e

Please sign in to comment.