Migrate to ESM and upgrade dependencies

This commit is contained in:
priyagupta108 2026-07-08 09:52:56 +05:30
parent 0f481fcb61
commit d24693a189
96 changed files with 135616 additions and 124521 deletions

View File

@ -1,6 +0,0 @@
# Ignore list
/*
# Do not ignore these folders:
!__tests__/
!src/

View File

@ -1,51 +0,0 @@
// This is a reusable configuration file copied from https://github.com/actions/reusable-workflows/tree/main/reusable-configurations. Please don't make changes to this file as it's the subject of an automatic update.
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:eslint-plugin-jest/recommended',
'eslint-config-prettier'
],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint', 'eslint-plugin-node', 'eslint-plugin-jest'],
rules: {
'@typescript-eslint/no-require-imports': 'error',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/ban-ts-comment': [
'error',
{
'ts-ignore': 'allow-with-description'
}
],
'no-console': 'error',
'yoda': 'error',
'prefer-const': [
'error',
{
destructuring: 'all'
}
],
'no-control-regex': 'off',
'no-constant-condition': ['error', {checkLoops: false}],
'node/no-extraneous-import': 'error'
},
overrides: [
{
files: ['**/*{test,spec}.ts'],
rules: {
'@typescript-eslint/no-unused-vars': 'off',
'jest/no-standalone-expect': 'off',
'jest/no-conditional-expect': 'off',
'no-console': 'off',
}
}
],
env: {
node: true,
es6: true,
'jest/globals': true
}
};

View File

@ -10,8 +10,11 @@ allowed:
- mit
- cc0-1.0
- unlicense
- blueoak-1.0.0
reviewed:
npm:
- "@actions/http-client" # MIT (license text present), but detected as "other"
- "argparse" # Python Software Foundation License (PSF), but detected as "other"
- "balanced-match"
- "brace-expansion"

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
.licenses/npm/@actions/glob-0.7.0.dep.yml generated Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
.licenses/npm/balanced-match-4.0.4.dep.yml generated Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
.licenses/npm/minimatch-10.2.5.dep.yml generated Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,11 +0,0 @@
// This is a reusable configuration file copied from https://github.com/actions/reusable-workflows/tree/main/reusable-configurations. Please don't make changes to this file as it's the subject of an automatic update.
module.exports = {
printWidth: 80,
tabWidth: 2,
useTabs: false,
semi: true,
singleQuote: true,
trailingComma: 'none',
bracketSpacing: false,
arrowParens: 'avoid'
};

10
.prettierrc.json Normal file
View File

@ -0,0 +1,10 @@
{
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"trailingComma": "none",
"bracketSpacing": false,
"arrowParens": "avoid"
}

View File

@ -18,6 +18,10 @@ The `setup-java` action provides the following functionality for GitHub Actions
This action allows you to work with Java and Scala projects.
## Breaking changes in V6
- **Migrated to ESM** to enable support for the latest `@actions/*` package versions.
## Breaking changes in V5
- Upgraded action from node20 to node24

View File

@ -1,24 +1,63 @@
import {
jest,
describe,
it,
expect,
beforeEach,
afterEach,
beforeAll,
afterAll
} from '@jest/globals';
import {fileURLToPath} from 'url';
import * as io from '@actions/io';
import * as core from '@actions/core';
import * as fs from 'fs';
import * as path from 'path';
import os from 'os';
import * as auth from '../src/auth';
import {M2_DIR, MVN_SETTINGS_FILE} from '../src/constants';
// Mock @actions/core before importing source modules that depend on it
jest.unstable_mockModule('@actions/core', () => ({
info: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
setFailed: jest.fn(),
setOutput: jest.fn(),
getInput: jest.fn(),
getBooleanInput: jest.fn(),
getMultilineInput: jest.fn(),
addPath: jest.fn(),
exportVariable: jest.fn(),
saveState: jest.fn(),
getState: jest.fn(),
setSecret: jest.fn(),
isDebug: jest.fn(() => false),
startGroup: jest.fn(),
endGroup: jest.fn(),
group: jest.fn((_name: string, fn: () => Promise<unknown>) => fn()),
toPlatformPath: jest.fn((p: string) => p),
toWin32Path: jest.fn((p: string) => p),
toPosixPath: jest.fn((p: string) => p)
}));
// Dynamic imports after mocking
const core = await import('@actions/core');
const auth = await import('../src/auth.js');
const {M2_DIR, MVN_SETTINGS_FILE} = await import('../src/constants.js');
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const m2Dir = path.join(__dirname, M2_DIR);
const settingsFile = path.join(m2Dir, MVN_SETTINGS_FILE);
describe('auth tests', () => {
let spyOSHomedir: jest.SpyInstance;
let spyInfo: jest.SpyInstance;
let spyOSHomedir: any;
let spyInfo: any;
beforeEach(async () => {
await io.rmRF(m2Dir);
spyOSHomedir = jest.spyOn(os, 'homedir');
spyOSHomedir.mockReturnValue(__dirname);
spyInfo = jest.spyOn(core, 'info');
spyInfo = core.info as jest.Mock;
spyInfo.mockImplementation(() => null);
}, 300000);

View File

@ -1,23 +1,84 @@
import {
jest,
describe,
it,
expect,
beforeEach,
afterEach,
beforeAll,
afterAll
} from '@jest/globals';
import {mkdtempSync} from 'fs';
import {tmpdir} from 'os';
import {join} from 'path';
import {restore, save} from '../src/cache';
import * as fs from 'fs';
import * as os from 'os';
import * as core from '@actions/core';
import * as cache from '@actions/cache';
import * as glob from '@actions/glob';
// Mock @actions/core before importing source modules that depend on it
jest.unstable_mockModule('@actions/core', () => ({
info: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
setFailed: jest.fn(),
setOutput: jest.fn(),
getInput: jest.fn(),
getBooleanInput: jest.fn(),
getMultilineInput: jest.fn(),
addPath: jest.fn(),
exportVariable: jest.fn(),
saveState: jest.fn(),
getState: jest.fn(),
setSecret: jest.fn(),
isDebug: jest.fn(() => false),
startGroup: jest.fn(),
endGroup: jest.fn(),
group: jest.fn((_name: string, fn: () => Promise<unknown>) => fn()),
toPlatformPath: jest.fn((p: string) => p),
toWin32Path: jest.fn((p: string) => p),
toPosixPath: jest.fn((p: string) => p)
}));
jest.unstable_mockModule('@actions/cache', () => ({
restoreCache: jest.fn(),
saveCache: jest.fn(),
isFeatureAvailable: jest.fn(),
ValidationError: class ValidationError extends Error {
constructor(message: string) {
super(message);
this.name = 'ValidationError';
}
},
ReserveCacheError: class ReserveCacheError extends Error {
constructor(message: string) {
super(message);
this.name = 'ReserveCacheError';
}
}
}));
jest.unstable_mockModule('@actions/glob', () => ({
hashFiles: jest.fn(),
create: jest.fn()
}));
// Dynamic imports after mocking
const core = await import('@actions/core');
const cache = await import('@actions/cache');
const glob = await import('@actions/glob');
const {restore, save} = await import('../src/cache.js');
describe('dependency cache', () => {
const ORIGINAL_RUNNER_OS = process.env['RUNNER_OS'];
const ORIGINAL_GITHUB_WORKSPACE = process.env['GITHUB_WORKSPACE'];
const ORIGINAL_CWD = process.cwd();
let workspace: string;
let spyInfo: jest.SpyInstance<void, Parameters<typeof core.info>>;
let spyWarning: jest.SpyInstance<void, Parameters<typeof core.warning>>;
let spyDebug: jest.SpyInstance<void, Parameters<typeof core.debug>>;
let spySaveState: jest.SpyInstance<void, Parameters<typeof core.saveState>>;
let spyCoreError: jest.SpyInstance;
let spyInfo: any;
let spyWarning: any;
let spyDebug: any;
let spySaveState: any;
let spyCoreError: any;
beforeEach(() => {
workspace = mkdtempSync(join(tmpdir(), 'setup-java-cache-'));
@ -41,20 +102,20 @@ describe('dependency cache', () => {
});
beforeEach(() => {
spyInfo = jest.spyOn(core, 'info');
spyInfo = core.info as jest.Mock;
spyInfo.mockImplementation(() => null);
spyWarning = jest.spyOn(core, 'warning');
spyWarning = core.warning as jest.Mock;
spyWarning.mockImplementation(() => null);
spyDebug = jest.spyOn(core, 'debug');
spyDebug = core.debug as jest.Mock;
spyDebug.mockImplementation(() => null);
spySaveState = jest.spyOn(core, 'saveState');
spySaveState = core.saveState as jest.Mock;
spySaveState.mockImplementation(() => null);
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError = core.error as jest.Mock;
spyCoreError.mockImplementation(() => {});
});
@ -70,22 +131,15 @@ describe('dependency cache', () => {
});
describe('restore', () => {
let spyCacheRestore: jest.SpyInstance<
ReturnType<typeof cache.restoreCache>,
Parameters<typeof cache.restoreCache>
>;
let spyGlobHashFiles: jest.SpyInstance<
ReturnType<typeof glob.hashFiles>,
Parameters<typeof glob.hashFiles>
>;
let spyCacheRestore: any;
let spyGlobHashFiles: any;
beforeEach(() => {
spyCacheRestore = jest
.spyOn(cache, 'restoreCache')
.mockImplementation((paths: string[], primaryKey: string) =>
Promise.resolve(undefined)
);
spyGlobHashFiles = jest.spyOn(glob, 'hashFiles');
spyCacheRestore = (cache.restoreCache as any).mockImplementation(
(paths: string[], primaryKey: string) => Promise.resolve(undefined)
);
spyGlobHashFiles = glob.hashFiles as jest.Mock;
spyGlobHashFiles.mockResolvedValue('hash-stub');
spyWarning.mockImplementation(() => null);
});
@ -97,6 +151,7 @@ describe('dependency cache', () => {
describe('for maven', () => {
it('throws error if no pom.xml or maven-wrapper.properties found', async () => {
spyGlobHashFiles.mockResolvedValue('');
await expect(restore('maven', '')).rejects.toThrow(
`No file in ${projectRoot(
workspace
@ -144,6 +199,7 @@ describe('dependency cache', () => {
});
describe('for gradle', () => {
it('throws error if no build.gradle found', async () => {
spyGlobHashFiles.mockResolvedValue('');
await expect(restore('gradle', '')).rejects.toThrow(
`No file in ${projectRoot(
workspace
@ -199,6 +255,7 @@ describe('dependency cache', () => {
});
describe('for sbt', () => {
it('throws error if no build.sbt found', async () => {
spyGlobHashFiles.mockResolvedValue('');
await expect(restore('sbt', '')).rejects.toThrow(
`No file in ${projectRoot(
workspace
@ -217,6 +274,13 @@ describe('dependency cache', () => {
expect(spyInfo).toHaveBeenCalledWith('sbt cache is not found');
});
it('detects scala and sbt changes under **/project/ folder', async () => {
let callCount = 0;
spyGlobHashFiles.mockImplementation(async () => {
callCount++;
// Return same hash for first two calls, different for third
return callCount <= 2 ? 'hash-v1' : 'hash-v2';
});
createFile(join(workspace, 'build.sbt'));
createDirectory(join(workspace, 'project'));
createFile(join(workspace, 'project/DependenciesV1.scala'));
@ -252,6 +316,7 @@ describe('dependency cache', () => {
});
describe('cache-dependency-path', () => {
it('throws error if no matching dependency file found', async () => {
spyGlobHashFiles.mockResolvedValue('');
createFile(join(workspace, 'build.gradle.kts'));
await expect(
restore('gradle', 'sub-project/**/build.gradle.kts')
@ -293,17 +358,12 @@ describe('dependency cache', () => {
});
});
describe('save', () => {
let spyCacheSave: jest.SpyInstance<
ReturnType<typeof cache.saveCache>,
Parameters<typeof cache.saveCache>
>;
let spyCacheSave: any;
beforeEach(() => {
spyCacheSave = jest
.spyOn(cache, 'saveCache')
.mockImplementation((paths: string[], key: string) =>
Promise.resolve(0)
);
spyCacheSave = (cache.saveCache as any).mockImplementation(
(paths: string[], key: string) => Promise.resolve(0)
);
spyWarning.mockImplementation(() => null);
});
@ -463,14 +523,14 @@ describe('dependency cache', () => {
});
function resetState() {
jest.spyOn(core, 'getState').mockReset();
(core.getState as jest.Mock).mockReset();
}
/**
* Create states to emulate a restore process without build file.
*/
function createStateForMissingBuildFile() {
jest.spyOn(core, 'getState').mockImplementation(name => {
(core.getState as jest.Mock<any>).mockImplementation((name: any) => {
switch (name) {
case 'cache-primary-key':
return 'setup-java-cache-';
@ -484,7 +544,7 @@ function createStateForMissingBuildFile() {
* Create states to emulate a successful restore process.
*/
function createStateForSuccessfulRestore() {
jest.spyOn(core, 'getState').mockImplementation(name => {
(core.getState as jest.Mock<any>).mockImplementation((name: any) => {
switch (name) {
case 'cache-primary-key':
return 'setup-java-cache-primary-key';

View File

@ -1,32 +1,87 @@
import {run as cleanup} from '../src/cleanup-java';
import * as core from '@actions/core';
import * as cache from '@actions/cache';
import * as util from '../src/util';
import {
jest,
describe,
it,
expect,
beforeEach,
afterEach,
beforeAll,
afterAll
} from '@jest/globals';
// Mock @actions/cache before importing source modules
const real_cache_module = await import('@actions/cache');
jest.unstable_mockModule('@actions/cache', () => ({
...real_cache_module,
saveCache: jest.fn(),
restoreCache: jest.fn()
}));
// Mock @actions/core before importing source modules that depend on it
jest.unstable_mockModule('@actions/core', () => ({
info: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
setFailed: jest.fn(),
setOutput: jest.fn(),
getInput: jest.fn(),
getBooleanInput: jest.fn(),
getMultilineInput: jest.fn(),
addPath: jest.fn(),
exportVariable: jest.fn(),
saveState: jest.fn(),
getState: jest.fn(),
setSecret: jest.fn(),
isDebug: jest.fn(() => false),
startGroup: jest.fn(),
endGroup: jest.fn(),
group: jest.fn((_name: string, fn: () => Promise<unknown>) => fn()),
toPlatformPath: jest.fn((p: string) => p),
toWin32Path: jest.fn((p: string) => p),
toPosixPath: jest.fn((p: string) => p)
}));
const real_util_module = await import('../src/util.js');
jest.unstable_mockModule('../src/util.js', () => ({
...real_util_module,
extractJdkFile: jest.fn(),
getDownloadArchiveExtension: jest.fn(),
getToolcachePath: jest.fn(),
isJobStatusSuccess: jest.fn(),
renameWinArchive: jest.fn(),
isVersionSatisfies: real_util_module.isVersionSatisfies,
getTempDir: real_util_module.getTempDir
}));
// Dynamic imports after mocking
const core = await import('@actions/core');
const cache = await import('@actions/cache');
const {run: cleanup} = await import('../src/cleanup-java.js');
const util = await import('../src/util.js');
describe('cleanup', () => {
let spyWarning: jest.SpyInstance<void, Parameters<typeof core.warning>>;
let spyInfo: jest.SpyInstance<void, Parameters<typeof core.info>>;
let spyCacheSave: jest.SpyInstance<
ReturnType<typeof cache.saveCache>,
Parameters<typeof cache.saveCache>
>;
let spyJobStatusSuccess: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
let spyWarning: any;
let spyInfo: any;
let spyCacheSave: any;
let spyJobStatusSuccess: any;
let spyCoreError: any;
beforeEach(() => {
spyWarning = jest.spyOn(core, 'warning');
spyWarning = core.warning as jest.Mock;
spyWarning.mockImplementation(() => null);
spyInfo = jest.spyOn(core, 'info');
spyInfo = core.info as jest.Mock;
spyInfo.mockImplementation(() => null);
spyCacheSave = jest.spyOn(cache, 'saveCache');
spyCacheSave = cache.saveCache as jest.Mock;
spyJobStatusSuccess = jest.spyOn(util, 'isJobStatusSuccess');
spyJobStatusSuccess = util.isJobStatusSuccess as jest.Mock;
spyJobStatusSuccess.mockReturnValue(true);
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError = core.error as jest.Mock;
spyCoreError.mockImplementation(() => {});
createStateForSuccessfulRestore();
@ -47,7 +102,7 @@ describe('cleanup', () => {
)
)
);
jest.spyOn(core, 'getInput').mockImplementation((name: string) => {
(core.getInput as jest.Mock<any>).mockImplementation((name: string) => {
return name === 'cache' ? 'gradle' : '';
});
await cleanup();
@ -59,7 +114,7 @@ describe('cleanup', () => {
spyCacheSave.mockImplementation((paths: string[], key: string) =>
Promise.reject(new Error('Unexpected error'))
);
jest.spyOn(core, 'getInput').mockImplementation((name: string) => {
(core.getInput as jest.Mock<any>).mockImplementation((name: string) => {
return name === 'cache' ? 'gradle' : '';
});
await cleanup();
@ -68,14 +123,14 @@ describe('cleanup', () => {
});
function resetState() {
jest.spyOn(core, 'getState').mockReset();
(core.getState as jest.Mock).mockReset();
}
/**
* Create states to emulate a successful restore process.
*/
function createStateForSuccessfulRestore() {
jest.spyOn(core, 'getState').mockImplementation(name => {
(core.getState as jest.Mock<any>).mockImplementation((name: any) => {
switch (name) {
case 'cache-primary-key':
return 'setup-java-cache-primary-key';

View File

@ -1,21 +1,59 @@
import {HttpClient} from '@actions/http-client';
import {IAdoptAvailableVersions} from '../../src/distributions/adopt/models';
import {
AdoptDistribution,
AdoptImplementation
} from '../../src/distributions/adopt/installer';
import {TemurinDistribution} from '../../src/distributions/temurin/installer';
import {JavaInstallerOptions} from '../../src/distributions/base-models';
jest,
describe,
it,
expect,
beforeEach,
afterEach,
beforeAll,
afterAll
} from '@jest/globals';
import {HttpClient} from '@actions/http-client';
import os from 'os';
import manifestData from '../data/adopt.json';
import * as core from '@actions/core';
import manifestData from '../data/adopt.json' with {type: 'json'};
// Mock @actions/core before importing source modules that depend on it
jest.unstable_mockModule('@actions/core', () => ({
info: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
setFailed: jest.fn(),
setOutput: jest.fn(),
getInput: jest.fn(),
getBooleanInput: jest.fn(),
getMultilineInput: jest.fn(),
addPath: jest.fn(),
exportVariable: jest.fn(),
saveState: jest.fn(),
getState: jest.fn(),
setSecret: jest.fn(),
isDebug: jest.fn(() => false),
startGroup: jest.fn(),
endGroup: jest.fn(),
group: jest.fn((_name: string, fn: () => Promise<unknown>) => fn()),
toPlatformPath: jest.fn((p: string) => p),
toWin32Path: jest.fn((p: string) => p),
toPosixPath: jest.fn((p: string) => p)
}));
// Dynamic imports after mocking
const core = await import('@actions/core');
const {AdoptDistribution, AdoptImplementation} =
await import('../../src/distributions/adopt/installer.js');
const {TemurinDistribution} =
await import('../../src/distributions/temurin/installer.js');
import type {IAdoptAvailableVersions} from '../../src/distributions/adopt/models.js';
import type {AdoptImplementation as AdoptImplementationType} from '../../src/distributions/adopt/installer.js';
import type {JavaInstallerOptions} from '../../src/distributions/base-models.js';
describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
let spyCoreWarning: jest.SpyInstance;
let spyHttpClient: any;
let spyCoreError: any;
let spyCoreWarning: any;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@ -26,9 +64,9 @@ describe('getAvailableVersions', () => {
});
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError = core.error as jest.Mock;
spyCoreError.mockImplementation(() => {});
spyCoreWarning = jest.spyOn(core, 'warning');
spyCoreWarning = core.warning as jest.Mock;
spyCoreWarning.mockImplementation(() => {});
});
@ -123,7 +161,7 @@ describe('getAvailableVersions', () => {
'build correct url for %s',
async (
installerOptions: JavaInstallerOptions,
impl: AdoptImplementation,
impl: AdoptImplementationType,
expectedParameters
) => {
const distribution = new AdoptDistribution(installerOptions, impl);
@ -204,7 +242,7 @@ describe('getAvailableVersions', () => {
[AdoptImplementation.OpenJ9, 'jre', 'Java_Adopt-OpenJ9_jre']
])(
'find right toolchain folder',
(impl: AdoptImplementation, packageType: string, expected: string) => {
(impl: AdoptImplementationType, packageType: string, expected: string) => {
const distribution = new AdoptDistribution(
{
version: '11',
@ -263,11 +301,11 @@ describe('findPackageForDownload', () => {
url: 'https://example.test/temurin-11.tar.gz'
};
const temurinFindPackageForDownload = jest
.fn()
.fn<any>()
.mockResolvedValue(temurinRelease);
const temurinDistribution = {
findPackageForDownload: temurinFindPackageForDownload
} as unknown as TemurinDistribution;
} as any;
const distribution = new AdoptDistribution(
{
@ -279,7 +317,7 @@ describe('findPackageForDownload', () => {
AdoptImplementation.Hotspot,
temurinDistribution
);
const adoptLookupSpy = jest.fn();
const adoptLookupSpy = jest.fn<any>();
distribution['getAvailableVersions'] = adoptLookupSpy;
const resolvedVersion = await distribution['findPackageForDownload']('11');

View File

@ -1,19 +1,90 @@
import * as tc from '@actions/tool-cache';
import * as core from '@actions/core';
import * as util from '../../src/util';
import {
jest,
describe,
it,
expect,
beforeEach,
afterEach,
beforeAll,
afterAll
} from '@jest/globals';
import type {
JavaDownloadRelease,
JavaInstallerOptions,
JavaInstallerResults
} from '../../src/distributions/base-models.js';
import path from 'path';
import * as semver from 'semver';
import {JavaBase} from '../../src/distributions/base-installer';
import {
JavaDownloadRelease,
JavaInstallerOptions,
JavaInstallerResults
} from '../../src/distributions/base-models';
import os from 'os';
// Mock @actions/core before importing source modules that depend on it
jest.unstable_mockModule('@actions/core', () => ({
info: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
setFailed: jest.fn(),
setOutput: jest.fn(),
getInput: jest.fn(),
getBooleanInput: jest.fn(),
getMultilineInput: jest.fn(),
addPath: jest.fn(),
exportVariable: jest.fn(),
saveState: jest.fn(),
getState: jest.fn(),
setSecret: jest.fn(),
isDebug: jest.fn(() => false),
startGroup: jest.fn(),
endGroup: jest.fn(),
group: jest.fn((_name: string, fn: () => Promise<unknown>) => fn()),
toPlatformPath: jest.fn((p: string) => p),
toWin32Path: jest.fn((p: string) => p),
toPosixPath: jest.fn((p: string) => p)
}));
jest.unstable_mockModule('@actions/tool-cache', () => ({
find: jest.fn(),
findAllVersions: jest.fn(),
downloadTool: jest.fn(),
extractZip: jest.fn(),
extractTar: jest.fn(),
extract7z: jest.fn(),
extractXar: jest.fn(),
cacheDir: jest.fn(),
cacheFile: jest.fn(),
getManifestFromRepo: jest.fn(),
findFromManifest: jest.fn(),
evaluateVersions: jest.fn(),
HTTPError: class HTTPError extends Error {
httpStatusCode: number;
constructor(statusCode: number) {
super(`HTTP Error: ${statusCode}`);
this.httpStatusCode = statusCode;
}
}
}));
const real_util_module = await import('../../src/util.js');
jest.unstable_mockModule('../../src/util.js', () => ({
...real_util_module,
extractJdkFile: jest.fn(),
getDownloadArchiveExtension: jest.fn(),
getToolcachePath: jest.fn(),
isJobStatusSuccess: jest.fn(),
renameWinArchive: jest.fn(),
isVersionSatisfies: real_util_module.isVersionSatisfies,
getTempDir: real_util_module.getTempDir
}));
// Dynamic imports after mocking
const core = await import('@actions/core');
const tc = await import('@actions/tool-cache');
const util = await import('../../src/util.js');
const {JavaBase} = await import('../../src/distributions/base-installer.js');
class EmptyJavaBase extends JavaBase {
constructor(installerOptions: JavaInstallerOptions) {
super('Empty', installerOptions);
@ -53,12 +124,12 @@ describe('findInToolcache', () => {
const javaPath = path.join('Java_Empty_jdk', actualJavaVersion, 'x64');
let mockJavaBase: EmptyJavaBase;
let spyGetToolcachePath: jest.SpyInstance;
let spyTcFindAllVersions: jest.SpyInstance;
let spyGetToolcachePath: any;
let spyTcFindAllVersions: any;
beforeEach(() => {
spyGetToolcachePath = jest.spyOn(util, 'getToolcachePath');
spyTcFindAllVersions = jest.spyOn(tc, 'findAllVersions');
spyGetToolcachePath = util.getToolcachePath as jest.Mock;
spyTcFindAllVersions = tc.findAllVersions as jest.Mock;
});
afterEach(() => {
@ -241,17 +312,17 @@ describe('setupJava', () => {
let mockJavaBase: EmptyJavaBase;
let spyGetToolcachePath: jest.SpyInstance;
let spyTcFindAllVersions: jest.SpyInstance;
let spyCoreDebug: jest.SpyInstance;
let spyCoreInfo: jest.SpyInstance;
let spyCoreExportVariable: jest.SpyInstance;
let spyCoreAddPath: jest.SpyInstance;
let spyCoreSetOutput: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
let spyGetToolcachePath: any;
let spyTcFindAllVersions: any;
let spyCoreDebug: any;
let spyCoreInfo: any;
let spyCoreExportVariable: any;
let spyCoreAddPath: any;
let spyCoreSetOutput: any;
let spyCoreError: any;
beforeEach(() => {
spyGetToolcachePath = jest.spyOn(util, 'getToolcachePath');
spyGetToolcachePath = util.getToolcachePath as jest.Mock;
spyGetToolcachePath.mockImplementation(
(toolname: string, javaVersion: string, architecture: string) => {
const semverVersion = new semver.Range(javaVersion);
@ -269,27 +340,27 @@ describe('setupJava', () => {
}
);
spyTcFindAllVersions = jest.spyOn(tc, 'findAllVersions');
spyTcFindAllVersions = tc.findAllVersions as jest.Mock;
spyTcFindAllVersions.mockReturnValue([installedJavaVersion]);
// Spy on core methods
spyCoreDebug = jest.spyOn(core, 'debug');
spyCoreDebug = core.debug as jest.Mock;
spyCoreDebug.mockImplementation(() => undefined);
spyCoreInfo = jest.spyOn(core, 'info');
spyCoreInfo = core.info as jest.Mock;
spyCoreInfo.mockImplementation(() => undefined);
spyCoreAddPath = jest.spyOn(core, 'addPath');
spyCoreAddPath = core.addPath as jest.Mock;
spyCoreAddPath.mockImplementation(() => undefined);
spyCoreExportVariable = jest.spyOn(core, 'exportVariable');
spyCoreExportVariable = core.exportVariable as jest.Mock;
spyCoreExportVariable.mockImplementation(() => undefined);
spyCoreSetOutput = jest.spyOn(core, 'setOutput');
spyCoreSetOutput = core.setOutput as jest.Mock;
spyCoreSetOutput.mockImplementation(() => undefined);
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError = core.error as jest.Mock;
spyCoreError.mockImplementation(() => undefined);
jest.spyOn(os, 'arch').mockReturnValue('x86' as ReturnType<typeof os.arch>);

View File

@ -1,17 +1,62 @@
import {
jest,
describe,
it,
expect,
beforeEach,
afterEach,
beforeAll,
afterAll
} from '@jest/globals';
import type {JavaInstallerOptions} from '../../src/distributions/base-models.js';
import {HttpClient} from '@actions/http-client';
import {JavaInstallerOptions} from '../../src/distributions/base-models';
import {CorrettoDistribution} from '../../src/distributions/corretto/installer';
import * as util from '../../src/util';
import os from 'os';
import * as core from '@actions/core';
import manifestData from '../data/corretto.json';
import manifestData from '../data/corretto.json' with {type: 'json'};
// Mock @actions/core before importing source modules that depend on it
jest.unstable_mockModule('@actions/core', () => ({
info: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
setFailed: jest.fn(),
setOutput: jest.fn(),
getInput: jest.fn(),
getBooleanInput: jest.fn(),
getMultilineInput: jest.fn(),
addPath: jest.fn(),
exportVariable: jest.fn(),
saveState: jest.fn(),
getState: jest.fn(),
setSecret: jest.fn(),
isDebug: jest.fn(() => false),
startGroup: jest.fn(),
endGroup: jest.fn(),
group: jest.fn((_name: string, fn: () => Promise<unknown>) => fn()),
toPlatformPath: jest.fn((p: string) => p),
toWin32Path: jest.fn((p: string) => p),
toPosixPath: jest.fn((p: string) => p)
}));
const real_util_module = await import('../../src/util.js');
jest.unstable_mockModule('../../src/util.js', () => ({
...real_util_module,
getDownloadArchiveExtension: jest.fn()
}));
// Dynamic imports after mocking
const core = await import('@actions/core');
const {CorrettoDistribution} =
await import('../../src/distributions/corretto/installer.js');
const util = await import('../../src/util.js');
describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance;
let spyGetDownloadArchiveExtension: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
let spyHttpClient: ReturnType<typeof jest.spyOn>;
let spyGetDownloadArchiveExtension: any;
let spyCoreError: any;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@ -20,13 +65,11 @@ describe('getAvailableVersions', () => {
headers: {},
result: manifestData
});
spyGetDownloadArchiveExtension = jest.spyOn(
util,
'getDownloadArchiveExtension'
);
spyGetDownloadArchiveExtension =
util.getDownloadArchiveExtension as jest.Mock;
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError = core.error as jest.Mock;
spyCoreError.mockImplementation(() => {});
});
@ -235,7 +278,7 @@ describe('getAvailableVersions', () => {
});
const mockPlatform = (
distribution: CorrettoDistribution,
distribution: InstanceType<typeof CorrettoDistribution>,
platform: string
) => {
distribution['getPlatformOption'] = () => platform;

View File

@ -1,14 +1,59 @@
import {
jest,
describe,
it,
expect,
beforeEach,
afterEach,
beforeAll,
afterAll
} from '@jest/globals';
import {HttpClient} from '@actions/http-client';
import {DragonwellDistribution} from '../../src/distributions/dragonwell/installer';
import * as utils from '../../src/util';
import * as core from '@actions/core';
import manifestData from '../data/dragonwell.json';
import manifestData from '../data/dragonwell.json' with {type: 'json'};
// Mock @actions/core before importing source modules that depend on it
jest.unstable_mockModule('@actions/core', () => ({
info: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
setFailed: jest.fn(),
setOutput: jest.fn(),
getInput: jest.fn(),
getBooleanInput: jest.fn(),
getMultilineInput: jest.fn(),
addPath: jest.fn(),
exportVariable: jest.fn(),
saveState: jest.fn(),
getState: jest.fn(),
setSecret: jest.fn(),
isDebug: jest.fn(() => false),
startGroup: jest.fn(),
endGroup: jest.fn(),
group: jest.fn((_name: string, fn: () => Promise<unknown>) => fn()),
toPlatformPath: jest.fn((p: string) => p),
toWin32Path: jest.fn((p: string) => p),
toPosixPath: jest.fn((p: string) => p)
}));
const real_util_module = await import('../../src/util.js');
jest.unstable_mockModule('../../src/util.js', () => ({
...real_util_module,
getDownloadArchiveExtension: jest.fn()
}));
// Dynamic imports after mocking
const core = await import('@actions/core');
const {DragonwellDistribution} =
await import('../../src/distributions/dragonwell/installer.js');
const utils = await import('../../src/util.js');
describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance;
let spyUtilGetDownloadArchiveExtension: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
let spyHttpClient: any;
let spyUtilGetDownloadArchiveExtension: any;
let spyCoreError: any;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@ -18,14 +63,12 @@ describe('getAvailableVersions', () => {
result: manifestData
});
spyUtilGetDownloadArchiveExtension = jest.spyOn(
utils,
'getDownloadArchiveExtension'
);
spyUtilGetDownloadArchiveExtension =
utils.getDownloadArchiveExtension as jest.Mock;
spyUtilGetDownloadArchiveExtension.mockReturnValue('tar.gz');
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError = core.error as jest.Mock;
spyCoreError.mockImplementation(() => {});
});
@ -36,7 +79,7 @@ describe('getAvailableVersions', () => {
});
const mockPlatform = (
distribution: DragonwellDistribution,
distribution: InstanceType<typeof DragonwellDistribution>,
platform: string
) => {
distribution['getPlatformOption'] = () => platform;

View File

@ -1,53 +1,116 @@
import * as core from '@actions/core';
import * as tc from '@actions/tool-cache';
import * as http from '@actions/http-client';
import fs from 'fs';
import path from 'path';
import {
GraalVMCommunityDistribution,
GraalVMDistribution
} from '../../src/distributions/graalvm/installer';
import {getJavaDistribution} from '../../src/distributions/distribution-factory';
import {JavaInstallerOptions} from '../../src/distributions/base-models';
import * as util from '../../src/util';
jest,
describe,
it,
expect,
beforeEach,
beforeAll,
afterAll
} from '@jest/globals';
import path from 'path';
jest.mock('@actions/core');
jest.mock('@actions/tool-cache');
jest.mock('@actions/http-client');
// Mock @actions modules
jest.unstable_mockModule('@actions/core', () => ({
info: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
setFailed: jest.fn(),
setOutput: jest.fn(),
getInput: jest.fn(),
getBooleanInput: jest.fn(),
getMultilineInput: jest.fn(),
addPath: jest.fn(),
exportVariable: jest.fn(),
saveState: jest.fn(),
getState: jest.fn(),
setSecret: jest.fn(),
isDebug: jest.fn(() => false),
startGroup: jest.fn(),
endGroup: jest.fn(),
group: jest.fn((_name: string, fn: () => Promise<unknown>) => fn()),
toPlatformPath: jest.fn((p: string) => p),
toWin32Path: jest.fn((p: string) => p),
toPosixPath: jest.fn((p: string) => p)
}));
jest.mock('../../src/util', () => ({
...jest.requireActual('../../src/util'),
jest.unstable_mockModule('@actions/tool-cache', () => ({
find: jest.fn(),
findAllVersions: jest.fn(),
downloadTool: jest.fn(),
extractZip: jest.fn(),
extractTar: jest.fn(),
extract7z: jest.fn(),
extractXar: jest.fn(),
cacheDir: jest.fn(),
cacheFile: jest.fn(),
getManifestFromRepo: jest.fn(),
findFromManifest: jest.fn(),
evaluateVersions: jest.fn()
}));
jest.unstable_mockModule('@actions/http-client', () => ({
HttpClient: jest.fn().mockImplementation(() => ({
getJson: jest.fn(),
head: jest.fn(),
get: jest.fn()
})),
HttpClientError: class HttpClientError extends Error {
statusCode: number;
constructor(message: string, statusCode: number) {
super(message);
this.statusCode = statusCode;
}
},
HttpCodes: {OK: 200, NotFound: 404, Unauthorized: 401, Forbidden: 403}
}));
// Get real util first, then mock specific functions
const realUtil = await import('../../src/util.js');
jest.unstable_mockModule('../../src/util.js', () => ({
...realUtil,
extractJdkFile: jest.fn(),
getDownloadArchiveExtension: jest.fn(),
renameWinArchive: jest.fn(),
getGitHubHttpHeaders: jest.fn().mockReturnValue({Accept: 'application/json'})
}));
jest.mock('fs', () => ({
...jest.requireActual('fs'),
const real_fs_module = await import('fs');
jest.unstable_mockModule('fs', () => ({
...real_fs_module,
default: {
...real_fs_module.default,
readdirSync: jest.fn(),
existsSync: jest.fn()
},
readdirSync: jest.fn(),
existsSync: jest.fn()
}));
// Dynamic imports after mocking
const core = await import('@actions/core');
const tc = await import('@actions/tool-cache');
const http = await import('@actions/http-client');
const fs = (await import('fs')).default;
const util = await import('../../src/util.js');
const {GraalVMCommunityDistribution, GraalVMDistribution} =
await import('../../src/distributions/graalvm/installer.js');
const {getJavaDistribution} =
await import('../../src/distributions/distribution-factory.js');
import type {JavaInstallerOptions} from '../../src/distributions/base-models.js';
beforeAll(() => {
process.env.NODE_ENV = 'test';
if (!jest.isMockFunction(http.HttpClient)) {
throw new Error('HTTP client must be mocked in tests!');
}
if (!jest.isMockFunction(tc.downloadTool)) {
throw new Error('Tool cache downloadTool must be mocked in tests!');
}
console.log('✅ All external dependencies are properly mocked');
});
describe('GraalVMDistribution', () => {
let distribution: GraalVMDistribution;
let communityDistribution: GraalVMCommunityDistribution;
let mockHttpClient: jest.Mocked<http.HttpClient>;
let spyCoreError: jest.SpyInstance;
let distribution: InstanceType<typeof GraalVMDistribution>;
let communityDistribution: InstanceType<typeof GraalVMCommunityDistribution>;
let mockHttpClient: any;
let spyCoreError: any;
const defaultOptions: JavaInstallerOptions = {
version: '17',
@ -62,23 +125,20 @@ describe('GraalVMDistribution', () => {
distribution = new GraalVMDistribution(defaultOptions);
communityDistribution = new GraalVMCommunityDistribution(defaultOptions);
mockHttpClient = new http.HttpClient() as jest.Mocked<http.HttpClient>;
mockHttpClient = new (http.HttpClient as any)();
(distribution as any).http = mockHttpClient;
(communityDistribution as any).http = mockHttpClient;
(util.getDownloadArchiveExtension as jest.Mock).mockReturnValue('tar.gz');
(util.getDownloadArchiveExtension as jest.Mock<any>).mockReturnValue(
'tar.gz'
);
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError = core.error as jest.Mock;
spyCoreError.mockImplementation(() => {});
});
afterAll(() => {
expect(jest.isMockFunction(http.HttpClient)).toBe(true);
expect(jest.isMockFunction(tc.downloadTool)).toBe(true);
expect(jest.isMockFunction(tc.cacheDir)).toBe(true);
jest.restoreAllMocks();
jest.clearAllMocks();
});
@ -113,20 +173,24 @@ describe('GraalVMDistribution', () => {
};
beforeEach(() => {
(tc.downloadTool as jest.Mock).mockResolvedValue('/tmp/archive.tar.gz');
(tc.cacheDir as jest.Mock).mockResolvedValue('/cached/java/path');
(tc.downloadTool as any).mockResolvedValue('/tmp/archive.tar.gz');
(tc.cacheDir as any).mockResolvedValue('/cached/java/path');
(util.extractJdkFile as jest.Mock).mockResolvedValue('/tmp/extracted');
(util.extractJdkFile as any).mockResolvedValue('/tmp/extracted');
// Mock renameWinArchive - it returns the same path (no renaming)
(util.renameWinArchive as jest.Mock).mockImplementation((p: string) => p);
(util.renameWinArchive as any).mockImplementation((p: string) => p);
(util.getDownloadArchiveExtension as jest.Mock).mockReturnValue('tar.gz');
(util.getDownloadArchiveExtension as jest.Mock<any>).mockReturnValue(
'tar.gz'
);
// Mock fs.existsSync to return true for extracted path
(fs.existsSync as jest.Mock).mockReturnValue(true);
(fs.existsSync as jest.Mock<any>).mockReturnValue(true);
(fs.readdirSync as jest.Mock).mockReturnValue(['graalvm-jdk-17.0.5']);
(fs.readdirSync as jest.Mock<any>).mockReturnValue([
'graalvm-jdk-17.0.5'
]);
jest
.spyOn(distribution as any, 'getToolcacheVersionName')
@ -173,7 +237,7 @@ describe('GraalVMDistribution', () => {
});
it('should throw error when extracted path does not exist', async () => {
(fs.existsSync as jest.Mock).mockReturnValue(false);
(fs.existsSync as jest.Mock<any>).mockReturnValue(false);
await expect(
(distribution as any).downloadTool(javaRelease)
@ -187,8 +251,8 @@ describe('GraalVMDistribution', () => {
});
it('should throw error when extracted directory is empty', async () => {
(fs.existsSync as jest.Mock).mockReturnValue(true);
(fs.readdirSync as jest.Mock).mockReturnValue([]);
(fs.existsSync as jest.Mock<any>).mockReturnValue(true);
(fs.readdirSync as jest.Mock<any>).mockReturnValue([]);
await expect(
(distribution as any).downloadTool(javaRelease)
@ -203,7 +267,7 @@ describe('GraalVMDistribution', () => {
it('should handle download errors', async () => {
const downloadError = new Error('Network error during download');
(tc.downloadTool as jest.Mock).mockRejectedValue(downloadError);
(tc.downloadTool as any).mockRejectedValue(downloadError);
await expect(
(distribution as any).downloadTool(javaRelease)
@ -216,7 +280,7 @@ describe('GraalVMDistribution', () => {
it('should handle extraction errors', async () => {
const extractError = new Error('Failed to extract archive');
(util.extractJdkFile as jest.Mock).mockRejectedValue(extractError);
(util.extractJdkFile as any).mockRejectedValue(extractError);
await expect(
(distribution as any).downloadTool(javaRelease)
@ -229,8 +293,10 @@ describe('GraalVMDistribution', () => {
it('should handle different archive extensions', async () => {
// Test with a .zip file
(util.getDownloadArchiveExtension as jest.Mock).mockReturnValue('zip');
(tc.downloadTool as jest.Mock).mockResolvedValue('/tmp/archive.zip');
(util.getDownloadArchiveExtension as jest.Mock<any>).mockReturnValue(
'zip'
);
(tc.downloadTool as any).mockResolvedValue('/tmp/archive.zip');
const zipRelease = {
version: '17.0.5',
@ -309,7 +375,7 @@ describe('GraalVMDistribution', () => {
it('should construct correct URL for specific version', async () => {
const mockResponse = {
message: {statusCode: 200}
} as http.HttpClientResponse;
} as any;
mockHttpClient.head.mockResolvedValue(mockResponse);
const result = await (distribution as any).findPackageForDownload(
@ -326,7 +392,7 @@ describe('GraalVMDistribution', () => {
it('should construct correct URL for major version (latest)', async () => {
const mockResponse = {
message: {statusCode: 200}
} as http.HttpClientResponse;
} as any;
mockHttpClient.head.mockResolvedValue(mockResponse);
const result = await (distribution as any).findPackageForDownload('21');
@ -374,7 +440,7 @@ describe('GraalVMDistribution', () => {
it('should throw error when file not found (404)', async () => {
const mockResponse = {
message: {statusCode: 404}
} as http.HttpClientResponse;
} as any;
mockHttpClient.head.mockResolvedValue(mockResponse);
// Verify the error is thrown with the expected message
@ -395,7 +461,7 @@ describe('GraalVMDistribution', () => {
it('should throw error for unauthorized access (401)', async () => {
const mockResponse = {
message: {statusCode: 401}
} as http.HttpClientResponse;
} as any;
mockHttpClient.head.mockResolvedValue(mockResponse);
await expect(
@ -408,7 +474,7 @@ describe('GraalVMDistribution', () => {
it('should throw error for forbidden access (403)', async () => {
const mockResponse = {
message: {statusCode: 403}
} as http.HttpClientResponse;
} as any;
mockHttpClient.head.mockResolvedValue(mockResponse);
await expect(
@ -424,7 +490,7 @@ describe('GraalVMDistribution', () => {
statusCode: 500,
statusMessage: 'Internal Server Error'
}
} as http.HttpClientResponse;
} as any;
mockHttpClient.head.mockResolvedValue(mockResponse);
await expect(
@ -437,7 +503,7 @@ describe('GraalVMDistribution', () => {
it('should throw error for other HTTP errors without status message', async () => {
const mockResponse = {
message: {statusCode: 500}
} as http.HttpClientResponse;
} as any;
mockHttpClient.head.mockResolvedValue(mockResponse);
await expect(
@ -713,7 +779,7 @@ describe('GraalVMDistribution', () => {
}
];
let fetchEASpy: jest.SpyInstance;
let fetchEASpy: any;
beforeEach(() => {
fetchEASpy = jest.spyOn(distribution as any, 'fetchEAJson');
@ -932,7 +998,7 @@ describe('GraalVMDistribution', () => {
const mockResponse = {
message: {statusCode: 200}
} as http.HttpClientResponse;
} as any;
mockHttpClient.head.mockResolvedValue(mockResponse);
const result = await (distribution as any).findPackageForDownload('17');
@ -960,7 +1026,7 @@ describe('GraalVMDistribution', () => {
const mockResponse = {
message: {statusCode: 200}
} as http.HttpClientResponse;
} as any;
mockHttpClient.head.mockResolvedValue(mockResponse);
const result = await (distribution as any).findPackageForDownload('17');

View File

@ -1,14 +1,53 @@
import {
jest,
describe,
it,
expect,
beforeEach,
afterEach,
beforeAll,
afterAll
} from '@jest/globals';
import https from 'https';
import {HttpClient} from '@actions/http-client';
import {JetBrainsDistribution} from '../../src/distributions/jetbrains/installer';
import manifestData from '../data/jetbrains.json';
import manifestData from '../data/jetbrains.json' with {type: 'json'};
import os from 'os';
import * as core from '@actions/core';
// Mock @actions/core before importing source modules that depend on it
jest.unstable_mockModule('@actions/core', () => ({
info: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
setFailed: jest.fn(),
setOutput: jest.fn(),
getInput: jest.fn(),
getBooleanInput: jest.fn(),
getMultilineInput: jest.fn(),
addPath: jest.fn(),
exportVariable: jest.fn(),
saveState: jest.fn(),
getState: jest.fn(),
setSecret: jest.fn(),
isDebug: jest.fn(() => false),
startGroup: jest.fn(),
endGroup: jest.fn(),
group: jest.fn((_name: string, fn: () => Promise<unknown>) => fn()),
toPlatformPath: jest.fn((p: string) => p),
toWin32Path: jest.fn((p: string) => p),
toPosixPath: jest.fn((p: string) => p)
}));
// Dynamic imports after mocking
const core = await import('@actions/core');
const {JetBrainsDistribution} =
await import('../../src/distributions/jetbrains/installer.js');
describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
let spyHttpClient: any;
let spyCoreError: any;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@ -19,7 +58,7 @@ describe('getAvailableVersions', () => {
});
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError = core.error as jest.Mock;
spyCoreError.mockImplementation(() => {});
});
@ -31,11 +70,17 @@ describe('getAvailableVersions', () => {
it('load available versions', async () => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
spyHttpClient.mockReturnValueOnce({
statusCode: 200,
headers: {},
result: manifestData as any
});
spyHttpClient
.mockReturnValueOnce({
statusCode: 200,
headers: {},
result: manifestData as any
})
.mockReturnValue({
statusCode: 200,
headers: {},
result: []
});
const distribution = new JetBrainsDistribution({
version: '17',

View File

@ -1,4 +1,4 @@
import {KonaDistribution} from '../../src/distributions/kona/installer';
import {KonaDistribution} from '../../src/distributions/kona/installer.js';
import manifestData from '../data/kona.json';

View File

@ -1,17 +1,56 @@
import {LibericaDistributions} from '../../src/distributions/liberica/installer';
import {
jest,
describe,
it,
expect,
beforeEach,
afterEach,
beforeAll,
afterAll
} from '@jest/globals';
import type {
ArchitectureOptions,
LibericaVersion
} from '../../src/distributions/liberica/models';
} from '../../src/distributions/liberica/models.js';
import {HttpClient} from '@actions/http-client';
import os from 'os';
import * as core from '@actions/core';
import manifestData from '../data/liberica.json';
import manifestData from '../data/liberica.json' with {type: 'json'};
// Mock @actions/core before importing source modules that depend on it
jest.unstable_mockModule('@actions/core', () => ({
info: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
setFailed: jest.fn(),
setOutput: jest.fn(),
getInput: jest.fn(),
getBooleanInput: jest.fn(),
getMultilineInput: jest.fn(),
addPath: jest.fn(),
exportVariable: jest.fn(),
saveState: jest.fn(),
getState: jest.fn(),
setSecret: jest.fn(),
isDebug: jest.fn(() => false),
startGroup: jest.fn(),
endGroup: jest.fn(),
group: jest.fn((_name: string, fn: () => Promise<unknown>) => fn()),
toPlatformPath: jest.fn((p: string) => p),
toWin32Path: jest.fn((p: string) => p),
toPosixPath: jest.fn((p: string) => p)
}));
// Dynamic imports after mocking
const core = await import('@actions/core');
const {LibericaDistributions} =
await import('../../src/distributions/liberica/installer.js');
describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
let spyHttpClient: any;
let spyCoreError: any;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@ -22,7 +61,7 @@ describe('getAvailableVersions', () => {
});
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError = core.error as jest.Mock;
spyCoreError.mockImplementation(() => {});
});
@ -184,7 +223,7 @@ describe('getArchitectureOptions', () => {
});
describe('findPackageForDownload', () => {
let distribution: LibericaDistributions;
let distribution: InstanceType<typeof LibericaDistributions>;
beforeEach(() => {
distribution = new LibericaDistributions({

View File

@ -1,17 +1,56 @@
import {LibericaDistributions} from '../../src/distributions/liberica/installer';
import {
jest,
describe,
it,
expect,
beforeEach,
afterEach,
beforeAll,
afterAll
} from '@jest/globals';
import type {
ArchitectureOptions,
LibericaVersion
} from '../../src/distributions/liberica/models';
} from '../../src/distributions/liberica/models.js';
import {HttpClient} from '@actions/http-client';
import os from 'os';
import * as core from '@actions/core';
import manifestData from '../data/liberica-linux.json';
import manifestData from '../data/liberica-linux.json' with {type: 'json'};
// Mock @actions/core before importing source modules that depend on it
jest.unstable_mockModule('@actions/core', () => ({
info: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
setFailed: jest.fn(),
setOutput: jest.fn(),
getInput: jest.fn(),
getBooleanInput: jest.fn(),
getMultilineInput: jest.fn(),
addPath: jest.fn(),
exportVariable: jest.fn(),
saveState: jest.fn(),
getState: jest.fn(),
setSecret: jest.fn(),
isDebug: jest.fn(() => false),
startGroup: jest.fn(),
endGroup: jest.fn(),
group: jest.fn((_name: string, fn: () => Promise<unknown>) => fn()),
toPlatformPath: jest.fn((p: string) => p),
toWin32Path: jest.fn((p: string) => p),
toPosixPath: jest.fn((p: string) => p)
}));
// Dynamic imports after mocking
const core = await import('@actions/core');
const {LibericaDistributions} =
await import('../../src/distributions/liberica/installer.js');
describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
let spyHttpClient: any;
let spyCoreError: any;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@ -22,7 +61,7 @@ describe('getAvailableVersions', () => {
});
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError = core.error as jest.Mock;
spyCoreError.mockImplementation(() => {});
});
@ -184,7 +223,7 @@ describe('getArchitectureOptions', () => {
});
describe('findPackageForDownload', () => {
let distribution: LibericaDistributions;
let distribution: InstanceType<typeof LibericaDistributions>;
beforeEach(() => {
distribution = new LibericaDistributions({

View File

@ -1,17 +1,56 @@
import {LibericaDistributions} from '../../src/distributions/liberica/installer';
import {
jest,
describe,
it,
expect,
beforeEach,
afterEach,
beforeAll,
afterAll
} from '@jest/globals';
import type {
ArchitectureOptions,
LibericaVersion
} from '../../src/distributions/liberica/models';
} from '../../src/distributions/liberica/models.js';
import {HttpClient} from '@actions/http-client';
import os from 'os';
import * as core from '@actions/core';
import manifestData from '../data/liberica-windows.json';
import manifestData from '../data/liberica-windows.json' with {type: 'json'};
// Mock @actions/core before importing source modules that depend on it
jest.unstable_mockModule('@actions/core', () => ({
info: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
setFailed: jest.fn(),
setOutput: jest.fn(),
getInput: jest.fn(),
getBooleanInput: jest.fn(),
getMultilineInput: jest.fn(),
addPath: jest.fn(),
exportVariable: jest.fn(),
saveState: jest.fn(),
getState: jest.fn(),
setSecret: jest.fn(),
isDebug: jest.fn(() => false),
startGroup: jest.fn(),
endGroup: jest.fn(),
group: jest.fn((_name: string, fn: () => Promise<unknown>) => fn()),
toPlatformPath: jest.fn((p: string) => p),
toWin32Path: jest.fn((p: string) => p),
toPosixPath: jest.fn((p: string) => p)
}));
// Dynamic imports after mocking
const core = await import('@actions/core');
const {LibericaDistributions} =
await import('../../src/distributions/liberica/installer.js');
describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
let spyHttpClient: any;
let spyCoreError: any;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@ -21,7 +60,7 @@ describe('getAvailableVersions', () => {
result: manifestData as LibericaVersion[]
});
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError = core.error as jest.Mock;
spyCoreError.mockImplementation(() => {});
});
@ -183,7 +222,7 @@ describe('getArchitectureOptions', () => {
});
describe('findPackageForDownload', () => {
let distribution: LibericaDistributions;
let distribution: InstanceType<typeof LibericaDistributions>;
beforeEach(() => {
distribution = new LibericaDistributions({

View File

@ -1,37 +1,101 @@
import {
jest,
describe,
it,
expect,
beforeEach,
afterEach,
beforeAll,
afterAll
} from '@jest/globals';
import fs from 'fs';
import * as tc from '@actions/tool-cache';
import * as core from '@actions/core';
import path from 'path';
import * as semver from 'semver';
import * as util from '../../src/util';
import {LocalDistribution} from '../../src/distributions/local/installer';
// Mock @actions/core before importing source modules that depend on it
jest.unstable_mockModule('@actions/core', () => ({
info: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
setFailed: jest.fn(),
setOutput: jest.fn(),
getInput: jest.fn(),
getBooleanInput: jest.fn(),
getMultilineInput: jest.fn(),
addPath: jest.fn(),
exportVariable: jest.fn(),
saveState: jest.fn(),
getState: jest.fn(),
setSecret: jest.fn(),
isDebug: jest.fn(() => false),
startGroup: jest.fn(),
endGroup: jest.fn(),
group: jest.fn((_name: string, fn: () => Promise<unknown>) => fn()),
toPlatformPath: jest.fn((p: string) => p),
toWin32Path: jest.fn((p: string) => p),
toPosixPath: jest.fn((p: string) => p)
}));
jest.unstable_mockModule('@actions/tool-cache', () => ({
find: jest.fn(),
findAllVersions: jest.fn(),
downloadTool: jest.fn(),
extractZip: jest.fn(),
extractTar: jest.fn(),
extract7z: jest.fn(),
extractXar: jest.fn(),
cacheDir: jest.fn(),
cacheFile: jest.fn(),
getManifestFromRepo: jest.fn(),
findFromManifest: jest.fn(),
evaluateVersions: jest.fn()
}));
const real_util_module = await import('../../src/util.js');
jest.unstable_mockModule('../../src/util.js', () => ({
...real_util_module,
extractJdkFile: jest.fn(),
getDownloadArchiveExtension: jest.fn(),
getToolcachePath: jest.fn(),
isJobStatusSuccess: jest.fn(),
renameWinArchive: jest.fn(),
isVersionSatisfies: real_util_module.isVersionSatisfies,
getTempDir: real_util_module.getTempDir
}));
// Dynamic imports after mocking
const core = await import('@actions/core');
const tc = await import('@actions/tool-cache');
const util = await import('../../src/util.js');
const {LocalDistribution} =
await import('../../src/distributions/local/installer.js');
describe('setupJava', () => {
const actualJavaVersion = '11.1.10';
const javaPath = path.join('Java_jdkfile_jdk', actualJavaVersion, 'x86');
let mockJavaBase: LocalDistribution;
let mockJavaBase: InstanceType<typeof LocalDistribution>;
let spyGetToolcachePath: jest.SpyInstance;
let spyTcCacheDir: jest.SpyInstance;
let spyTcFindAllVersions: jest.SpyInstance;
let spyCoreDebug: jest.SpyInstance;
let spyCoreInfo: jest.SpyInstance;
let spyCoreExportVariable: jest.SpyInstance;
let spyCoreAddPath: jest.SpyInstance;
let spyCoreSetOutput: jest.SpyInstance;
let spyFsStat: jest.SpyInstance;
let spyFsReadDir: jest.SpyInstance;
let spyUtilsExtractJdkFile: jest.SpyInstance;
let spyPathResolve: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
let spyGetToolcachePath: any;
let spyTcCacheDir: any;
let spyTcFindAllVersions: any;
let spyCoreDebug: any;
let spyCoreInfo: any;
let spyCoreExportVariable: any;
let spyCoreAddPath: any;
let spyCoreSetOutput: any;
let spyFsStat: any;
let spyFsReadDir: any;
let spyUtilsExtractJdkFile: any;
let spyPathResolve: any;
let spyCoreError: any;
const expectedJdkFile = 'JavaLocalJdkFile';
beforeEach(() => {
spyGetToolcachePath = jest.spyOn(util, 'getToolcachePath');
spyGetToolcachePath = util.getToolcachePath as jest.Mock;
spyGetToolcachePath.mockImplementation(
(toolname: string, javaVersion: string, architecture: string) => {
const semverVersion = new semver.Range(javaVersion);
@ -49,7 +113,7 @@ describe('setupJava', () => {
}
);
spyTcCacheDir = jest.spyOn(tc, 'cacheDir');
spyTcCacheDir = tc.cacheDir as jest.Mock;
spyTcCacheDir.mockImplementation(
(
archivePath: string,
@ -59,23 +123,23 @@ describe('setupJava', () => {
) => path.join(toolcacheFolderName, version, architecture)
);
spyTcFindAllVersions = jest.spyOn(tc, 'findAllVersions');
spyTcFindAllVersions = tc.findAllVersions as jest.Mock;
spyTcFindAllVersions.mockReturnValue([actualJavaVersion]);
// Spy on core methods
spyCoreDebug = jest.spyOn(core, 'debug');
spyCoreDebug = core.debug as jest.Mock;
spyCoreDebug.mockImplementation(() => undefined);
spyCoreInfo = jest.spyOn(core, 'info');
spyCoreInfo = core.info as jest.Mock;
spyCoreInfo.mockImplementation(() => undefined);
spyCoreAddPath = jest.spyOn(core, 'addPath');
spyCoreAddPath = core.addPath as jest.Mock;
spyCoreAddPath.mockImplementation(() => undefined);
spyCoreExportVariable = jest.spyOn(core, 'exportVariable');
spyCoreExportVariable = core.exportVariable as jest.Mock;
spyCoreExportVariable.mockImplementation(() => undefined);
spyCoreSetOutput = jest.spyOn(core, 'setOutput');
spyCoreSetOutput = core.setOutput as jest.Mock;
spyCoreSetOutput.mockImplementation(() => undefined);
// Spy on fs methods
@ -88,7 +152,7 @@ describe('setupJava', () => {
});
// Spy on util methods
spyUtilsExtractJdkFile = jest.spyOn(util, 'extractJdkFile');
spyUtilsExtractJdkFile = util.extractJdkFile as jest.Mock;
spyUtilsExtractJdkFile.mockImplementation(() => 'some/random/path/');
// Spy on path methods
@ -96,7 +160,7 @@ describe('setupJava', () => {
spyPathResolve.mockImplementation((path: string) => path);
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError = core.error as jest.Mock;
spyCoreError.mockImplementation(() => {});
});

View File

@ -1,23 +1,115 @@
import {
MicrosoftDistributions,
MICROSOFT_PUBLIC_KEY
} from '../../src/distributions/microsoft/installer';
import os from 'os';
import data from '../data/microsoft.json';
import * as httpm from '@actions/http-client';
import * as core from '@actions/core';
import * as tc from '@actions/tool-cache';
import * as gpg from '../../src/gpg';
import * as util from '../../src/util';
import fs from 'fs';
jest,
describe,
it,
expect,
beforeEach,
afterEach,
beforeAll,
afterAll
} from '@jest/globals';
import {HttpClient} from '@actions/http-client';
import data from '../data/microsoft.json' with {type: 'json'};
const mockOsArch = jest.fn(() => 'x64');
const mockOsPlatform = jest.fn(() => 'linux');
const real_os_module = await import('os');
jest.unstable_mockModule('os', () => ({
...real_os_module,
default: {
...real_os_module.default,
arch: mockOsArch,
platform: mockOsPlatform,
homedir: real_os_module.default.homedir
},
arch: mockOsArch,
platform: mockOsPlatform
}));
const real_fs_module = await import('fs');
const mockReaddirSync = jest.fn();
jest.unstable_mockModule('fs', () => ({
...real_fs_module,
default: {
...real_fs_module.default,
readdirSync: mockReaddirSync
},
readdirSync: mockReaddirSync
}));
// Mock @actions/core before importing source modules that depend on it
jest.unstable_mockModule('@actions/core', () => ({
info: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
setFailed: jest.fn(),
setOutput: jest.fn(),
getInput: jest.fn(),
getBooleanInput: jest.fn(),
getMultilineInput: jest.fn(),
addPath: jest.fn(),
exportVariable: jest.fn(),
saveState: jest.fn(),
getState: jest.fn(),
setSecret: jest.fn(),
isDebug: jest.fn(() => false),
startGroup: jest.fn(),
endGroup: jest.fn(),
group: jest.fn((_name: string, fn: () => Promise<unknown>) => fn()),
toPlatformPath: jest.fn((p: string) => p),
toWin32Path: jest.fn((p: string) => p),
toPosixPath: jest.fn((p: string) => p)
}));
const real_tc_module = await import('@actions/tool-cache');
jest.unstable_mockModule('@actions/tool-cache', () => ({
...real_tc_module,
downloadTool: jest.fn(),
cacheDir: jest.fn(),
cacheFile: jest.fn()
}));
const real_util_module = await import('../../src/util.js');
jest.unstable_mockModule('../../src/util.js', () => ({
...real_util_module,
extractJdkFile: jest.fn(),
getDownloadArchiveExtension: jest.fn(),
getToolcachePath: jest.fn(),
isJobStatusSuccess: jest.fn(),
renameWinArchive: jest.fn(),
isVersionSatisfies: real_util_module.isVersionSatisfies,
getTempDir: real_util_module.getTempDir
}));
jest.unstable_mockModule('../../src/gpg.js', () => ({
importKey: jest.fn(),
deleteKey: jest.fn(),
verifyPackageSignature: jest.fn()
}));
// Dynamic imports after mocking
const core = await import('@actions/core');
const gpg = await import('../../src/gpg.js');
const tc = await import('@actions/tool-cache');
const os = (await import('os')).default;
const fs = (await import('fs')).default;
const {MicrosoftDistributions, MICROSOFT_PUBLIC_KEY} =
await import('../../src/distributions/microsoft/installer.js');
const util = await import('../../src/util.js');
describe('findPackageForDownload', () => {
let distribution: MicrosoftDistributions;
let spyGetManifestFromRepo: jest.SpyInstance;
let spyDebug: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
let distribution: InstanceType<typeof MicrosoftDistributions>;
let spyGetManifestFromRepo: any;
let spyDebug: any;
let spyCoreError: any;
beforeEach(() => {
mockOsArch.mockReturnValue('x64');
mockOsPlatform.mockReturnValue(process.platform);
distribution = new MicrosoftDistributions({
version: '',
architecture: 'x64',
@ -25,18 +117,18 @@ describe('findPackageForDownload', () => {
checkLatest: false
});
spyGetManifestFromRepo = jest.spyOn(httpm.HttpClient.prototype, 'getJson');
spyGetManifestFromRepo = jest.spyOn(HttpClient.prototype, 'getJson');
spyGetManifestFromRepo.mockReturnValue({
result: data,
statusCode: 200,
headers: {}
});
spyDebug = jest.spyOn(core, 'debug');
spyDebug = core.debug as jest.Mock;
spyDebug.mockImplementation(() => {});
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError = core.error as jest.Mock;
spyCoreError.mockImplementation(() => {});
});
@ -118,10 +210,8 @@ describe('findPackageForDownload', () => {
])(
'defaults to os.arch(): %s mapped to distro arch: %s',
async (osArch: string, distroArch: string) => {
jest
.spyOn(os, 'arch')
.mockReturnValue(osArch as ReturnType<typeof os.arch>);
jest.spyOn(os, 'platform').mockReturnValue('darwin');
mockOsArch.mockReturnValue(osArch);
mockOsPlatform.mockReturnValue('darwin');
const version = '17';
const distro = new MicrosoftDistributions({
@ -144,10 +234,8 @@ describe('findPackageForDownload', () => {
])(
'defaults to os.arch(): %s mapped to distro arch: %s',
async (osArch: string, distroArch: string) => {
jest
.spyOn(os, 'arch')
.mockReturnValue(osArch as ReturnType<typeof os.arch>);
jest.spyOn(os, 'platform').mockReturnValue('linux');
mockOsArch.mockReturnValue(osArch);
mockOsPlatform.mockReturnValue('linux');
const version = '17';
const distro = new MicrosoftDistributions({
@ -170,10 +258,8 @@ describe('findPackageForDownload', () => {
])(
'defaults to os.arch(): %s mapped to distro arch: %s',
async (osArch: string, distroArch: string) => {
jest
.spyOn(os, 'arch')
.mockReturnValue(osArch as ReturnType<typeof os.arch>);
jest.spyOn(os, 'platform').mockReturnValue('win32');
mockOsArch.mockReturnValue(osArch);
mockOsPlatform.mockReturnValue('win32');
const version = '17';
const distro = new MicrosoftDistributions({
@ -217,7 +303,7 @@ describe('findPackageForDownload', () => {
statusCode: 200,
headers: {}
});
jest.spyOn(os, 'platform').mockReturnValue('linux');
mockOsPlatform.mockReturnValue('linux');
const result = await distribution['findPackageForDownload']('17.0.10');
@ -228,16 +314,14 @@ describe('findPackageForDownload', () => {
});
describe('downloadTool', () => {
let spyDownloadTool: jest.SpyInstance;
let spyExtractJdkFile: jest.SpyInstance;
let spyCacheDir: jest.SpyInstance;
let spyVerifySignature: jest.SpyInstance;
let distribution: MicrosoftDistributions;
let spyDownloadTool: any;
let spyExtractJdkFile: any;
let spyCacheDir: any;
let spyVerifySignature: any;
let distribution: InstanceType<typeof MicrosoftDistributions>;
beforeEach(() => {
jest
.spyOn(os, 'platform')
.mockReturnValue(process.platform as ReturnType<typeof os.platform>);
mockOsPlatform.mockReturnValue(process.platform);
distribution = new MicrosoftDistributions({
version: '17',
@ -246,27 +330,27 @@ describe('downloadTool', () => {
checkLatest: false
});
spyDownloadTool = jest.spyOn(tc, 'downloadTool');
spyDownloadTool = tc.downloadTool as jest.Mock;
spyDownloadTool.mockImplementation(async () => {
return '/tmp/jdk.tar.gz';
});
spyExtractJdkFile = jest.spyOn(util, 'extractJdkFile');
spyExtractJdkFile = util.extractJdkFile as jest.Mock;
spyExtractJdkFile.mockImplementation(async () => {
return '/tmp/unpacked';
});
jest.spyOn(fs, 'readdirSync').mockReturnValue(['jdk'] as any);
spyCacheDir = jest.spyOn(tc, 'cacheDir');
mockReaddirSync.mockReturnValue(['jdk'] as any);
spyCacheDir = tc.cacheDir as jest.Mock;
spyCacheDir.mockImplementation(async () => {
return '/tmp/cached';
});
jest
.spyOn(util, 'renameWinArchive')
.mockImplementation((archivePath: string) => `${archivePath}.zip`);
(util.renameWinArchive as jest.Mock<any>).mockImplementation(
(archivePath: string) => `${archivePath}.zip`
);
spyVerifySignature = jest.spyOn(gpg, 'verifyPackageSignature');
spyVerifySignature = gpg.verifyPackageSignature as jest.Mock;
spyVerifySignature.mockImplementation(async () => {});
});

View File

@ -1,14 +1,53 @@
import {OracleDistribution} from '../../src/distributions/oracle/installer';
import {
jest,
describe,
it,
expect,
beforeEach,
afterEach,
beforeAll,
afterAll
} from '@jest/globals';
import os from 'os';
import * as core from '@actions/core';
import {getDownloadArchiveExtension} from '../../src/util';
import {HttpClient} from '@actions/http-client';
// Mock @actions/core before importing source modules that depend on it
jest.unstable_mockModule('@actions/core', () => ({
info: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
setFailed: jest.fn(),
setOutput: jest.fn(),
getInput: jest.fn(),
getBooleanInput: jest.fn(),
getMultilineInput: jest.fn(),
addPath: jest.fn(),
exportVariable: jest.fn(),
saveState: jest.fn(),
getState: jest.fn(),
setSecret: jest.fn(),
isDebug: jest.fn(() => false),
startGroup: jest.fn(),
endGroup: jest.fn(),
group: jest.fn((_name: string, fn: () => Promise<unknown>) => fn()),
toPlatformPath: jest.fn((p: string) => p),
toWin32Path: jest.fn((p: string) => p),
toPosixPath: jest.fn((p: string) => p)
}));
// Dynamic imports after mocking
const core = await import('@actions/core');
const {OracleDistribution} =
await import('../../src/distributions/oracle/installer.js');
const {getDownloadArchiveExtension} = await import('../../src/util.js');
describe('findPackageForDownload', () => {
let distribution: OracleDistribution;
let spyDebug: jest.SpyInstance;
let spyHttpClient: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
let distribution: InstanceType<typeof OracleDistribution>;
let spyDebug: any;
let spyHttpClient: any;
let spyCoreError: any;
beforeEach(() => {
distribution = new OracleDistribution({
@ -18,11 +57,11 @@ describe('findPackageForDownload', () => {
checkLatest: false
});
spyDebug = jest.spyOn(core, 'debug');
spyDebug = core.debug as jest.Mock;
spyDebug.mockImplementation(() => {});
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError = core.error as jest.Mock;
spyCoreError.mockImplementation(() => {});
});

View File

@ -1,14 +1,59 @@
import {
jest,
describe,
it,
expect,
beforeEach,
afterEach,
beforeAll,
afterAll
} from '@jest/globals';
import {HttpClient} from '@actions/http-client';
import {SapMachineDistribution} from '../../src/distributions/sapmachine/installer';
import * as utils from '../../src/util';
import * as core from '@actions/core';
import manifestData from '../data/sapmachine.json';
import manifestData from '../data/sapmachine.json' with {type: 'json'};
// Mock @actions/core before importing source modules that depend on it
jest.unstable_mockModule('@actions/core', () => ({
info: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
setFailed: jest.fn(),
setOutput: jest.fn(),
getInput: jest.fn(),
getBooleanInput: jest.fn(),
getMultilineInput: jest.fn(),
addPath: jest.fn(),
exportVariable: jest.fn(),
saveState: jest.fn(),
getState: jest.fn(),
setSecret: jest.fn(),
isDebug: jest.fn(() => false),
startGroup: jest.fn(),
endGroup: jest.fn(),
group: jest.fn((_name: string, fn: () => Promise<unknown>) => fn()),
toPlatformPath: jest.fn((p: string) => p),
toWin32Path: jest.fn((p: string) => p),
toPosixPath: jest.fn((p: string) => p)
}));
const real_util_module = await import('../../src/util.js');
jest.unstable_mockModule('../../src/util.js', () => ({
...real_util_module,
getDownloadArchiveExtension: jest.fn()
}));
// Dynamic imports after mocking
const core = await import('@actions/core');
const {SapMachineDistribution} =
await import('../../src/distributions/sapmachine/installer.js');
const utils = await import('../../src/util.js');
describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance;
let spyUtilGetDownloadArchiveExtension: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
let spyHttpClient: any;
let spyUtilGetDownloadArchiveExtension: any;
let spyCoreError: any;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@ -18,14 +63,12 @@ describe('getAvailableVersions', () => {
result: manifestData
});
spyUtilGetDownloadArchiveExtension = jest.spyOn(
utils,
'getDownloadArchiveExtension'
);
spyUtilGetDownloadArchiveExtension =
utils.getDownloadArchiveExtension as jest.Mock<any>;
spyUtilGetDownloadArchiveExtension.mockReturnValue('tar.gz');
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError = core.error as jest.Mock;
spyCoreError.mockImplementation(() => {});
});
@ -36,7 +79,7 @@ describe('getAvailableVersions', () => {
});
const mockPlatform = (
distribution: SapMachineDistribution,
distribution: InstanceType<typeof SapMachineDistribution>,
platform: string
) => {
distribution['getPlatformOption'] = () => platform;

View File

@ -1,15 +1,53 @@
import {
jest,
describe,
it,
expect,
beforeEach,
afterEach,
beforeAll,
afterAll
} from '@jest/globals';
import type {JavaInstallerOptions} from '../../src/distributions/base-models.js';
import {HttpClient} from '@actions/http-client';
import {JavaInstallerOptions} from '../../src/distributions/base-models';
import {SemeruDistribution} from '../../src/distributions/semeru/installer';
import manifestData from '../data/semeru.json' with {type: 'json'};
import manifestData from '../data/semeru.json';
import * as core from '@actions/core';
// Mock @actions/core before importing source modules that depend on it
jest.unstable_mockModule('@actions/core', () => ({
info: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
setFailed: jest.fn(),
setOutput: jest.fn(),
getInput: jest.fn(),
getBooleanInput: jest.fn(),
getMultilineInput: jest.fn(),
addPath: jest.fn(),
exportVariable: jest.fn(),
saveState: jest.fn(),
getState: jest.fn(),
setSecret: jest.fn(),
isDebug: jest.fn(() => false),
startGroup: jest.fn(),
endGroup: jest.fn(),
group: jest.fn((_name: string, fn: () => Promise<unknown>) => fn()),
toPlatformPath: jest.fn((p: string) => p),
toWin32Path: jest.fn((p: string) => p),
toPosixPath: jest.fn((p: string) => p)
}));
// Dynamic imports after mocking
const core = await import('@actions/core');
const {SemeruDistribution} =
await import('../../src/distributions/semeru/installer.js');
describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
let spyCoreWarning: jest.SpyInstance;
let spyHttpClient: any;
let spyCoreError: any;
let spyCoreWarning: any;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@ -19,9 +57,9 @@ describe('getAvailableVersions', () => {
result: []
});
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError = core.error as jest.Mock;
spyCoreError.mockImplementation(() => {});
spyCoreWarning = jest.spyOn(core, 'warning');
spyCoreWarning = core.warning as jest.Mock;
spyCoreWarning.mockImplementation(() => {});
});

View File

@ -1,23 +1,92 @@
import {
jest,
describe,
it,
expect,
beforeEach,
afterEach,
beforeAll,
afterAll
} from '@jest/globals';
import type {JavaInstallerOptions} from '../../src/distributions/base-models.js';
import type {TemurinImplementation as TemurinImplementationType} from '../../src/distributions/temurin/installer.js';
import {HttpClient} from '@actions/http-client';
import * as tc from '@actions/tool-cache';
import fs from 'fs';
import os from 'os';
import {
TemurinDistribution,
TemurinImplementation,
ADOPTIUM_PUBLIC_KEY
} from '../../src/distributions/temurin/installer';
import {JavaInstallerOptions} from '../../src/distributions/base-models';
import * as util from '../../src/util';
import * as gpg from '../../src/gpg';
import manifestData from '../data/temurin.json';
import * as core from '@actions/core';
import manifestData from '../data/temurin.json' with {type: 'json'};
// Mock @actions/core before importing source modules that depend on it
jest.unstable_mockModule('@actions/core', () => ({
info: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
setFailed: jest.fn(),
setOutput: jest.fn(),
getInput: jest.fn(),
getBooleanInput: jest.fn(),
getMultilineInput: jest.fn(),
addPath: jest.fn(),
exportVariable: jest.fn(),
saveState: jest.fn(),
getState: jest.fn(),
setSecret: jest.fn(),
isDebug: jest.fn(() => false),
startGroup: jest.fn(),
endGroup: jest.fn(),
group: jest.fn((_name: string, fn: () => Promise<unknown>) => fn()),
toPlatformPath: jest.fn((p: string) => p),
toWin32Path: jest.fn((p: string) => p),
toPosixPath: jest.fn((p: string) => p)
}));
jest.unstable_mockModule('@actions/tool-cache', () => ({
find: jest.fn(),
findAllVersions: jest.fn(),
downloadTool: jest.fn(),
extractZip: jest.fn(),
extractTar: jest.fn(),
extract7z: jest.fn(),
extractXar: jest.fn(),
cacheDir: jest.fn(),
cacheFile: jest.fn(),
getManifestFromRepo: jest.fn(),
findFromManifest: jest.fn(),
evaluateVersions: jest.fn()
}));
const real_util_module = await import('../../src/util.js');
jest.unstable_mockModule('../../src/util.js', () => ({
...real_util_module,
extractJdkFile: jest.fn(),
getDownloadArchiveExtension: jest.fn(),
getToolcachePath: jest.fn(),
isJobStatusSuccess: jest.fn(),
renameWinArchive: jest.fn(),
isVersionSatisfies: real_util_module.isVersionSatisfies,
getTempDir: real_util_module.getTempDir
}));
jest.unstable_mockModule('../../src/gpg.js', () => ({
importKey: jest.fn(),
deleteKey: jest.fn(),
verifyPackageSignature: jest.fn()
}));
// Dynamic imports after mocking
const core = await import('@actions/core');
const gpg = await import('../../src/gpg.js');
const tc = await import('@actions/tool-cache');
const {TemurinDistribution, TemurinImplementation, ADOPTIUM_PUBLIC_KEY} =
await import('../../src/distributions/temurin/installer.js');
const util = await import('../../src/util.js');
describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
let spyCoreWarning: jest.SpyInstance;
let spyHttpClient: any;
let spyCoreError: any;
let spyCoreWarning: any;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@ -27,9 +96,9 @@ describe('getAvailableVersions', () => {
result: []
});
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError = core.error as jest.Mock;
spyCoreError.mockImplementation(() => {});
spyCoreWarning = jest.spyOn(core, 'warning');
spyCoreWarning = core.warning as jest.Mock;
spyCoreWarning.mockImplementation(() => {});
});
@ -84,7 +153,7 @@ describe('getAvailableVersions', () => {
'build correct url for %s',
async (
installerOptions: JavaInstallerOptions,
impl: TemurinImplementation,
impl: TemurinImplementationType,
expectedParameters
) => {
const distribution = new TemurinDistribution(installerOptions, impl);
@ -163,7 +232,11 @@ describe('getAvailableVersions', () => {
[TemurinImplementation.Hotspot, 'jre', 'Java_Temurin-Hotspot_jre']
])(
'find right toolchain folder',
(impl: TemurinImplementation, packageType: string, expected: string) => {
(
impl: TemurinImplementationType,
packageType: string,
expected: string
) => {
const distribution = new TemurinDistribution(
{
version: '8',
@ -289,25 +362,25 @@ describe('findPackageForDownload', () => {
});
describe('downloadTool', () => {
let spyDownloadTool: jest.SpyInstance;
let spyVerifySignature: jest.SpyInstance;
let spyExtractJdkFile: jest.SpyInstance;
let spyCacheDir: jest.SpyInstance;
let spyReadDirSync: jest.SpyInstance;
let spyRenameWinArchive: jest.SpyInstance;
let spyDownloadTool: any;
let spyVerifySignature: any;
let spyExtractJdkFile: any;
let spyCacheDir: any;
let spyReadDirSync: any;
let spyRenameWinArchive: any;
beforeEach(() => {
spyDownloadTool = jest.spyOn(tc, 'downloadTool');
spyDownloadTool = tc.downloadTool as jest.Mock;
spyDownloadTool.mockResolvedValue('/tmp/jdk.tar.gz');
spyVerifySignature = jest.spyOn(gpg, 'verifyPackageSignature');
spyVerifySignature = gpg.verifyPackageSignature as jest.Mock;
spyVerifySignature.mockResolvedValue(undefined);
spyExtractJdkFile = jest.spyOn(util, 'extractJdkFile');
spyExtractJdkFile = util.extractJdkFile as jest.Mock;
spyExtractJdkFile.mockResolvedValue('/tmp/extracted');
spyCacheDir = jest.spyOn(tc, 'cacheDir');
spyCacheDir = tc.cacheDir as jest.Mock;
spyCacheDir.mockResolvedValue('/tmp/toolcache');
spyReadDirSync = jest.spyOn(fs, 'readdirSync');
spyReadDirSync.mockReturnValue(['jdk-17'] as any);
spyRenameWinArchive = jest.spyOn(util, 'renameWinArchive');
spyRenameWinArchive = util.renameWinArchive as jest.Mock;
spyRenameWinArchive.mockReturnValue('/tmp/jdk.tar.gz.zip');
});

View File

@ -1,16 +1,60 @@
import {
jest,
describe,
it,
expect,
beforeEach,
afterEach,
beforeAll,
afterAll
} from '@jest/globals';
import type {IZuluVersions} from '../../src/distributions/zulu/models.js';
import {HttpClient} from '@actions/http-client';
import {ZuluDistribution} from '../../src/distributions/zulu/installer';
import {IZuluVersions} from '../../src/distributions/zulu/models';
import * as utils from '../../src/util';
import os from 'os';
import * as core from '@actions/core';
import manifestData from '../data/zulu-releases-default.json';
import manifestData from '../data/zulu-releases-default.json' with {type: 'json'};
// Mock @actions/core before importing source modules that depend on it
jest.unstable_mockModule('@actions/core', () => ({
info: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
setFailed: jest.fn(),
setOutput: jest.fn(),
getInput: jest.fn(),
getBooleanInput: jest.fn(),
getMultilineInput: jest.fn(),
addPath: jest.fn(),
exportVariable: jest.fn(),
saveState: jest.fn(),
getState: jest.fn(),
setSecret: jest.fn(),
isDebug: jest.fn(() => false),
startGroup: jest.fn(),
endGroup: jest.fn(),
group: jest.fn((_name: string, fn: () => Promise<unknown>) => fn()),
toPlatformPath: jest.fn((p: string) => p),
toWin32Path: jest.fn((p: string) => p),
toPosixPath: jest.fn((p: string) => p)
}));
const real_util_module = await import('../../src/util.js');
jest.unstable_mockModule('../../src/util.js', () => ({
...real_util_module,
getDownloadArchiveExtension: jest.fn()
}));
// Dynamic imports after mocking
const core = await import('@actions/core');
const {ZuluDistribution} =
await import('../../src/distributions/zulu/installer.js');
const utils = await import('../../src/util.js');
describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance;
let spyUtilGetDownloadArchiveExtension: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
let spyHttpClient: any;
let spyCoreError: any;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@ -20,14 +64,12 @@ describe('getAvailableVersions', () => {
result: manifestData as IZuluVersions[]
});
spyUtilGetDownloadArchiveExtension = jest.spyOn(
utils,
'getDownloadArchiveExtension'
(utils.getDownloadArchiveExtension as jest.Mock<any>).mockReturnValue(
'tar.gz'
);
spyUtilGetDownloadArchiveExtension.mockReturnValue('tar.gz');
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError = core.error as jest.Mock;
spyCoreError.mockImplementation(() => {});
});

View File

@ -1,17 +1,62 @@
import {
jest,
describe,
it,
expect,
beforeEach,
afterEach,
beforeAll,
afterAll
} from '@jest/globals';
import type {IZuluVersions} from '../../src/distributions/zulu/models.js';
import {HttpClient} from '@actions/http-client';
import * as semver from 'semver';
import {ZuluDistribution} from '../../src/distributions/zulu/installer';
import {IZuluVersions} from '../../src/distributions/zulu/models';
import * as utils from '../../src/util';
import os from 'os';
import * as core from '@actions/core';
import manifestData from '../data/zulu-linux.json';
import manifestData from '../data/zulu-linux.json' with {type: 'json'};
// Mock @actions/core before importing source modules that depend on it
jest.unstable_mockModule('@actions/core', () => ({
info: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
setFailed: jest.fn(),
setOutput: jest.fn(),
getInput: jest.fn(),
getBooleanInput: jest.fn(),
getMultilineInput: jest.fn(),
addPath: jest.fn(),
exportVariable: jest.fn(),
saveState: jest.fn(),
getState: jest.fn(),
setSecret: jest.fn(),
isDebug: jest.fn(() => false),
startGroup: jest.fn(),
endGroup: jest.fn(),
group: jest.fn((_name: string, fn: () => Promise<unknown>) => fn()),
toPlatformPath: jest.fn((p: string) => p),
toWin32Path: jest.fn((p: string) => p),
toPosixPath: jest.fn((p: string) => p)
}));
const real_util_module = await import('../../src/util.js');
jest.unstable_mockModule('../../src/util.js', () => ({
...real_util_module,
getDownloadArchiveExtension: jest.fn()
}));
// Dynamic imports after mocking
const core = await import('@actions/core');
const {ZuluDistribution} =
await import('../../src/distributions/zulu/installer.js');
const utils = await import('../../src/util.js');
describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance;
let spyUtilGetDownloadArchiveExtension: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
let spyHttpClient: any;
let spyUtilGetDownloadArchiveExtension: any;
let spyCoreError: any;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@ -21,14 +66,12 @@ describe('getAvailableVersions', () => {
result: manifestData as IZuluVersions[]
});
spyUtilGetDownloadArchiveExtension = jest.spyOn(
utils,
'getDownloadArchiveExtension'
);
spyUtilGetDownloadArchiveExtension =
utils.getDownloadArchiveExtension as jest.Mock<any>;
spyUtilGetDownloadArchiveExtension.mockReturnValue('zip');
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError = core.error as jest.Mock;
spyCoreError.mockImplementation(() => {});
});

View File

@ -1,17 +1,61 @@
import {
jest,
describe,
it,
expect,
beforeEach,
afterEach,
beforeAll,
afterAll
} from '@jest/globals';
import type {IZuluVersions} from '../../src/distributions/zulu/models.js';
import {HttpClient} from '@actions/http-client';
import * as semver from 'semver';
import {ZuluDistribution} from '../../src/distributions/zulu/installer';
import {IZuluVersions} from '../../src/distributions/zulu/models';
import * as utils from '../../src/util';
import os from 'os';
import * as core from '@actions/core';
import manifestData from '../data/zulu-windows.json';
import manifestData from '../data/zulu-windows.json' with {type: 'json'};
// Mock @actions/core before importing source modules that depend on it
jest.unstable_mockModule('@actions/core', () => ({
info: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
setFailed: jest.fn(),
setOutput: jest.fn(),
getInput: jest.fn(),
getBooleanInput: jest.fn(),
getMultilineInput: jest.fn(),
addPath: jest.fn(),
exportVariable: jest.fn(),
saveState: jest.fn(),
getState: jest.fn(),
setSecret: jest.fn(),
isDebug: jest.fn(() => false),
startGroup: jest.fn(),
endGroup: jest.fn(),
group: jest.fn((_name: string, fn: () => Promise<unknown>) => fn()),
toPlatformPath: jest.fn((p: string) => p),
toWin32Path: jest.fn((p: string) => p),
toPosixPath: jest.fn((p: string) => p)
}));
const real_util_module = await import('../../src/util.js');
jest.unstable_mockModule('../../src/util.js', () => ({
...real_util_module,
getDownloadArchiveExtension: jest.fn()
}));
// Dynamic imports after mocking
const core = await import('@actions/core');
const {ZuluDistribution} =
await import('../../src/distributions/zulu/installer.js');
const utils = await import('../../src/util.js');
describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance;
let spyUtilGetDownloadArchiveExtension: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
let spyHttpClient: any;
let spyCoreError: any;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@ -21,14 +65,12 @@ describe('getAvailableVersions', () => {
result: manifestData as IZuluVersions[]
});
spyUtilGetDownloadArchiveExtension = jest.spyOn(
utils,
'getDownloadArchiveExtension'
(utils.getDownloadArchiveExtension as jest.Mock<any>).mockReturnValue(
'zip'
);
spyUtilGetDownloadArchiveExtension.mockReturnValue('zip');
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError = core.error as jest.Mock;
spyCoreError.mockImplementation(() => {});
});

View File

@ -1,20 +1,29 @@
import {
jest,
describe,
it,
expect,
beforeEach,
afterAll,
afterEach
} from '@jest/globals';
import {fileURLToPath} from 'url';
import * as path from 'path';
import * as io from '@actions/io';
import * as exec from '@actions/exec';
import * as tc from '@actions/tool-cache';
import * as gpg from '../src/gpg';
jest.mock('@actions/exec', () => {
return {
exec: jest.fn()
};
});
const __dirname = path.dirname(fileURLToPath(import.meta.url));
jest.mock('@actions/tool-cache', () => {
return {
downloadTool: jest.fn()
};
});
jest.unstable_mockModule('@actions/exec', () => ({
exec: jest.fn()
}));
jest.unstable_mockModule('@actions/tool-cache', () => ({
downloadTool: jest.fn()
}));
const exec = await import('@actions/exec');
const tc = await import('@actions/tool-cache');
const gpg = await import('../src/gpg.js');
const tempDir = path.join(__dirname, 'runner', 'temp');
process.env['RUNNER_TEMP'] = tempDir;
@ -92,7 +101,9 @@ describe('gpg tests', () => {
it('imports bundled key and verifies package', async () => {
const publicKeyContent =
'-----BEGIN PGP PUBLIC KEY BLOCK-----\ntest\n-----END PGP PUBLIC KEY BLOCK-----';
(tc.downloadTool as jest.Mock).mockResolvedValue('/tmp/jdk.tar.gz.sig');
(tc.downloadTool as jest.Mock<any>).mockResolvedValue(
'/tmp/jdk.tar.gz.sig'
);
await gpg.verifyPackageSignature(
'/tmp/jdk.tar.gz',
'https://example.com/jdk.tar.gz.sig',

View File

@ -1,42 +1,68 @@
import * as core from '@actions/core';
import {afterEach, beforeEach, describe, expect, it, jest} from '@jest/globals';
import {configureMavenArgs} from '../src/maven-args';
import {
const mockGetInput = jest.fn<(...args: any[]) => any>();
const mockExportVariable = jest.fn<(...args: any[]) => any>();
const mockInfo = jest.fn<(...args: any[]) => any>();
const mockDebug = jest.fn<(...args: any[]) => any>();
const mockWarning = jest.fn<(...args: any[]) => any>();
jest.unstable_mockModule('@actions/core', () => ({
getInput: mockGetInput,
exportVariable: mockExportVariable,
info: mockInfo,
debug: mockDebug,
warning: mockWarning,
setSecret: jest.fn(),
setFailed: jest.fn(),
setOutput: jest.fn(),
addPath: jest.fn(),
getMultilineInput: jest.fn(),
getBooleanInput: jest.fn(),
getState: jest.fn(),
saveState: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
startGroup: jest.fn(),
endGroup: jest.fn(),
group: jest.fn(),
isDebug: jest.fn(),
setCommandEcho: jest.fn(),
getIDToken: jest.fn(),
ExitCode: {Success: 0, Failure: 1},
summary: {},
markdownSummary: {},
platform: {},
toPosixPath: jest.fn(),
toWin32Path: jest.fn(),
toPlatformPath: jest.fn()
}));
const {configureMavenArgs} = await import('../src/maven-args.js');
const {
INPUT_SHOW_DOWNLOAD_PROGRESS,
MAVEN_ARGS_ENV,
MAVEN_NO_TRANSFER_PROGRESS_FLAG
} from '../src/constants';
} = await import('../src/constants.js');
describe('configureMavenArgs', () => {
let inputs: Record<string, string>;
let spyGetInput: jest.SpyInstance;
let spyExportVariable: jest.SpyInstance;
let spyInfo: jest.SpyInstance;
let spyDebug: jest.SpyInstance;
const originalMavenArgs = process.env[MAVEN_ARGS_ENV];
beforeEach(() => {
inputs = {};
spyGetInput = jest.spyOn(core, 'getInput');
spyGetInput.mockImplementation((name: string) => inputs[name] ?? '');
spyExportVariable = jest.spyOn(core, 'exportVariable');
spyExportVariable.mockImplementation((name: string, value: string) => {
mockGetInput.mockImplementation((name: string) => inputs[name] ?? '');
mockExportVariable.mockImplementation((name: string, value: string) => {
process.env[name] = value;
});
spyInfo = jest.spyOn(core, 'info');
spyInfo.mockImplementation(() => undefined);
spyDebug = jest.spyOn(core, 'debug');
spyDebug.mockImplementation(() => undefined);
mockInfo.mockImplementation(() => undefined);
mockDebug.mockImplementation(() => undefined);
delete process.env[MAVEN_ARGS_ENV];
});
afterEach(() => {
jest.restoreAllMocks();
jest.resetAllMocks();
if (originalMavenArgs === undefined) {
delete process.env[MAVEN_ARGS_ENV];
} else {
@ -47,7 +73,7 @@ describe('configureMavenArgs', () => {
it('sets MAVEN_ARGS with -ntp by default', () => {
configureMavenArgs();
expect(spyExportVariable).toHaveBeenCalledWith(
expect(mockExportVariable).toHaveBeenCalledWith(
MAVEN_ARGS_ENV,
MAVEN_NO_TRANSFER_PROGRESS_FLAG
);
@ -59,7 +85,7 @@ describe('configureMavenArgs', () => {
configureMavenArgs();
expect(spyExportVariable).not.toHaveBeenCalled();
expect(mockExportVariable).not.toHaveBeenCalled();
expect(process.env[MAVEN_ARGS_ENV]).toBeUndefined();
});
@ -68,7 +94,7 @@ describe('configureMavenArgs', () => {
configureMavenArgs();
expect(spyExportVariable).toHaveBeenCalledWith(
expect(mockExportVariable).toHaveBeenCalledWith(
MAVEN_ARGS_ENV,
`-B -Dstyle.color=always ${MAVEN_NO_TRANSFER_PROGRESS_FLAG}`
);
@ -79,7 +105,7 @@ describe('configureMavenArgs', () => {
configureMavenArgs();
expect(spyExportVariable).not.toHaveBeenCalled();
expect(mockExportVariable).not.toHaveBeenCalled();
expect(process.env[MAVEN_ARGS_ENV]).toBe('-B -ntp');
});
@ -88,7 +114,7 @@ describe('configureMavenArgs', () => {
configureMavenArgs();
expect(spyExportVariable).not.toHaveBeenCalled();
expect(mockExportVariable).not.toHaveBeenCalled();
expect(process.env[MAVEN_ARGS_ENV]).toBe('--no-transfer-progress -B');
});
@ -98,7 +124,7 @@ describe('configureMavenArgs', () => {
configureMavenArgs();
expect(spyExportVariable).not.toHaveBeenCalled();
expect(mockExportVariable).not.toHaveBeenCalled();
expect(process.env[MAVEN_ARGS_ENV]).toBe('-B');
});
});

View File

@ -1,23 +1,63 @@
import {
jest,
describe,
it,
expect,
beforeEach,
afterEach,
beforeAll,
afterAll
} from '@jest/globals';
import {fileURLToPath} from 'url';
import * as fs from 'fs';
import os from 'os';
import * as path from 'path';
import * as core from '@actions/core';
import * as io from '@actions/io';
import * as toolchains from '../src/toolchains';
import {M2_DIR, MVN_TOOLCHAINS_FILE} from '../src/constants';
// Mock @actions/core before importing source modules that depend on it
jest.unstable_mockModule('@actions/core', () => ({
info: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
setFailed: jest.fn(),
setOutput: jest.fn(),
getInput: jest.fn(),
getBooleanInput: jest.fn(),
getMultilineInput: jest.fn(),
addPath: jest.fn(),
exportVariable: jest.fn(),
saveState: jest.fn(),
getState: jest.fn(),
setSecret: jest.fn(),
isDebug: jest.fn(() => false),
startGroup: jest.fn(),
endGroup: jest.fn(),
group: jest.fn((_name: string, fn: () => Promise<unknown>) => fn()),
toPlatformPath: jest.fn((p: string) => p),
toWin32Path: jest.fn((p: string) => p),
toPosixPath: jest.fn((p: string) => p)
}));
// Dynamic imports after mocking
const core = await import('@actions/core');
const toolchains = await import('../src/toolchains.js');
const {M2_DIR, MVN_TOOLCHAINS_FILE} = await import('../src/constants.js');
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const m2Dir = path.join(__dirname, M2_DIR);
const toolchainsFile = path.join(m2Dir, MVN_TOOLCHAINS_FILE);
describe('toolchains tests', () => {
let spyOSHomedir: jest.SpyInstance;
let spyInfo: jest.SpyInstance;
let spyOSHomedir: any;
let spyInfo: any;
beforeEach(async () => {
await io.rmRF(m2Dir);
spyOSHomedir = jest.spyOn(os, 'homedir');
spyOSHomedir.mockReturnValue(__dirname);
spyInfo = jest.spyOn(core, 'info');
spyInfo = core.info as jest.Mock;
spyInfo.mockImplementation(() => null);
}, 300000);
@ -895,6 +935,11 @@ describe('toolchains tests', () => {
const jdkHome =
'/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64';
(core.getInput as jest.Mock<any>).mockImplementation((name: string) => {
if (name === 'settings-path') return m2Dir;
return '';
});
await toolchains.configureToolchains(
version,
distributionName,

View File

@ -1,8 +1,55 @@
import * as cache from '@actions/cache';
import * as core from '@actions/core';
import {
jest,
describe,
it,
expect,
beforeEach,
afterAll,
afterEach
} from '@jest/globals';
import {fileURLToPath} from 'url';
import * as fs from 'fs';
import * as path from 'path';
import {
const __dirname = path.dirname(fileURLToPath(import.meta.url));
// Mock @actions/cache
jest.unstable_mockModule('@actions/cache', () => ({
isFeatureAvailable: jest.fn(),
saveCache: jest.fn(),
restoreCache: jest.fn()
}));
// Mock @actions/core
jest.unstable_mockModule('@actions/core', () => ({
getInput: jest.fn(),
getBooleanInput: jest.fn(),
getMultilineInput: jest.fn(),
setOutput: jest.fn(),
setFailed: jest.fn(),
warning: jest.fn(),
info: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
startGroup: jest.fn(),
endGroup: jest.fn(),
addPath: jest.fn(),
exportVariable: jest.fn(),
saveState: jest.fn(),
getState: jest.fn(),
setSecret: jest.fn(),
isDebug: jest.fn(() => false),
group: jest.fn((_name: string, fn: () => Promise<unknown>) => fn()),
toPlatformPath: jest.fn((p: string) => p),
toWin32Path: jest.fn((p: string) => p),
toPosixPath: jest.fn((p: string) => p)
}));
const cache = await import('@actions/cache');
const core = await import('@actions/core');
const {
convertVersionToSemver,
getNextPageUrlFromLinkHeader,
getVersionFromFileContent,
@ -10,10 +57,7 @@ import {
isCacheFeatureAvailable,
isGhes,
validatePaginationUrl
} from '../src/util';
jest.mock('@actions/cache');
jest.mock('@actions/core');
} = await import('../src/util.js');
describe('isVersionSatisfies', () => {
it.each([
@ -45,8 +89,10 @@ describe('isVersionSatisfies', () => {
describe('isCacheFeatureAvailable', () => {
it('isCacheFeatureAvailable disabled on GHES', () => {
jest.spyOn(cache, 'isFeatureAvailable').mockImplementation(() => false);
const infoMock = jest.spyOn(core, 'warning');
(cache.isFeatureAvailable as jest.Mock<any>).mockImplementation(
() => false
);
const infoMock = core.warning as jest.Mock;
const message =
'Caching is only supported on GHES version >= 3.5. If you are on a version >= 3.5, please check with your GHES admin if the Actions cache service is enabled or not.';
try {
@ -59,8 +105,10 @@ describe('isCacheFeatureAvailable', () => {
});
it('isCacheFeatureAvailable disabled on dotcom', () => {
jest.spyOn(cache, 'isFeatureAvailable').mockImplementation(() => false);
const infoMock = jest.spyOn(core, 'warning');
(cache.isFeatureAvailable as jest.Mock<any>).mockImplementation(
() => false
);
const infoMock = core.warning as jest.Mock;
const message =
'The runner was not able to contact the cache service. Caching will be skipped';
try {
@ -73,9 +121,14 @@ describe('isCacheFeatureAvailable', () => {
});
it('isCacheFeatureAvailable is enabled', () => {
jest.spyOn(cache, 'isFeatureAvailable').mockImplementation(() => true);
(cache.isFeatureAvailable as jest.Mock<any>).mockImplementation(() => true);
expect(isCacheFeatureAvailable()).toBe(true);
});
afterEach(() => {
jest.resetAllMocks();
jest.clearAllMocks();
});
});
describe('convertVersionToSemver', () => {
@ -249,7 +302,6 @@ describe('isGhes', () => {
const pristineEnv = process.env;
beforeEach(() => {
jest.resetModules();
process.env = {...pristineEnv};
});

118495
dist/cleanup/index.js vendored

File diff suppressed because one or more lines are too long

3
dist/cleanup/package.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"type": "module"
}

135923
dist/setup/index.js vendored

File diff suppressed because one or more lines are too long

3
dist/setup/package.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"type": "module"
}

74
eslint.config.mjs Normal file
View File

@ -0,0 +1,74 @@
// This is a reusable configuration file copied from https://github.com/actions/reusable-workflows/tree/main/reusable-configurations. Please don't make changes to this file as it's the subject of an automatic update.
import js from '@eslint/js';
import tsParser from '@typescript-eslint/parser';
import tsPlugin from '@typescript-eslint/eslint-plugin';
import jest from 'eslint-plugin-jest';
import n from 'eslint-plugin-n';
import prettier from 'eslint-config-prettier';
import globals from 'globals';
export default [
{
ignores: ['**/*', '!src/**', '!__tests__/**']
},
js.configs.recommended,
{
files: ['**/*.ts'],
languageOptions: {
parser: tsParser,
ecmaVersion: 2022,
sourceType: 'module',
globals: {
...globals.node,
...globals.es2015
}
},
plugins: {
'@typescript-eslint': tsPlugin,
n
},
rules: {
...tsPlugin.configs.recommended.rules,
'@typescript-eslint/no-require-imports': 'error',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/ban-ts-comment': [
'error',
{
'ts-ignore': 'allow-with-description'
}
],
'no-console': 'error',
yoda: 'error',
'prefer-const': [
'error',
{
destructuring: 'all'
}
],
'no-control-regex': 'off',
'no-constant-condition': ['error', {checkLoops: false}],
'no-undef': 'off',
'no-useless-assignment': 'off',
'n/no-extraneous-import': 'error'
}
},
{
files: ['**/*{test,spec}.ts'],
plugins: {jest},
languageOptions: {
globals: {
...globals.jest
}
},
rules: {
...jest.configs['flat/recommended'].rules,
'@typescript-eslint/no-unused-vars': 'off',
'jest/no-standalone-expect': 'off',
'jest/no-conditional-expect': 'off',
'no-console': 'off'
}
},
prettier
];

View File

@ -1,11 +0,0 @@
module.exports = {
clearMocks: true,
moduleFileExtensions: ['js', 'ts'],
testEnvironment: 'node',
testMatch: ['**/*.test.ts'],
testRunner: 'jest-circus/runner',
transform: {
'^.+\\.ts$': 'ts-jest'
},
verbose: true
}

24
jest.config.ts Normal file
View File

@ -0,0 +1,24 @@
export default {
clearMocks: true,
moduleFileExtensions: ['js', 'ts'],
roots: ['<rootDir>'],
testEnvironment: 'node',
testMatch: ['**/*.test.ts'],
transform: {
'^.+\\.ts$': [
'ts-jest',
{
useESM: true,
diagnostics: {
ignoreCodes: [151002]
}
}
]
},
extensionsToTreatAsEsm: ['.ts'],
transformIgnorePatterns: ['node_modules/(?!(@actions)/)'],
moduleNameMapper: {
'^(\\.{1,2}/.*)\\.js$': '$1'
},
verbose: true
}

3099
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,7 @@
{
"name": "setup-java",
"version": "5.3.0",
"version": "6.0.0",
"type": "module",
"private": true,
"description": "setup java action",
"main": "dist/setup/index.js",
@ -9,24 +10,24 @@
},
"scripts": {
"build": "ncc build -o dist/setup src/setup-java.ts && ncc build -o dist/cleanup src/cleanup-java.ts",
"format": "prettier --no-error-on-unmatched-pattern --config ./.prettierrc.js --write \"**/*.{ts,yml,yaml}\"",
"format-check": "prettier --no-error-on-unmatched-pattern --config ./.prettierrc.js --check \"**/*.{ts,yml,yaml}\"",
"lint": "eslint --config ./.eslintrc.js \"**/*.ts\"",
"lint:fix": "eslint --config ./.eslintrc.js \"**/*.ts\" --fix",
"format": "prettier --no-error-on-unmatched-pattern --write \"**/*.{ts,yml,yaml}\"",
"format-check": "prettier --no-error-on-unmatched-pattern --check \"**/*.{ts,yml,yaml}\"",
"lint": "eslint \"**/*.ts\"",
"lint:fix": "eslint \"**/*.ts\" --fix",
"check": "npm run format-check && npm run lint && npm run build && npm test",
"fix": "npm run format && npm run lint:fix && npm run build",
"prepare": "husky install",
"prerelease": "npm run-script build",
"release": "git add -f dist/setup/index.js dist/cleanup/index.js",
"test": "jest"
"test": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js --runInBand --coverage"
},
"lint-staged": {
"*.ts": [
"prettier --no-error-on-unmatched-pattern --config ./.prettierrc.js --write",
"eslint --config ./.eslintrc.js --fix"
"prettier --no-error-on-unmatched-pattern --write",
"eslint --fix"
],
"*.{yml,yaml}": [
"prettier --no-error-on-unmatched-pattern --config ./.prettierrc.js --write"
"prettier --no-error-on-unmatched-pattern --write"
]
},
"repository": {
@ -41,34 +42,35 @@
"author": "GitHub",
"license": "MIT",
"dependencies": {
"@actions/cache": "^5.1.0",
"@actions/core": "^2.0.3",
"@actions/exec": "^2.0.0",
"@actions/glob": "^0.5.1",
"@actions/http-client": "^3.0.2",
"@actions/io": "^2.0.0",
"@actions/tool-cache": "^3.0.1",
"semver": "^7.6.0",
"@actions/cache": "^6.1.0",
"@actions/core": "^3.0.1",
"@actions/exec": "^3.0.0",
"@actions/glob": "^0.7.0",
"@actions/http-client": "^4.0.1",
"@actions/io": "^3.0.2",
"@actions/tool-cache": "^4.0.0",
"semver": "^7.8.5",
"xmlbuilder2": "^4.0.3"
},
"devDependencies": {
"@types/jest": "^30.0.0",
"@eslint/js": "^10.0.1",
"@jest/globals": "^30.4.1",
"@types/node": "^26.0.0",
"@types/semver": "^7.5.8",
"@typescript-eslint/eslint-plugin": "^8.48.0",
"@types/semver": "^7.7.0",
"@typescript-eslint/eslint-plugin": "^8.62.0",
"@typescript-eslint/parser": "^8.62.0",
"@vercel/ncc": "^0.44.0",
"eslint": "^8.57.0",
"eslint": "^10.5.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-jest": "^29.15.4",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-n": "^18.1.0",
"globals": "^17.7.0",
"husky": "^9.1.7",
"jest": "^30.4.2",
"jest-circus": "^30.4.2",
"lint-staged": "^17.0.8",
"prettier": "^3.9.1",
"ts-jest": "^29.4.11",
"typescript": "^5.3.3"
"typescript": "^6.0.3"
},
"bugs": {
"url": "https://github.com/actions/setup-java/issues"

View File

@ -6,9 +6,9 @@ import * as fs from 'fs';
import * as os from 'os';
import {create as xmlCreate} from 'xmlbuilder2';
import * as constants from './constants';
import * as gpg from './gpg';
import {getBooleanInput} from './util';
import * as constants from './constants.js';
import * as gpg from './gpg.js';
import {getBooleanInput} from './util.js';
export async function configureAuthentication() {
const id = core.getInput(constants.INPUT_SERVER_ID);

View File

@ -1,8 +1,9 @@
import * as core from '@actions/core';
import * as gpg from './gpg';
import * as constants from './constants';
import {isJobStatusSuccess} from './util';
import {save} from './cache';
import * as gpg from './gpg.js';
import * as constants from './constants.js';
import {isJobStatusSuccess} from './util.js';
import {save} from './cache.js';
import {fileURLToPath} from 'url';
async function removePrivateKeyFromKeychain() {
if (core.getInput(constants.INPUT_GPG_PRIVATE_KEY, {required: false})) {
@ -52,7 +53,7 @@ export async function run() {
await ignoreError(saveCache());
}
if (require.main === module) {
if (process.argv[1] === fileURLToPath(import.meta.url)) {
run();
} else {
// https://nodejs.org/api/modules.html#modules_accessing_the_main_module

View File

@ -5,13 +5,13 @@ import fs from 'fs';
import path from 'path';
import semver from 'semver';
import {JavaBase} from '../base-installer';
import {IAdoptAvailableVersions} from './models';
import {JavaBase} from '../base-installer.js';
import {IAdoptAvailableVersions} from './models.js';
import {
JavaDownloadRelease,
JavaInstallerOptions,
JavaInstallerResults
} from '../base-models';
} from '../base-models.js';
import {
extractJdkFile,
getNextPageUrlFromLinkHeader,
@ -20,8 +20,11 @@ import {
renameWinArchive,
MAX_PAGINATION_PAGES,
validatePaginationUrl
} from '../../util';
import {TemurinDistribution, TemurinImplementation} from '../temurin/installer';
} from '../../util.js';
import {
TemurinDistribution,
TemurinImplementation
} from '../temurin/installer.js';
export enum AdoptImplementation {
Hotspot = 'Hotspot',

View File

@ -4,13 +4,13 @@ import * as fs from 'fs';
import semver from 'semver';
import path from 'path';
import * as httpm from '@actions/http-client';
import {getToolcachePath, isVersionSatisfies} from '../util';
import {getToolcachePath, isVersionSatisfies} from '../util.js';
import {
JavaDownloadRelease,
JavaInstallerOptions,
JavaInstallerResults
} from './base-models';
import {MACOS_JAVA_CONTENT_POSTFIX} from '../constants';
} from './base-models.js';
import {MACOS_JAVA_CONTENT_POSTFIX} from '../constants.js';
import os from 'os';
export abstract class JavaBase {

View File

@ -7,17 +7,17 @@ import {
getDownloadArchiveExtension,
convertVersionToSemver,
renameWinArchive
} from '../../util';
import {JavaBase} from '../base-installer';
} from '../../util.js';
import {JavaBase} from '../base-installer.js';
import {
JavaDownloadRelease,
JavaInstallerOptions,
JavaInstallerResults
} from '../base-models';
} from '../base-models.js';
import {
ICorrettoAllAvailableVersions,
ICorrettoAvailableVersions
} from './models';
} from './models.js';
export class CorrettoDistribution extends JavaBase {
constructor(installerOptions: JavaInstallerOptions) {

View File

@ -1,22 +1,25 @@
import {JavaBase} from './base-installer';
import {JavaInstallerOptions} from './base-models';
import {LocalDistribution} from './local/installer';
import {ZuluDistribution} from './zulu/installer';
import {AdoptDistribution, AdoptImplementation} from './adopt/installer';
import {TemurinDistribution, TemurinImplementation} from './temurin/installer';
import {LibericaDistributions} from './liberica/installer';
import {MicrosoftDistributions} from './microsoft/installer';
import {SemeruDistribution} from './semeru/installer';
import {CorrettoDistribution} from './corretto/installer';
import {OracleDistribution} from './oracle/installer';
import {DragonwellDistribution} from './dragonwell/installer';
import {SapMachineDistribution} from './sapmachine/installer';
import {JavaBase} from './base-installer.js';
import {JavaInstallerOptions} from './base-models.js';
import {LocalDistribution} from './local/installer.js';
import {ZuluDistribution} from './zulu/installer.js';
import {AdoptDistribution, AdoptImplementation} from './adopt/installer.js';
import {
TemurinDistribution,
TemurinImplementation
} from './temurin/installer.js';
import {LibericaDistributions} from './liberica/installer.js';
import {MicrosoftDistributions} from './microsoft/installer.js';
import {SemeruDistribution} from './semeru/installer.js';
import {CorrettoDistribution} from './corretto/installer.js';
import {OracleDistribution} from './oracle/installer.js';
import {DragonwellDistribution} from './dragonwell/installer.js';
import {SapMachineDistribution} from './sapmachine/installer.js';
import {
GraalVMCommunityDistribution,
GraalVMDistribution
} from './graalvm/installer';
import {JetBrainsDistribution} from './jetbrains/installer';
import {KonaDistribution} from './kona/installer';
} from './graalvm/installer.js';
import {JetBrainsDistribution} from './jetbrains/installer.js';
import {KonaDistribution} from './kona/installer.js';
enum JavaDistribution {
Adopt = 'adopt',

View File

@ -5,7 +5,7 @@ import semver from 'semver';
import fs from 'fs';
import path from 'path';
import {JavaBase} from '../base-installer';
import {JavaBase} from '../base-installer.js';
import {
convertVersionToSemver,
extractJdkFile,
@ -13,13 +13,13 @@ import {
getGitHubHttpHeaders,
isVersionSatisfies,
renameWinArchive
} from '../../util';
import {IDragonwellVersions, IDragonwellAllVersions} from './models';
} from '../../util.js';
import {IDragonwellVersions, IDragonwellAllVersions} from './models.js';
import {
JavaDownloadRelease,
JavaInstallerOptions,
JavaInstallerResults
} from '../base-models';
} from '../base-models.js';
export class DragonwellDistribution extends JavaBase {
constructor(installerOptions: JavaInstallerOptions) {

View File

@ -3,14 +3,14 @@ import * as tc from '@actions/tool-cache';
import fs from 'fs';
import path from 'path';
import semver from 'semver';
import {JavaBase} from '../base-installer';
import {JavaBase} from '../base-installer.js';
import {HttpCodes} from '@actions/http-client';
import {GraalVMEAVersion} from './models';
import {GraalVMEAVersion} from './models.js';
import {
JavaDownloadRelease,
JavaInstallerOptions,
JavaInstallerResults
} from '../base-models';
} from '../base-models.js';
import {
convertVersionToSemver,
extractJdkFile,
@ -21,7 +21,7 @@ import {
MAX_PAGINATION_PAGES,
renameWinArchive,
validatePaginationUrl
} from '../../util';
} from '../../util.js';
const GRAALVM_DL_BASE = 'https://download.oracle.com/graalvm';
const GRAALVM_DOWNLOAD_URL = 'https://www.graalvm.org/downloads/';
@ -300,17 +300,20 @@ export class GraalVMDistribution extends JavaBase {
// Check if it's a 404 error (file not found)
if (error.message?.includes('404')) {
throw new Error(
`GraalVM EA version '${javaEaVersion}' not found. Please verify the version exists in the EA builds repository.`
`GraalVM EA version '${javaEaVersion}' not found. Please verify the version exists in the EA builds repository.`,
{cause: error}
);
}
// Re-throw with more context
throw new Error(
`Failed to fetch GraalVM EA version information for '${javaEaVersion}': ${error.message}`
`Failed to fetch GraalVM EA version information for '${javaEaVersion}': ${error.message}`,
{cause: error}
);
}
// If it's not an Error instance, throw a generic error
throw new Error(
`Failed to fetch GraalVM EA version information for '${javaEaVersion}'`
`Failed to fetch GraalVM EA version information for '${javaEaVersion}'`,
{cause: error}
);
}
}

View File

@ -5,14 +5,14 @@ import fs from 'fs';
import path from 'path';
import semver from 'semver';
import {JavaBase} from '../base-installer';
import {IJetBrainsRawVersion, IJetBrainsVersion} from './models';
import {JavaBase} from '../base-installer.js';
import {IJetBrainsRawVersion, IJetBrainsVersion} from './models.js';
import {
JavaDownloadRelease,
JavaInstallerOptions,
JavaInstallerResults
} from '../base-models';
import {extractJdkFile, isVersionSatisfies} from '../../util';
} from '../base-models.js';
import {extractJdkFile, isVersionSatisfies} from '../../util.js';
import {OutgoingHttpHeaders} from 'http';
import {HttpCodes} from '@actions/http-client';

View File

@ -5,19 +5,19 @@ import semver from 'semver';
import fs from 'fs';
import path from 'path';
import {JavaBase} from '../base-installer';
import {IKonaReleaseInfo, IKonaRelease} from './models';
import {JavaBase} from '../base-installer.js';
import {IKonaReleaseInfo, IKonaRelease} from './models.js';
import {
JavaDownloadRelease,
JavaInstallerOptions,
JavaInstallerResults
} from '../base-models';
} from '../base-models.js';
import {
extractJdkFile,
getDownloadArchiveExtension,
isVersionSatisfies,
renameWinArchive
} from '../../util';
} from '../../util.js';
export class KonaDistribution extends JavaBase {
constructor(installerOptions: JavaInstallerOptions) {

View File

@ -1,18 +1,18 @@
import {JavaBase} from '../base-installer';
import {JavaBase} from '../base-installer.js';
import {
JavaDownloadRelease,
JavaInstallerOptions,
JavaInstallerResults
} from '../base-models';
} from '../base-models.js';
import semver from 'semver';
import {
extractJdkFile,
getDownloadArchiveExtension,
isVersionSatisfies,
renameWinArchive
} from '../../util';
} from '../../util.js';
import * as core from '@actions/core';
import {ArchitectureOptions, LibericaVersion, OsVersions} from './models';
import {ArchitectureOptions, LibericaVersion, OsVersions} from './models.js';
import * as tc from '@actions/tool-cache';
import fs from 'fs';
import path from 'path';

View File

@ -4,14 +4,14 @@ import * as core from '@actions/core';
import fs from 'fs';
import path from 'path';
import {JavaBase} from '../base-installer';
import {JavaBase} from '../base-installer.js';
import {
JavaInstallerOptions,
JavaDownloadRelease,
JavaInstallerResults
} from '../base-models';
import {extractJdkFile} from '../../util';
import {MACOS_JAVA_CONTENT_POSTFIX} from '../../constants';
} from '../base-models.js';
import {extractJdkFile} from '../../util.js';
import {MACOS_JAVA_CONTENT_POSTFIX} from '../../constants.js';
export class LocalDistribution extends JavaBase {
constructor(

View File

@ -1,24 +1,24 @@
import {JavaBase} from '../base-installer';
import {JavaBase} from '../base-installer.js';
import {
JavaDownloadRelease,
JavaInstallerOptions,
JavaInstallerResults
} from '../base-models';
} from '../base-models.js';
import {
extractJdkFile,
getDownloadArchiveExtension,
getGitHubHttpHeaders,
renameWinArchive
} from '../../util';
import * as gpg from '../../gpg';
import {MICROSOFT_PUBLIC_KEY} from './microsoft-key';
} from '../../util.js';
import * as gpg from '../../gpg.js';
import {MICROSOFT_PUBLIC_KEY} from './microsoft-key.js';
import * as core from '@actions/core';
import * as tc from '@actions/tool-cache';
import fs from 'fs';
import path from 'path';
import {TypedResponse} from '@actions/http-client/lib/interfaces';
export {MICROSOFT_PUBLIC_KEY} from './microsoft-key';
export {MICROSOFT_PUBLIC_KEY} from './microsoft-key.js';
export class MicrosoftDistributions extends JavaBase {
constructor(installerOptions: JavaInstallerOptions) {
@ -48,7 +48,8 @@ export class MicrosoftDistributions extends JavaBase {
);
} catch (error) {
throw new Error(
`Failed to verify signature for Microsoft Build of OpenJDK version ${javaRelease.version}. Signature URL: ${javaRelease.signatureUrl}. Error: ${(error as Error).message}`
`Failed to verify signature for Microsoft Build of OpenJDK version ${javaRelease.version}. Signature URL: ${javaRelease.signatureUrl}. Error: ${(error as Error).message}`,
{cause: error}
);
}
}

View File

@ -4,18 +4,19 @@ import * as tc from '@actions/tool-cache';
import fs from 'fs';
import path from 'path';
import {JavaBase} from '../base-installer';
import {JavaBase} from '../base-installer.js';
import {
JavaDownloadRelease,
JavaInstallerOptions,
JavaInstallerResults
} from '../base-models';
} from '../base-models.js';
import {
extractJdkFile,
getDownloadArchiveExtension,
renameWinArchive
} from '../../util';
} from '../../util.js';
import {HttpCodes} from '@actions/http-client';
import {OsVersions} from './models.js';
const ORACLE_DL_BASE = 'https://download.oracle.com/java';

View File

@ -10,14 +10,14 @@ import {
getDownloadArchiveExtension,
isVersionSatisfies,
renameWinArchive
} from '../../util';
import {JavaBase} from '../base-installer';
} from '../../util.js';
import {JavaBase} from '../base-installer.js';
import {
JavaDownloadRelease,
JavaInstallerOptions,
JavaInstallerResults
} from '../base-models';
import {ISapMachineAllVersions, ISapMachineVersions} from './models';
} from '../base-models.js';
import {ISapMachineAllVersions, ISapMachineVersions} from './models.js';
export class SapMachineDistribution extends JavaBase {
constructor(installerOptions: JavaInstallerOptions) {

View File

@ -1,9 +1,9 @@
import {JavaBase} from '../base-installer';
import {JavaBase} from '../base-installer.js';
import {
JavaDownloadRelease,
JavaInstallerOptions,
JavaInstallerResults
} from '../base-models';
} from '../base-models.js';
import semver from 'semver';
import {
extractJdkFile,
@ -13,12 +13,12 @@ import {
renameWinArchive,
MAX_PAGINATION_PAGES,
validatePaginationUrl
} from '../../util';
} from '../../util.js';
import * as core from '@actions/core';
import * as tc from '@actions/tool-cache';
import fs from 'fs';
import path from 'path';
import {ISemeruAvailableVersions} from './models';
import {ISemeruAvailableVersions} from './models.js';
const supportedArchitectures = [
'x64',

View File

@ -4,16 +4,16 @@ import * as tc from '@actions/tool-cache';
import fs from 'fs';
import path from 'path';
import semver from 'semver';
import * as gpg from '../../gpg';
import * as gpg from '../../gpg.js';
import {ADOPTIUM_PUBLIC_KEY} from './adoptium-key';
import {JavaBase} from '../base-installer';
import {ITemurinAvailableVersions} from './models';
import {ADOPTIUM_PUBLIC_KEY} from './adoptium-key.js';
import {JavaBase} from '../base-installer.js';
import {ITemurinAvailableVersions} from './models.js';
import {
JavaDownloadRelease,
JavaInstallerOptions,
JavaInstallerResults
} from '../base-models';
} from '../base-models.js';
import {
extractJdkFile,
getNextPageUrlFromLinkHeader,
@ -22,9 +22,9 @@ import {
renameWinArchive,
MAX_PAGINATION_PAGES,
validatePaginationUrl
} from '../../util';
} from '../../util.js';
export {ADOPTIUM_PUBLIC_KEY} from './adoptium-key';
export {ADOPTIUM_PUBLIC_KEY} from './adoptium-key.js';
export enum TemurinImplementation {
Hotspot = 'Hotspot'
@ -102,7 +102,8 @@ export class TemurinDistribution extends JavaBase {
throw new Error(
`Failed to verify signature for Temurin version ${javaRelease.version} from ${javaRelease.signatureUrl}: ${
(error as Error).message
}`
}`,
{cause: error}
);
}
}

View File

@ -5,20 +5,20 @@ import path from 'path';
import fs from 'fs';
import semver from 'semver';
import {JavaBase} from '../base-installer';
import {IZuluVersions} from './models';
import {JavaBase} from '../base-installer.js';
import {IZuluVersions} from './models.js';
import {
extractJdkFile,
getDownloadArchiveExtension,
convertVersionToSemver,
isVersionSatisfies,
renameWinArchive
} from '../../util';
} from '../../util.js';
import {
JavaDownloadRelease,
JavaInstallerOptions,
JavaInstallerResults
} from '../base-models';
} from '../base-models.js';
export class ZuluDistribution extends JavaBase {
constructor(installerOptions: JavaInstallerOptions) {

View File

@ -3,8 +3,8 @@ import * as path from 'path';
import * as io from '@actions/io';
import * as exec from '@actions/exec';
import * as tc from '@actions/tool-cache';
import * as util from './util';
import {ExecOptions} from '@actions/exec/lib/interfaces';
import * as util from './util.js';
import {ExecOptions} from '@actions/exec';
export const PRIVATE_KEY_FILE = path.join(util.getTempDir(), 'private-key.asc');
@ -86,7 +86,8 @@ export async function verifyPackageSignature(
throw new Error(
`Failed to create temporary GPG home directory for signature verification: ${
(error as Error).message
}`
}`,
{cause: error}
);
}
try {

View File

@ -1,11 +1,11 @@
import * as core from '@actions/core';
import {getBooleanInput} from './util';
import {getBooleanInput} from './util.js';
import {
INPUT_SHOW_DOWNLOAD_PROGRESS,
MAVEN_ARGS_ENV,
MAVEN_NO_TRANSFER_PROGRESS_FLAG,
MAVEN_NO_TRANSFER_PROGRESS_LONG_FLAG
} from './constants';
} from './constants.js';
/**
* Configures the MAVEN_ARGS environment variable so that Maven suppresses

View File

@ -1,18 +1,19 @@
import fs from 'fs';
import * as core from '@actions/core';
import * as auth from './auth';
import * as auth from './auth.js';
import {
getBooleanInput,
isCacheFeatureAvailable,
getVersionFromFileContent
} from './util';
import * as toolchains from './toolchains';
import * as constants from './constants';
import {restore} from './cache';
} from './util.js';
import * as toolchains from './toolchains.js';
import * as constants from './constants.js';
import {restore} from './cache.js';
import * as path from 'path';
import {getJavaDistribution} from './distributions/distribution-factory';
import {JavaInstallerOptions} from './distributions/base-models';
import {configureMavenArgs} from './maven-args';
import {fileURLToPath} from 'url';
import {getJavaDistribution} from './distributions/distribution-factory.js';
import {JavaInstallerOptions} from './distributions/base-models.js';
import {configureMavenArgs} from './maven-args.js';
async function run() {
try {
@ -113,7 +114,12 @@ async function run() {
}
}
core.endGroup();
const matchersPath = path.join(__dirname, '..', '..', '.github');
const matchersPath = path.join(
path.dirname(fileURLToPath(import.meta.url)),
'..',
'..',
'.github'
);
core.info(`##[add-matcher]${path.join(matchersPath, 'java.json')}`);
await auth.configureAuthentication();

View File

@ -3,9 +3,9 @@ import * as os from 'os';
import * as path from 'path';
import * as core from '@actions/core';
import * as io from '@actions/io';
import * as constants from './constants';
import * as constants from './constants.js';
import {getBooleanInput} from './util';
import {getBooleanInput} from './util.js';
import {create as xmlCreate} from 'xmlbuilder2';
interface JdkInfo {

View File

@ -6,7 +6,10 @@ import * as cache from '@actions/cache';
import * as core from '@actions/core';
import * as tc from '@actions/tool-cache';
import {INPUT_JOB_STATUS, DISTRIBUTIONS_ONLY_MAJOR_VERSION} from './constants';
import {
INPUT_JOB_STATUS,
DISTRIBUTIONS_ONLY_MAJOR_VERSION
} from './constants.js';
import {OutgoingHttpHeaders} from 'http';
export function getTempDir() {

View File

@ -2,8 +2,8 @@
"compilerOptions": {
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"target": "ES2022", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
"module": "NodeNext", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
"resolveJsonModule": true,
@ -61,5 +61,5 @@
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
},
"exclude": ["node_modules", "**/*.test.ts"]
"exclude": ["node_modules", "**/*.test.ts", "jest.config.ts"]
}