Migrate to ESM and upgrade dependencies

This commit is contained in:
priyagupta108 2026-06-26 10:36:45 +05:30
parent 924ae3a1cd
commit 7999c2b071
59 changed files with 125164 additions and 112480 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,7 +10,10 @@ allowed:
- cc0-1.0
- unlicense
- 0bsd
- blueoak-1.0.0
reviewed:
npm:
- "@actions/http-client"
- "@actions/http-client"
- "balanced-match"
- "brace-expansion"

View file

@ -1,6 +1,6 @@
---
name: "@actions/cache"
version: 5.1.0
version: 6.1.0
type: npm
summary: Actions cache lib
homepage: https://github.com/actions/toolkit/tree/main/packages/cache

View file

@ -1,6 +1,6 @@
---
name: "@actions/core"
version: 2.0.3
version: 3.0.1
type: npm
summary: Actions core lib
homepage: https://github.com/actions/toolkit/tree/main/packages/core

View file

@ -1,6 +1,6 @@
---
name: "@actions/exec"
version: 2.0.0
version: 3.0.0
type: npm
summary: Actions exec lib
homepage: https://github.com/actions/toolkit/tree/main/packages/exec

View file

@ -1,6 +1,6 @@
---
name: "@actions/glob"
version: 0.5.1
version: 0.6.1
type: npm
summary: Actions glob lib
homepage: https://github.com/actions/toolkit/tree/main/packages/glob

View file

@ -0,0 +1,20 @@
---
name: "@actions/glob"
version: 0.7.0
type: npm
summary: Actions glob lib
homepage: https://github.com/actions/toolkit/tree/main/packages/glob
license: mit
licenses:
- sources: LICENSE.md
text: |-
The MIT License (MIT)
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
notices: []

View file

@ -1,6 +1,6 @@
---
name: "@actions/http-client"
version: 3.0.2
version: 4.0.1
type: npm
summary: Actions Http Client
homepage: https://github.com/actions/toolkit/tree/main/packages/http-client

View file

@ -1,6 +1,6 @@
---
name: "@actions/io"
version: 2.0.0
version: 3.0.2
type: npm
summary: Actions io lib
homepage: https://github.com/actions/toolkit/tree/main/packages/io

View file

@ -1,6 +1,6 @@
---
name: "@actions/tool-cache"
version: 3.0.1
version: 4.0.0
type: npm
summary: Actions tool-cache lib
homepage: https://github.com/actions/toolkit/tree/main/packages/tool-cache

View file

@ -1,6 +1,6 @@
---
name: "@azure/core-client"
version: 1.10.1
version: 1.10.2
type: npm
summary: Core library for interfacing with AutoRest generated code
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-client/

View file

@ -1,6 +1,6 @@
---
name: "@azure/core-http-compat"
version: 2.3.1
version: 2.4.0
type: npm
summary: Core HTTP Compatibility Library to bridge the gap between Core V1 & V2 packages.
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-compat/

View file

@ -1,9 +1,9 @@
---
name: "@azure/core-rest-pipeline"
version: 1.22.2
version: 1.24.0
type: npm
summary: Isomorphic client library for making HTTP requests in node.js and browser.
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-rest-pipeline/
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/core-rest-pipeline/README.md
license: mit
licenses:
- sources: LICENSE

View file

@ -1,6 +1,6 @@
---
name: "@azure/core-xml"
version: 1.5.0
version: 1.5.1
type: npm
summary: Core library for interacting with XML payloads
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-xml/

View file

@ -1,9 +1,9 @@
---
name: "@azure/storage-blob"
version: 12.29.1
version: 12.32.0
type: npm
summary: Microsoft Azure Storage SDK for JavaScript - Blob
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/storage/storage-blob/
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/storage/storage-blob/README.md
license: mit
licenses:
- sources: LICENSE

View file

@ -1,9 +1,9 @@
---
name: "@azure/storage-common"
version: 12.1.1
version: 12.4.0
type: npm
summary: Azure Storage Common Client Library for JavaScript
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/storage/storage-internal-avro/
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/storage/storage-common/README.md
license: mit
licenses:
- sources: LICENSE

View file

@ -1,9 +1,9 @@
---
name: "@typespec/ts-http-runtime"
version: 0.3.2
version: 0.3.6
type: npm
summary: Isomorphic client library for making HTTP requests in node.js and browser.
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/ts-http-runtime/
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/ts-http-runtime/README.md
license: mit
licenses:
- sources: LICENSE

View file

@ -1,6 +1,6 @@
---
name: anynum
version: 1.0.0
version: 1.0.1
type: npm
summary: Normalize all Unicode decimal digits (Devanagari, Arabic, Thai, etc.) to
ASCII numerals. Zero dependencies, performance-first.

View file

@ -0,0 +1,34 @@
---
name: balanced-match
version: 4.0.4
type: npm
summary: Match balanced character pairs, like "{" and "}"
homepage:
license: other
licenses:
- sources: LICENSE.md
text: |
(MIT)
Original code Copyright Julian Gruber <julian@juliangruber.com>
Port to TypeScript Copyright Isaac Z. Schlueter <i@izs.me>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
notices: []

View file

@ -1,6 +1,6 @@
---
name: brace-expansion
version: 1.1.13
version: 1.1.15
type: npm
summary: Brace expansion as known from sh/bash
homepage: https://github.com/juliangruber/brace-expansion

View file

@ -0,0 +1,34 @@
---
name: brace-expansion
version: 5.0.6
type: npm
summary: Brace expansion as known from sh/bash
homepage:
license: other
licenses:
- sources: LICENSE
text: |
MIT License
Copyright Julian Gruber <julian@juliangruber.com>
TypeScript port Copyright Isaac Z. Schlueter <i@izs.me>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
notices: []

View file

@ -1,6 +1,6 @@
---
name: fast-xml-parser
version: 5.8.0
version: 5.9.3
type: npm
summary: Validate XML, Parse XML, Build XML without C/C++ based libraries
homepage:

View file

@ -1,16 +1,17 @@
---
name: "@azure/abort-controller"
version: 1.1.0
name: is-unsafe
version: 1.0.1
type: npm
summary: Microsoft Azure SDK for JavaScript - Aborter
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/abort-controller/README.md
summary: Zero-dependency, DOM-free, pure predicate for detecting unsafe strings across
HTML, XML, SVG, SQL, SHELL, and REGEX contexts
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
The MIT License (MIT)
MIT License
Copyright (c) 2020 Microsoft
Copyright (c) 2026 Natural Intelligence
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -29,4 +30,6 @@ licenses:
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
- sources: README.md
text: MIT
notices: []

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

@ -0,0 +1,66 @@
---
name: minimatch
version: 10.2.5
type: npm
summary: a glob matcher in javascript
homepage:
license: blueoak-1.0.0
licenses:
- sources: LICENSE.md
text: |
# Blue Oak Model License
Version 1.0.0
## Purpose
This license gives everyone as much permission to work with
this software as possible, while protecting contributors
from liability.
## Acceptance
In order to receive this license, you must agree to its
rules. The rules of this license are both obligations
under that agreement and conditions to your license.
You must not do anything with this software that triggers
a rule that you cannot or will not follow.
## Copyright
Each contributor licenses you to do everything with this
software that would otherwise infringe that contributor's
copyright in it.
## Notices
You must ensure that everyone who gets a copy of
any part of this software from you, with or without
changes, also gets the text of this license or a link to
<https://blueoakcouncil.org/license/1.0.0>.
## Excuse
If anyone notifies you in writing that you have not
complied with [Notices](#notices), you can keep your
license by taking all practical steps to comply within 30
days after the notice. If you do not do so, your license
ends immediately.
## Patent
Each contributor licenses you to do everything with this
software that would otherwise infringe any patent claims
they can license or become able to license.
## Reliability
No contributor can revoke this license.
## No Liability
**_As far as the law allows, this software comes as is,
without any warranty or condition, and no contributor
will be liable to anyone for any damages related to this
software or this license, under any kind of legal claim._**
notices: []

View file

@ -1,6 +1,6 @@
---
name: path-expression-matcher
version: 1.5.0
version: 1.6.0
type: npm
summary: Efficient path tracking and pattern matching for XML/JSON parsers
homepage: https://github.com/NaturalIntelligence/path-expression-matcher#readme

View file

@ -1,26 +0,0 @@
---
name: semver
version: 6.3.1
type: npm
summary: The semantic version parser used by npm.
homepage:
license: isc
licenses:
- sources: LICENSE
text: |
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
notices: []

View file

@ -1,6 +1,6 @@
---
name: strnum
version: 2.4.0
version: 2.4.1
type: npm
summary: Parse String to Number based on configuration
homepage:

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

@ -1,18 +1,65 @@
import * as cache from '@actions/cache';
import * as core from '@actions/core';
import * as glob from '@actions/glob';
import {jest, describe, it, expect, beforeEach, afterEach} from '@jest/globals';
import fs from 'fs';
import * as cacheRestore from '../src/cache-restore';
import * as cacheUtils from '../src/cache-utils';
import {PackageManagerInfo} from '../src/package-managers';
jest.unstable_mockModule('@actions/cache', () => ({
saveCache: jest.fn(),
restoreCache: jest.fn(),
isFeatureAvailable: jest.fn()
}));
jest.unstable_mockModule('@actions/glob', () => ({
create: jest.fn(),
hashFiles: jest.fn()
}));
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)
}));
// Import real cache-utils (with mocked @actions) before mocking it
const realCacheUtils = await import('../src/cache-utils.js');
jest.unstable_mockModule('../src/cache-utils.js', () => ({
...realCacheUtils,
getCacheDirectoryPath: jest.fn()
}));
const cache = await import('@actions/cache');
const core = await import('@actions/core');
const glob = await import('@actions/glob');
const cacheRestore = await import('../src/cache-restore.js');
const cacheUtils = await import('../src/cache-utils.js');
import type {PackageManagerInfo} from '../src/package-managers.js';
describe('restoreCache', () => {
let hashFilesSpy: jest.SpyInstance;
let getCacheDirectoryPathSpy: jest.SpyInstance;
let restoreCacheSpy: jest.SpyInstance;
let infoSpy: jest.SpyInstance;
let setOutputSpy: jest.SpyInstance;
let hashFilesSpy: jest.Mock<typeof glob.hashFiles>;
let getCacheDirectoryPathSpy: jest.Mock<
typeof cacheUtils.getCacheDirectoryPath
>;
let restoreCacheSpy: jest.Mock<typeof cache.restoreCache>;
let infoSpy: jest.Mock<typeof core.info>;
let setOutputSpy: jest.Mock<typeof core.setOutput>;
const versionSpec = '1.13.1';
const packageManager = 'default';
@ -24,11 +71,15 @@ describe('restoreCache', () => {
originalWorkspace = process.env.GITHUB_WORKSPACE;
process.env.GITHUB_WORKSPACE = '/test/workspace';
//Arrange
hashFilesSpy = jest.spyOn(glob, 'hashFiles');
getCacheDirectoryPathSpy = jest.spyOn(cacheUtils, 'getCacheDirectoryPath');
restoreCacheSpy = jest.spyOn(cache, 'restoreCache');
infoSpy = jest.spyOn(core, 'info');
setOutputSpy = jest.spyOn(core, 'setOutput');
hashFilesSpy = glob.hashFiles as jest.Mock<typeof glob.hashFiles>;
getCacheDirectoryPathSpy = cacheUtils.getCacheDirectoryPath as jest.Mock<
typeof cacheUtils.getCacheDirectoryPath
>;
restoreCacheSpy = cache.restoreCache as jest.Mock<
typeof cache.restoreCache
>;
infoSpy = core.info as jest.Mock<typeof core.info>;
setOutputSpy = core.setOutput as jest.Mock<typeof core.setOutput>;
getCacheDirectoryPathSpy.mockImplementation(
(PackageManager: PackageManagerInfo) => {

View file

@ -1,10 +1,41 @@
import * as cache from '@actions/cache';
import * as core from '@actions/core';
import fs from 'fs';
import {jest, describe, it, expect, beforeEach, afterEach} from '@jest/globals';
import {run} from '../src/cache-save';
import * as cacheUtils from '../src/cache-utils';
import {State} from '../src/constants';
jest.unstable_mockModule('@actions/cache', () => ({
saveCache: jest.fn(),
restoreCache: jest.fn(),
isFeatureAvailable: jest.fn()
}));
jest.unstable_mockModule('@actions/core', () => ({
info: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
setFailed: jest.fn(),
getInput: jest.fn(),
getBooleanInput: jest.fn(),
getState: jest.fn(),
saveState: jest.fn()
}));
const realFs = (await import('fs')).default;
const fsExports = {...realFs, existsSync: jest.fn()};
jest.unstable_mockModule('fs', () => ({...fsExports, default: fsExports}));
// Import real cache-utils (with mocked @actions) before mocking it
const realCacheUtils = await import('../src/cache-utils.js');
jest.unstable_mockModule('../src/cache-utils.js', () => ({
...realCacheUtils,
getCacheDirectoryPath: jest.fn()
}));
const cache = await import('@actions/cache');
const core = await import('@actions/core');
const fs = (await import('fs')).default;
const cacheUtils = await import('../src/cache-utils.js');
const {run} = await import('../src/cache-save.js');
const {State} = await import('../src/constants.js');
describe('cache-save', () => {
const primaryKey = 'primary-key';
@ -12,24 +43,28 @@ describe('cache-save', () => {
let primaryKeyValue: string;
let matchedKeyValue: string;
let getBooleanInputSpy: jest.SpyInstance;
let getStateSpy: jest.SpyInstance;
let infoSpy: jest.SpyInstance;
let warningSpy: jest.SpyInstance;
let debugSpy: jest.SpyInstance;
let setFailedSpy: jest.SpyInstance;
let saveCacheSpy: jest.SpyInstance;
let getCacheDirectoryPathSpy: jest.SpyInstance;
let existsSpy: jest.SpyInstance;
let getBooleanInputSpy: jest.Mock<typeof core.getBooleanInput>;
let getStateSpy: jest.Mock<typeof core.getState>;
let infoSpy: jest.Mock<typeof core.info>;
let warningSpy: jest.Mock<typeof core.warning>;
let debugSpy: jest.Mock<typeof core.debug>;
let setFailedSpy: jest.Mock<typeof core.setFailed>;
let saveCacheSpy: jest.Mock<typeof cache.saveCache>;
let getCacheDirectoryPathSpy: jest.Mock<
typeof cacheUtils.getCacheDirectoryPath
>;
let existsSpy: jest.Mock<typeof fs.existsSync>;
beforeEach(() => {
primaryKeyValue = primaryKey;
matchedKeyValue = 'matched-key';
getBooleanInputSpy = jest.spyOn(core, 'getBooleanInput');
getBooleanInputSpy = core.getBooleanInput as jest.Mock<
typeof core.getBooleanInput
>;
getBooleanInputSpy.mockReturnValue(true);
getStateSpy = jest.spyOn(core, 'getState');
getStateSpy = core.getState as jest.Mock<typeof core.getState>;
getStateSpy.mockImplementation((key: string) => {
if (key === State.CachePrimaryKey) {
return primaryKeyValue;
@ -40,32 +75,34 @@ describe('cache-save', () => {
return '';
});
infoSpy = jest.spyOn(core, 'info');
infoSpy = core.info as jest.Mock<typeof core.info>;
infoSpy.mockImplementation(() => undefined);
warningSpy = jest.spyOn(core, 'warning');
warningSpy = core.warning as jest.Mock<typeof core.warning>;
warningSpy.mockImplementation(() => undefined);
debugSpy = jest.spyOn(core, 'debug');
debugSpy = core.debug as jest.Mock<typeof core.debug>;
debugSpy.mockImplementation(() => undefined);
setFailedSpy = jest.spyOn(core, 'setFailed');
setFailedSpy = core.setFailed as jest.Mock<typeof core.setFailed>;
setFailedSpy.mockImplementation(() => undefined);
saveCacheSpy = jest.spyOn(cache, 'saveCache');
saveCacheSpy = cache.saveCache as jest.Mock<typeof cache.saveCache>;
saveCacheSpy.mockImplementation(() => Promise.resolve(0));
getCacheDirectoryPathSpy = jest.spyOn(cacheUtils, 'getCacheDirectoryPath');
getCacheDirectoryPathSpy = cacheUtils.getCacheDirectoryPath as jest.Mock<
typeof cacheUtils.getCacheDirectoryPath
>;
getCacheDirectoryPathSpy.mockImplementation(() =>
Promise.resolve(['cache_directory_path', 'cache_directory_path'])
);
existsSpy = jest.spyOn(fs, 'existsSync');
existsSpy = fs.existsSync as jest.Mock<typeof fs.existsSync>;
existsSpy.mockImplementation(() => true);
});
afterEach(() => {
jest.restoreAllMocks();
jest.clearAllMocks();
});
it('does not save cache when the cache input is false', async () => {

View file

@ -1,22 +1,60 @@
import * as exec from '@actions/exec';
import * as cache from '@actions/cache';
import * as core from '@actions/core';
import * as cacheUtils from '../src/cache-utils';
import {PackageManagerInfo} from '../src/package-managers';
import {jest, describe, it, expect, beforeEach, afterAll} from '@jest/globals';
jest.unstable_mockModule('@actions/exec', () => ({
exec: jest.fn(),
getExecOutput: jest.fn()
}));
jest.unstable_mockModule('@actions/cache', () => ({
saveCache: jest.fn(),
restoreCache: jest.fn(),
isFeatureAvailable: jest.fn()
}));
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 exec = await import('@actions/exec');
const cache = await import('@actions/cache');
const core = await import('@actions/core');
const cacheUtils = await import('../src/cache-utils.js');
import type {PackageManagerInfo} from '../src/package-managers.js';
describe('getCommandOutput', () => {
//Arrange
const getExecOutputSpy = jest.spyOn(exec, 'getExecOutput');
const getExecOutputSpy = exec.getExecOutput as jest.Mock<
typeof exec.getExecOutput
>;
it('should return trimmed stdout in case of successful exit code', async () => {
//Arrange
const stdoutResult = ' stdout ';
const trimmedStdout = stdoutResult.trim();
getExecOutputSpy.mockImplementation((commandLine: string) => {
return new Promise<exec.ExecOutput>(resolve => {
resolve({exitCode: 0, stdout: stdoutResult, stderr: ''});
});
getExecOutputSpy.mockImplementation(async (commandLine: string) => {
return {exitCode: 0, stdout: stdoutResult, stderr: ''};
});
//Act + Assert
@ -29,10 +67,8 @@ describe('getCommandOutput', () => {
//Arrange
const stderrResult = 'error message';
getExecOutputSpy.mockImplementation((commandLine: string) => {
return new Promise<exec.ExecOutput>(resolve => {
resolve({exitCode: 10, stdout: '', stderr: stderrResult});
});
getExecOutputSpy.mockImplementation(async (commandLine: string) => {
return {exitCode: 10, stdout: '', stderr: stderrResult};
});
//Act + Assert
@ -70,7 +106,9 @@ describe('getPackageManagerInfo', () => {
describe('getCacheDirectoryPath', () => {
//Arrange
const getExecOutputSpy = jest.spyOn(exec, 'getExecOutput');
const getExecOutputSpy = exec.getExecOutput as jest.Mock<
typeof exec.getExecOutput
>;
const validPackageManager: PackageManagerInfo = {
dependencyFilePattern: 'go.mod',
@ -79,10 +117,8 @@ describe('getCacheDirectoryPath', () => {
it('should return path to the cache folders which specified package manager uses', async () => {
//Arrange
getExecOutputSpy.mockImplementation((commandLine: string) => {
return new Promise<exec.ExecOutput>(resolve => {
resolve({exitCode: 0, stdout: 'path/to/cache/folder', stderr: ''});
});
getExecOutputSpy.mockImplementation(async (commandLine: string) => {
return {exitCode: 0, stdout: 'path/to/cache/folder', stderr: ''};
});
const expectedResult = ['path/to/cache/folder', 'path/to/cache/folder'];
@ -95,16 +131,12 @@ describe('getCacheDirectoryPath', () => {
it('should return path to the cache folder if one command return empty str', async () => {
//Arrange
getExecOutputSpy.mockImplementationOnce((commandLine: string) => {
return new Promise<exec.ExecOutput>(resolve => {
resolve({exitCode: 0, stdout: 'path/to/cache/folder', stderr: ''});
});
getExecOutputSpy.mockImplementationOnce(async (commandLine: string) => {
return {exitCode: 0, stdout: 'path/to/cache/folder', stderr: ''};
});
getExecOutputSpy.mockImplementationOnce((commandLine: string) => {
return new Promise<exec.ExecOutput>(resolve => {
resolve({exitCode: 0, stdout: '', stderr: ''});
});
getExecOutputSpy.mockImplementationOnce(async (commandLine: string) => {
return {exitCode: 0, stdout: '', stderr: ''};
});
const expectedResult = ['path/to/cache/folder'];
@ -116,10 +148,8 @@ describe('getCacheDirectoryPath', () => {
});
it('should throw if the both commands return empty str', async () => {
getExecOutputSpy.mockImplementation((commandLine: string) => {
return new Promise<exec.ExecOutput>(resolve => {
resolve({exitCode: 10, stdout: '', stderr: ''});
});
getExecOutputSpy.mockImplementation(async (commandLine: string) => {
return {exitCode: 10, stdout: '', stderr: ''};
});
//Act + Assert
@ -129,10 +159,8 @@ describe('getCacheDirectoryPath', () => {
});
it('should throw if the specified package name is invalid', async () => {
getExecOutputSpy.mockImplementation((commandLine: string) => {
return new Promise<exec.ExecOutput>(resolve => {
resolve({exitCode: 10, stdout: '', stderr: 'Error message'});
});
getExecOutputSpy.mockImplementation(async (commandLine: string) => {
return {exitCode: 10, stdout: '', stderr: 'Error message'};
});
//Act + Assert
@ -144,8 +172,10 @@ describe('getCacheDirectoryPath', () => {
describe('isCacheFeatureAvailable', () => {
//Arrange
const isFeatureAvailableSpy = jest.spyOn(cache, 'isFeatureAvailable');
const warningSpy = jest.spyOn(core, 'warning');
const isFeatureAvailableSpy = cache.isFeatureAvailable as jest.Mock<
typeof cache.isFeatureAvailable
>;
const warningSpy = core.warning as jest.Mock<typeof core.warning>;
it('should return true when cache feature is available', () => {
//Arrange
@ -211,10 +241,9 @@ describe('isCacheFeatureAvailable', () => {
});
describe('isGhes', () => {
const pristineEnv = process.env;
const pristineEnv = {...process.env};
beforeEach(() => {
jest.resetModules();
process.env = {...pristineEnv};
});

View file

@ -1,17 +1,98 @@
import * as core from '@actions/core';
import * as io from '@actions/io';
import * as tc from '@actions/tool-cache';
import {
jest,
describe,
it,
expect,
beforeAll,
beforeEach,
afterEach,
afterAll
} from '@jest/globals';
import fs from 'fs';
import cp from 'child_process';
import osm, {type} from 'os';
import path from 'path';
import * as main from '../src/main';
import * as im from '../src/installer';
import * as httpm from '@actions/http-client';
import goJsonData from './data/golang-dl.json';
import matchers from '../matchers.json';
import goTestManifest from './data/versions-manifest.json';
import goJsonData from './data/golang-dl.json' with {type: 'json'};
import matchers from '../matchers.json' with {type: 'json'};
import goTestManifest from './data/versions-manifest.json' with {type: 'json'};
import type {IGoVersion} from '../src/installer.js';
import type {IToolRelease} from '@actions/tool-cache';
const httpClientGetJson = jest.fn();
const realCore = await import('@actions/core');
jest.unstable_mockModule('@actions/core', () => ({
...realCore,
getInput: jest.fn(),
getBooleanInput: jest.fn(),
info: jest.fn(),
debug: jest.fn(),
exportVariable: jest.fn()
}));
const realOs = (await import('os')).default;
const osPlatformMock = jest.fn();
const osArchMock = jest.fn();
const osExports = {
...realOs,
platform: osPlatformMock,
arch: osArchMock
};
jest.unstable_mockModule('os', () => ({...osExports, default: osExports}));
const realPath = (await import('path')).default;
const pathJoinMock = jest.fn();
const pathExports = {
...realPath,
join: pathJoinMock
};
jest.unstable_mockModule('path', () => ({
...pathExports,
default: pathExports
}));
jest.unstable_mockModule('@actions/io', () => ({
which: jest.fn(),
mkdirP: jest.fn(),
rmRF: jest.fn(),
mv: jest.fn(),
cp: jest.fn()
}));
const realTc = await import('@actions/tool-cache');
jest.unstable_mockModule('@actions/tool-cache', () => ({
...realTc,
find: jest.fn(),
downloadTool: jest.fn(),
extractTar: jest.fn(),
extractZip: jest.fn(),
cacheDir: jest.fn(),
getManifestFromRepo: jest.fn()
}));
const realHttp = await import('@actions/http-client');
jest.unstable_mockModule('@actions/http-client', () => ({
...realHttp,
HttpClient: jest.fn().mockImplementation(() => ({
getJson: httpClientGetJson
}))
}));
jest.unstable_mockModule('../src/go-version-fetch.js', () => ({
getVersionsDist: jest.fn()
}));
const core = await import('@actions/core');
const io = await import('@actions/io');
const tc = await import('@actions/tool-cache');
const vf = await import('../src/go-version-fetch.js');
const main = await import('../src/main.js');
const im = await import('../src/installer.js');
const osm = (await import('os')).default;
const path = (await import('path')).default;
const matcherPattern = matchers.problemMatcher[0].pattern[0];
const matcherRegExp = new RegExp(matcherPattern.regexp);
const win32Join = path.win32.join;
@ -23,32 +104,31 @@ describe('setup-go', () => {
let inputs = {} as any;
let os = {} as any;
let inSpy: jest.SpyInstance;
let getBooleanInputSpy: jest.SpyInstance;
let exportVarSpy: jest.SpyInstance;
let findSpy: jest.SpyInstance;
let cnSpy: jest.SpyInstance;
let logSpy: jest.SpyInstance;
let getSpy: jest.SpyInstance;
let platSpy: jest.SpyInstance;
let archSpy: jest.SpyInstance;
let joinSpy: jest.SpyInstance;
let dlSpy: jest.SpyInstance;
let extractTarSpy: jest.SpyInstance;
let extractZipSpy: jest.SpyInstance;
let cacheSpy: jest.SpyInstance;
let dbgSpy: jest.SpyInstance;
let whichSpy: jest.SpyInstance;
let existsSpy: jest.SpyInstance;
let readFileSpy: jest.SpyInstance;
let mkdirpSpy: jest.SpyInstance;
let mkdirSpy: jest.SpyInstance;
let symlinkSpy: jest.SpyInstance;
let execSpy: jest.SpyInstance;
let execFileSpy: jest.SpyInstance;
let getManifestSpy: jest.SpyInstance;
let getAllVersionsSpy: jest.SpyInstance;
let httpmGetJsonSpy: jest.SpyInstance;
let inSpy: jest.Mock<typeof core.getInput>;
let getBooleanInputSpy: jest.Mock<typeof core.getBooleanInput>;
let exportVarSpy: jest.Mock<typeof core.exportVariable>;
let findSpy: jest.Mock;
let cnSpy: jest.SpiedFunction<typeof process.stdout.write>;
let logSpy: jest.Mock;
let getSpy: jest.Mock;
let platSpy: jest.Mock;
let archSpy: jest.Mock;
let joinSpy: jest.Mock<typeof path.join>;
let dlSpy: jest.Mock;
let extractTarSpy: jest.Mock;
let extractZipSpy: jest.Mock;
let cacheSpy: jest.Mock;
let dbgSpy: jest.Mock;
let whichSpy: jest.Mock;
let existsSpy: jest.SpiedFunction<typeof fs.existsSync>;
let readFileSpy: jest.SpiedFunction<typeof fs.readFileSync>;
let mkdirpSpy: jest.Mock;
let mkdirSpy: jest.SpiedFunction<typeof fs.mkdir>;
let symlinkSpy: jest.SpiedFunction<typeof fs.symlinkSync>;
let execSpy: jest.SpiedFunction<typeof cp.execSync>;
let execFileSpy: jest.SpiedFunction<typeof cp.execFileSync>;
let getManifestSpy: jest.Mock;
let httpmGetJsonSpy: jest.Mock;
beforeAll(async () => {
process.env['GITHUB_ENV'] = ''; // Stub out Environment file functionality so we can verify it writes to standard out (toolkit is backwards compatible)
@ -59,17 +139,19 @@ describe('setup-go', () => {
// @actions/core
inputs = {};
inSpy = jest.spyOn(core, 'getInput');
inSpy = core.getInput as jest.Mock<typeof core.getInput>;
inSpy.mockImplementation(name => inputs[name]);
getBooleanInputSpy = jest.spyOn(core, 'getBooleanInput');
getBooleanInputSpy = core.getBooleanInput as jest.Mock<
typeof core.getBooleanInput
>;
getBooleanInputSpy.mockImplementation(name => inputs[name]);
exportVarSpy = jest.spyOn(core, 'exportVariable');
exportVarSpy = core.exportVariable as jest.Mock<typeof core.exportVariable>;
// node
os = {};
platSpy = jest.spyOn(osm, 'platform');
platSpy = osm.platform as jest.Mock;
platSpy.mockImplementation(() => os['platform']);
archSpy = jest.spyOn(osm, 'arch');
archSpy = osm.arch as jest.Mock;
archSpy.mockImplementation(() => os['arch']);
execSpy = jest.spyOn(cp, 'execSync');
execFileSpy = jest.spyOn(cp, 'execFileSync');
@ -78,7 +160,7 @@ describe('setup-go', () => {
});
// switch path join behaviour based on set os.platform
joinSpy = jest.spyOn(path, 'join');
joinSpy = path.join as jest.Mock<typeof path.join>;
joinSpy.mockImplementation((...paths: string[]): string => {
if (os['platform'] == 'win32') {
return win32Join(...paths);
@ -88,23 +170,22 @@ describe('setup-go', () => {
});
// @actions/tool-cache
findSpy = jest.spyOn(tc, 'find');
dlSpy = jest.spyOn(tc, 'downloadTool');
extractTarSpy = jest.spyOn(tc, 'extractTar');
extractZipSpy = jest.spyOn(tc, 'extractZip');
cacheSpy = jest.spyOn(tc, 'cacheDir');
getSpy = jest.spyOn(im, 'getVersionsDist');
getManifestSpy = jest.spyOn(tc, 'getManifestFromRepo');
getAllVersionsSpy = jest.spyOn(im, 'getManifest');
findSpy = tc.find as jest.Mock;
dlSpy = tc.downloadTool as jest.Mock;
extractTarSpy = tc.extractTar as jest.Mock;
extractZipSpy = tc.extractZip as jest.Mock;
cacheSpy = tc.cacheDir as jest.Mock;
getSpy = vf.getVersionsDist as jest.Mock;
getManifestSpy = tc.getManifestFromRepo as jest.Mock;
// httm
httpmGetJsonSpy = jest.spyOn(httpm.HttpClient.prototype, 'getJson');
httpmGetJsonSpy = httpClientGetJson;
// io
whichSpy = jest.spyOn(io, 'which');
whichSpy = io.which as jest.Mock;
existsSpy = jest.spyOn(fs, 'existsSync');
readFileSpy = jest.spyOn(fs, 'readFileSync');
mkdirpSpy = jest.spyOn(io, 'mkdirP');
mkdirpSpy = io.mkdirP as jest.Mock;
// fs
mkdirSpy = jest.spyOn(fs, 'mkdir');
@ -112,25 +193,16 @@ describe('setup-go', () => {
symlinkSpy.mockImplementation(() => {});
// gets
getManifestSpy.mockImplementation(() => <tc.IToolRelease[]>goTestManifest);
getManifestSpy.mockImplementation(() => goTestManifest as IToolRelease[]);
// writes
cnSpy = jest.spyOn(process.stdout, 'write');
logSpy = jest.spyOn(core, 'info');
dbgSpy = jest.spyOn(core, 'debug');
getSpy.mockImplementation(() => <im.IGoVersion[] | null>goJsonData);
cnSpy.mockImplementation(line => {
// uncomment to debug
// process.stderr.write('write:' + line + '\n');
});
logSpy.mockImplementation(line => {
// uncomment to debug
//process.stderr.write('log:' + line + '\n');
});
dbgSpy.mockImplementation(msg => {
// uncomment to see debug output
// process.stderr.write(msg + '\n');
});
logSpy = core.info as jest.Mock;
dbgSpy = core.debug as jest.Mock;
getSpy.mockImplementation(() => goJsonData as IGoVersion[] | null);
cnSpy.mockImplementation(() => true);
logSpy.mockImplementation(() => {});
dbgSpy.mockImplementation(() => {});
});
afterEach(() => {
@ -138,6 +210,10 @@ describe('setup-go', () => {
delete process.env[im.GOTOOLCHAIN_ENV_VAR];
delete process.env['GO_DOWNLOAD_BASE_URL'];
// reset the exit code that core.setFailed sets on the error-path tests so
// that a passing run does not leak a non-zero process exit code
process.exitCode = 0;
//jest.resetAllMocks();
jest.clearAllMocks();
//jest.restoreAllMocks();
@ -171,8 +247,10 @@ describe('setup-go', () => {
});
it('should return manifest from raw URL if repo fetch fails', async () => {
getManifestSpy.mockRejectedValue(new Error('Fetch failed'));
httpmGetJsonSpy.mockResolvedValue({
(getManifestSpy as jest.Mock<any>).mockRejectedValue(
new Error('Fetch failed')
);
(httpmGetJsonSpy as jest.Mock<any>).mockResolvedValue({
result: goTestManifest
});
const manifest = await im.getManifest(undefined);
@ -211,7 +289,7 @@ describe('setup-go', () => {
os.arch = 'x64';
// spec: 1.13.0 => 1.13
const match: im.IGoVersion | undefined = await im.findMatch('1.13.0');
const match: IGoVersion | undefined = await im.findMatch('1.13.0');
expect(match).toBeDefined();
const version: string = match ? match.version : '';
expect(version).toBe('go1.13');
@ -224,7 +302,7 @@ describe('setup-go', () => {
os.arch = 'x64';
// spec: 1.13 => 1.13.7 (latest)
const match: im.IGoVersion | undefined = await im.findMatch('1.13');
const match: IGoVersion | undefined = await im.findMatch('1.13');
expect(match).toBeDefined();
const version: string = match ? match.version : '';
expect(version).toBe('go1.13.7');
@ -237,7 +315,7 @@ describe('setup-go', () => {
os.arch = 'x64';
// spec: ^1.13.6 => 1.13.7
const match: im.IGoVersion | undefined = await im.findMatch('^1.13.6');
const match: IGoVersion | undefined = await im.findMatch('^1.13.6');
expect(match).toBeDefined();
const version: string = match ? match.version : '';
expect(version).toBe('go1.13.7');
@ -250,7 +328,7 @@ describe('setup-go', () => {
os.arch = 'x32';
// spec: 1 => 1.13.7 (latest)
const match: im.IGoVersion | undefined = await im.findMatch('1');
const match: IGoVersion | undefined = await im.findMatch('1');
expect(match).toBeDefined();
const version: string = match ? match.version : '';
expect(version).toBe('go1.13.7');
@ -263,7 +341,7 @@ describe('setup-go', () => {
os.arch = 'x64';
// spec: 1.14, stable=false => go1.14rc1
const match: im.IGoVersion | undefined = await im.findMatch('1.14.0-rc.1');
const match: IGoVersion | undefined = await im.findMatch('1.14.0-rc.1');
expect(match).toBeDefined();
const version: string = match ? match.version : '';
expect(version).toBe('go1.14rc1');
@ -817,10 +895,9 @@ describe('setup-go', () => {
getManifestSpy.mockImplementation(() => {
throw new Error('Unable to download manifest');
});
httpmGetJsonSpy.mockRejectedValue(
(httpmGetJsonSpy as jest.Mock<any>).mockRejectedValue(
new Error('Unable to download manifest from raw URL')
);
getAllVersionsSpy.mockImplementationOnce(() => undefined);
dlSpy.mockImplementation(async () => '/some/temp/path');
const toolPath = path.normalize('/cache/go/1.13.7/x64');

View file

@ -1,4 +1,5 @@
import {isSelfHosted} from '../src/utils';
import {describe, it, expect, beforeEach, afterEach} from '@jest/globals';
import {isSelfHosted} from '../src/utils.js';
describe('utils', () => {
describe('isSelfHosted', () => {

View file

@ -1,38 +1,57 @@
import fs from 'fs';
import * as io from '@actions/io';
import * as tc from '@actions/tool-cache';
import {jest, describe, it, expect, beforeEach, afterEach} from '@jest/globals';
import path from 'path';
const statSyncMock = jest.fn(() => ({
isDirectory: () => true,
isFile: () => true
}));
const readdirSyncMock = jest.fn(() => [] as any);
const writeFileSyncMock = jest.fn();
const mkdirMock = jest.fn();
const symlinkSyncMock = jest.fn();
jest.unstable_mockModule('@actions/io', () => ({
which: jest.fn(),
mkdirP: jest.fn(() => Promise.resolve()),
rmRF: jest.fn(() => Promise.resolve()),
mv: jest.fn(() => Promise.resolve()),
cp: jest.fn(() => Promise.resolve())
}));
const realFs = (await import('fs')).default;
const fsExports = {
...realFs,
statSync: statSyncMock,
readdirSync: readdirSyncMock,
writeFileSync: writeFileSyncMock,
mkdir: mkdirMock,
symlinkSync: symlinkSyncMock
};
jest.unstable_mockModule('fs', () => ({...fsExports, default: fsExports}));
const io = await import('@actions/io');
const tc = await import('@actions/tool-cache');
describe('Windows performance workaround', () => {
let mkdirSpy: jest.SpyInstance;
let symlinkSpy: jest.SpyInstance;
let statSpy: jest.SpyInstance;
let readdirSpy: jest.SpyInstance;
let writeFileSpy: jest.SpyInstance;
let rmRFSpy: jest.SpyInstance;
let mkdirPSpy: jest.SpyInstance;
let cpSpy: jest.SpyInstance;
let rmRFSpy: jest.Mock;
let mkdirPSpy: jest.Mock;
let cpSpy: jest.Mock;
let runnerToolCache: string | undefined;
beforeEach(() => {
mkdirSpy = jest.spyOn(fs, 'mkdir');
symlinkSpy = jest.spyOn(fs, 'symlinkSync');
statSpy = jest.spyOn(fs, 'statSync');
readdirSpy = jest.spyOn(fs, 'readdirSync');
writeFileSpy = jest.spyOn(fs, 'writeFileSync');
rmRFSpy = jest.spyOn(io, 'rmRF');
mkdirPSpy = jest.spyOn(io, 'mkdirP');
cpSpy = jest.spyOn(io, 'cp');
rmRFSpy = io.rmRF as jest.Mock;
mkdirPSpy = io.mkdirP as jest.Mock;
cpSpy = io.cp as jest.Mock;
// default implementations
// @ts-ignore - not implement unused methods
statSpy.mockImplementation(() => ({
isDirectory: () => true
statSyncMock.mockImplementation(() => ({
isDirectory: () => true,
isFile: () => true
}));
readdirSpy.mockImplementation(() => []);
writeFileSpy.mockImplementation(() => {});
mkdirSpy.mockImplementation(() => {});
symlinkSpy.mockImplementation(() => {});
readdirSyncMock.mockImplementation(() => []);
writeFileSyncMock.mockImplementation(() => {});
mkdirMock.mockImplementation(() => {});
symlinkSyncMock.mockImplementation(() => {});
rmRFSpy.mockImplementation(() => Promise.resolve());
mkdirPSpy.mockImplementation(() => Promise.resolve());
cpSpy.mockImplementation(() => Promise.resolve());

113042
dist/cache-save/index.js vendored

File diff suppressed because one or more lines are too long

3
dist/cache-save/package.json vendored Normal file
View file

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

118681
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"
}

73
eslint.config.mjs Normal file
View file

@ -0,0 +1,73 @@
// 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-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
};

4735
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,7 @@
{
"name": "setup-go",
"version": "6.5.0",
"type": "module",
"private": true,
"description": "setup go action",
"main": "lib/setup-go.js",
@ -9,11 +10,11 @@
},
"scripts": {
"build": "tsc && ncc build -o dist/setup src/setup-go.ts && ncc build -o dist/cache-save src/cache-save.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",
"test": "jest --coverage",
"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",
"test": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js --runInBand --coverage",
"pre-checkin": "npm run format && npm run lint:fix && npm run build && npm test"
},
"repository": {
@ -28,31 +29,34 @@
"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.7.3"
"@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"
},
"devDependencies": {
"@types/jest": "^29.5.14",
"@types/node": "^25.9.3",
"@types/semver": "^7.7.1",
"@typescript-eslint/eslint-plugin": "^8.61.0",
"@typescript-eslint/parser": "^8.61.0",
"@vercel/ncc": "^0.38.1",
"eslint": "^8.57.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-jest": "^29.0.1",
"eslint-plugin-node": "^11.1.0",
"jest": "^29.7.0",
"jest-circus": "^29.7.0",
"nock": "^10.0.6",
"prettier": "^2.8.4",
"ts-jest": "^29.3.2",
"typescript": "^5.8.3"
"@eslint/js": "^10.0.1",
"@jest/globals": "^30.4.1",
"@types/jest": "^30.0.0",
"@types/node": "^26.0.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": "^10.5.0",
"eslint-config-prettier": "^10.0.0",
"eslint-plugin-jest": "^29.15.2",
"eslint-plugin-n": "^18.1.0",
"globals": "^17.7.0",
"jest": "^30.4.2",
"nock": "^14.0.0",
"prettier": "^3.8.4",
"ts-jest": "^29.4.11",
"ts-node": "^10.9.2",
"typescript": "^6.0.3"
}
}

View file

@ -4,9 +4,9 @@ import * as glob from '@actions/glob';
import path from 'path';
import fs from 'fs';
import {State, Outputs} from './constants';
import {PackageManagerInfo} from './package-managers';
import {getCacheDirectoryPath, getPackageManagerInfo} from './cache-utils';
import {State, Outputs} from './constants.js';
import {PackageManagerInfo} from './package-managers.js';
import {getCacheDirectoryPath, getPackageManagerInfo} from './cache-utils.js';
export const restoreCache = async (
versionSpec: string,

View file

@ -1,8 +1,8 @@
import * as core from '@actions/core';
import * as cache from '@actions/cache';
import fs from 'fs';
import {State} from './constants';
import {getCacheDirectoryPath, getPackageManagerInfo} from './cache-utils';
import {State} from './constants.js';
import {getCacheDirectoryPath, getPackageManagerInfo} from './cache-utils.js';
// Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in
// @actions/toolkit when a failed upload closes the file descriptor causing any in-process reads to

View file

@ -1,7 +1,10 @@
import * as cache from '@actions/cache';
import * as core from '@actions/core';
import * as exec from '@actions/exec';
import {supportedPackageManagers, PackageManagerInfo} from './package-managers';
import {
supportedPackageManagers,
PackageManagerInfo
} from './package-managers.js';
export const getCommandOutput = async (toolCommand: string) => {
let {stdout, stderr, exitCode} = await exec.getExecOutput(

13
src/go-version-fetch.ts Normal file
View file

@ -0,0 +1,13 @@
import * as httpm from '@actions/http-client';
import type {IGoVersion} from './installer.js';
export async function getVersionsDist(
dlUrl: string
): Promise<IGoVersion[] | null> {
// this returns versions descending so latest is first
const http: httpm.HttpClient = new httpm.HttpClient('setup-go', [], {
allowRedirects: true,
maxRedirects: 3
});
return (await http.getJson<IGoVersion[]>(dlUrl)).result;
}

View file

@ -3,13 +3,14 @@ import * as core from '@actions/core';
import * as path from 'path';
import * as semver from 'semver';
import * as httpm from '@actions/http-client';
import * as sys from './system';
import * as sys from './system.js';
import crypto from 'crypto';
import cp from 'child_process';
import fs from 'fs';
import os from 'os';
import {StableReleaseAlias, isSelfHosted} from './utils';
import {Architecture} from './types';
import {StableReleaseAlias, isSelfHosted} from './utils.js';
import {Architecture} from './types.js';
import {getVersionsDist} from './go-version-fetch.js';
export const GOTOOLCHAIN_ENV_VAR = 'GOTOOLCHAIN';
export const GOTOOLCHAIN_LOCAL_VAL = 'local';
@ -167,12 +168,14 @@ export async function getGo(
if (err instanceof tc.HTTPError && err.httpStatusCode === 404) {
throw new Error(
`The requested Go version ${versionSpec} is not available for platform ${osPlat}/${arch}. ` +
`Download URL returned HTTP 404: ${downloadUrl}`
`Download URL returned HTTP 404: ${downloadUrl}`,
{cause: err}
);
}
throw new Error(
`Failed to download Go ${versionSpec} for platform ${osPlat}/${arch} ` +
`from ${downloadUrl}: ${err}`
`from ${downloadUrl}: ${err}`,
{cause: err}
);
}
} else {
@ -218,7 +221,9 @@ export async function getGo(
core.info('Install from dist');
downloadPath = await installGoVersion(info, undefined, arch);
} catch (err) {
throw new Error(`Failed to download version ${versionSpec}: ${err}`);
throw new Error(`Failed to download version ${versionSpec}: ${err}`, {
cause: err
});
}
}
}
@ -569,9 +574,7 @@ export async function findMatch(
let result: IGoVersion | undefined;
let match: IGoVersion | undefined;
const candidates: IGoVersion[] | null = await module.exports.getVersionsDist(
dlUrl
);
const candidates: IGoVersion[] | null = await getVersionsDist(dlUrl);
if (!candidates) {
throw new Error(`golang download url did not return results`);
}
@ -607,17 +610,6 @@ export async function findMatch(
return result;
}
export async function getVersionsDist(
dlUrl: string
): Promise<IGoVersion[] | null> {
// this returns versions descending so latest is first
const http: httpm.HttpClient = new httpm.HttpClient('setup-go', [], {
allowRedirects: true,
maxRedirects: 3
});
return (await http.getJson<IGoVersion[]>(dlUrl)).result;
}
//
// Convert the go version syntax into semver for semver matching
// 1.13.1 => 1.13.1
@ -686,9 +678,8 @@ async function resolveStableVersionDist(
) {
const archFilter = sys.getArch(arch);
const platFilter = sys.getPlatform();
const candidates: IGoVersion[] | null = await module.exports.getVersionsDist(
GOLANG_DOWNLOAD_URL
);
const candidates: IGoVersion[] | null =
await getVersionsDist(GOLANG_DOWNLOAD_URL);
if (!candidates) {
throw new Error(`golang download url did not return results`);
}

View file

@ -1,14 +1,15 @@
import * as core from '@actions/core';
import * as io from '@actions/io';
import * as installer from './installer';
import * as installer from './installer.js';
import * as semver from 'semver';
import path from 'path';
import {restoreCache} from './cache-restore';
import {isCacheFeatureAvailable} from './cache-utils';
import {fileURLToPath} from 'url';
import {restoreCache} from './cache-restore.js';
import {isCacheFeatureAvailable} from './cache-utils.js';
import cp from 'child_process';
import fs from 'fs';
import os from 'os';
import {Architecture} from './types';
import {Architecture} from './types.js';
export async function run() {
try {
@ -91,7 +92,11 @@ export async function run() {
}
// add problem matchers
const matchersPath = path.join(__dirname, '../..', 'matchers.json');
const matchersPath = path.join(
path.dirname(fileURLToPath(import.meta.url)),
'../..',
'matchers.json'
);
core.info(`##[add-matcher]${matchersPath}`);
// output the version actually being used

View file

@ -1,3 +1,3 @@
import {run} from './main';
import {run} from './main.js';
run();

View file

@ -1,5 +1,5 @@
import os from 'os';
import {Architecture} from './types';
import {Architecture} from './types.js';
export function getPlatform(): string {
// darwin and linux match already

8
tsconfig.eslint.json Normal file
View file

@ -0,0 +1,8 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"rootDir": "."
},
"include": ["src/**/*.ts", "__tests__/**/*.ts", "*.ts"],
"exclude": ["node_modules", "lib", "dist"]
}

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. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
@ -38,7 +38,7 @@
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
"moduleResolution": "NodeNext", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
@ -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"]
}