mirror of
https://github.com/actions/javascript-action.git
synced 2025-04-06 23:39:39 +00:00
Restructure source and tests
This commit is contained in:
18
__tests__/index.test.js
Normal file
18
__tests__/index.test.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* Unit tests for the action's entrypoint, src/index.ts
|
||||||
|
*/
|
||||||
|
|
||||||
|
const { run } = require('../src/main')
|
||||||
|
|
||||||
|
// Mock the action's entrypoint
|
||||||
|
jest.mock('../src/main', () => ({
|
||||||
|
run: jest.fn()
|
||||||
|
}))
|
||||||
|
|
||||||
|
describe('index', () => {
|
||||||
|
it('calls run when imported', async () => {
|
||||||
|
require('../src/index')
|
||||||
|
|
||||||
|
expect(run).toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
})
|
100
__tests__/main.test.js
Normal file
100
__tests__/main.test.js
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/**
|
||||||
|
* Unit tests for the action's main functionality, src/main.ts
|
||||||
|
*
|
||||||
|
* These should be run as if the action was called from a workflow.
|
||||||
|
* Specifically, the inputs listed in `action.yml` should be set as environment
|
||||||
|
* variables following the pattern `INPUT_<INPUT_NAME>`.
|
||||||
|
*/
|
||||||
|
const core = require('@actions/core')
|
||||||
|
const main = require('../src/main')
|
||||||
|
|
||||||
|
// Mock the GitHub Actions core library
|
||||||
|
const debugMock = jest.spyOn(core, 'debug').mockImplementation()
|
||||||
|
const getInputMock = jest.spyOn(core, 'getInput').mockImplementation()
|
||||||
|
const setFailedMock = jest.spyOn(core, 'setFailed').mockImplementation()
|
||||||
|
const setOutputMock = jest.spyOn(core, 'setOutput').mockImplementation()
|
||||||
|
|
||||||
|
// Mock the action's main function
|
||||||
|
const runMock = jest.spyOn(main, 'run')
|
||||||
|
|
||||||
|
// Other utilities
|
||||||
|
const timeRegex = /^\d{2}:\d{2}:\d{2}/
|
||||||
|
|
||||||
|
describe('action', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sets the time output', async () => {
|
||||||
|
// Set the action's inputs as return values from core.getInput()
|
||||||
|
getInputMock.mockImplementation(name => {
|
||||||
|
switch (name) {
|
||||||
|
case 'milliseconds':
|
||||||
|
return '500'
|
||||||
|
default:
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
await main.run()
|
||||||
|
expect(runMock).toHaveReturned()
|
||||||
|
|
||||||
|
// Verify that all of the core library functions were called correctly
|
||||||
|
expect(debugMock).toHaveBeenNthCalledWith(1, 'Waiting 500 milliseconds ...')
|
||||||
|
expect(debugMock).toHaveBeenNthCalledWith(
|
||||||
|
2,
|
||||||
|
expect.stringMatching(timeRegex)
|
||||||
|
)
|
||||||
|
expect(debugMock).toHaveBeenNthCalledWith(
|
||||||
|
3,
|
||||||
|
expect.stringMatching(timeRegex)
|
||||||
|
)
|
||||||
|
expect(setOutputMock).toHaveBeenNthCalledWith(
|
||||||
|
1,
|
||||||
|
'time',
|
||||||
|
expect.stringMatching(timeRegex)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sets a failed status', async () => {
|
||||||
|
// Set the action's inputs as return values from core.getInput()
|
||||||
|
getInputMock.mockImplementation(name => {
|
||||||
|
switch (name) {
|
||||||
|
case 'milliseconds':
|
||||||
|
return 'this is not a number'
|
||||||
|
default:
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
await main.run()
|
||||||
|
expect(runMock).toHaveReturned()
|
||||||
|
|
||||||
|
// Verify that all of the core library functions were called correctly
|
||||||
|
expect(setFailedMock).toHaveBeenNthCalledWith(
|
||||||
|
1,
|
||||||
|
'milliseconds not a number'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('fails if no input is provided', async () => {
|
||||||
|
// Set the action's inputs as return values from core.getInput()
|
||||||
|
getInputMock.mockImplementation(name => {
|
||||||
|
switch (name) {
|
||||||
|
case 'milliseconds':
|
||||||
|
throw new Error('Input required and not supplied: milliseconds')
|
||||||
|
default:
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
await main.run()
|
||||||
|
expect(runMock).toHaveReturned()
|
||||||
|
|
||||||
|
// Verify that all of the core library functions were called correctly
|
||||||
|
expect(setFailedMock).toHaveBeenNthCalledWith(
|
||||||
|
1,
|
||||||
|
'Input required and not supplied: milliseconds'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
24
__tests__/wait.test.js
Normal file
24
__tests__/wait.test.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* Unit tests for src/wait.ts
|
||||||
|
*/
|
||||||
|
const { wait } = require('../src/wait')
|
||||||
|
const { expect } = require('@jest/globals')
|
||||||
|
|
||||||
|
describe('wait.ts', () => {
|
||||||
|
it('throws an invalid number', async () => {
|
||||||
|
const input = parseInt('foo', 10)
|
||||||
|
expect(isNaN(input)).toBe(true)
|
||||||
|
|
||||||
|
await expect(wait(input)).rejects.toThrow('milliseconds not a number')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('waits with a valid number', async () => {
|
||||||
|
const start = new Date()
|
||||||
|
await wait(500)
|
||||||
|
const end = new Date()
|
||||||
|
|
||||||
|
const delta = Math.abs(end.getTime() - start.getTime())
|
||||||
|
|
||||||
|
expect(delta).toBeGreaterThan(450)
|
||||||
|
})
|
||||||
|
})
|
136
dist/index.js
generated
vendored
136
dist/index.js
generated
vendored
@ -1,7 +1,7 @@
|
|||||||
require('./sourcemap-register.js');/******/ (() => { // webpackBootstrap
|
/******/ (() => { // webpackBootstrap
|
||||||
/******/ var __webpack_modules__ = ({
|
/******/ var __webpack_modules__ = ({
|
||||||
|
|
||||||
/***/ 351:
|
/***/ 241:
|
||||||
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
@ -135,7 +135,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.getIDToken = exports.getState = exports.saveState = exports.group = exports.endGroup = exports.startGroup = exports.info = exports.notice = exports.warning = exports.error = exports.debug = exports.isDebug = exports.setFailed = exports.setCommandEcho = exports.setOutput = exports.getBooleanInput = exports.getMultilineInput = exports.getInput = exports.addPath = exports.setSecret = exports.exportVariable = exports.ExitCode = void 0;
|
exports.getIDToken = exports.getState = exports.saveState = exports.group = exports.endGroup = exports.startGroup = exports.info = exports.notice = exports.warning = exports.error = exports.debug = exports.isDebug = exports.setFailed = exports.setCommandEcho = exports.setOutput = exports.getBooleanInput = exports.getMultilineInput = exports.getInput = exports.addPath = exports.setSecret = exports.exportVariable = exports.ExitCode = void 0;
|
||||||
const command_1 = __nccwpck_require__(351);
|
const command_1 = __nccwpck_require__(241);
|
||||||
const file_command_1 = __nccwpck_require__(717);
|
const file_command_1 = __nccwpck_require__(717);
|
||||||
const utils_1 = __nccwpck_require__(278);
|
const utils_1 = __nccwpck_require__(278);
|
||||||
const os = __importStar(__nccwpck_require__(37));
|
const os = __importStar(__nccwpck_require__(37));
|
||||||
@ -558,7 +558,7 @@ class OidcClient {
|
|||||||
.catch(error => {
|
.catch(error => {
|
||||||
throw new Error(`Failed to get ID Token. \n
|
throw new Error(`Failed to get ID Token. \n
|
||||||
Error Code : ${error.statusCode}\n
|
Error Code : ${error.statusCode}\n
|
||||||
Error Message: ${error.result.message}`);
|
Error Message: ${error.message}`);
|
||||||
});
|
});
|
||||||
const id_token = (_a = res.result) === null || _a === void 0 ? void 0 : _a.value;
|
const id_token = (_a = res.result) === null || _a === void 0 ? void 0 : _a.value;
|
||||||
if (!id_token) {
|
if (!id_token) {
|
||||||
@ -1211,6 +1211,19 @@ class HttpClientResponse {
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
readBodyBuffer() {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const chunks = [];
|
||||||
|
this.message.on('data', (chunk) => {
|
||||||
|
chunks.push(chunk);
|
||||||
|
});
|
||||||
|
this.message.on('end', () => {
|
||||||
|
resolve(Buffer.concat(chunks));
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
exports.HttpClientResponse = HttpClientResponse;
|
exports.HttpClientResponse = HttpClientResponse;
|
||||||
function isHttps(requestUrl) {
|
function isHttps(requestUrl) {
|
||||||
@ -1715,7 +1728,13 @@ function getProxyUrl(reqUrl) {
|
|||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
if (proxyVar) {
|
if (proxyVar) {
|
||||||
return new URL(proxyVar);
|
try {
|
||||||
|
return new URL(proxyVar);
|
||||||
|
}
|
||||||
|
catch (_a) {
|
||||||
|
if (!proxyVar.startsWith('http://') && !proxyVar.startsWith('https://'))
|
||||||
|
return new URL(`http://${proxyVar}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return undefined;
|
return undefined;
|
||||||
@ -1726,6 +1745,10 @@ function checkBypass(reqUrl) {
|
|||||||
if (!reqUrl.hostname) {
|
if (!reqUrl.hostname) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
const reqHost = reqUrl.hostname;
|
||||||
|
if (isLoopbackAddress(reqHost)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
const noProxy = process.env['no_proxy'] || process.env['NO_PROXY'] || '';
|
const noProxy = process.env['no_proxy'] || process.env['NO_PROXY'] || '';
|
||||||
if (!noProxy) {
|
if (!noProxy) {
|
||||||
return false;
|
return false;
|
||||||
@ -1751,13 +1774,24 @@ function checkBypass(reqUrl) {
|
|||||||
.split(',')
|
.split(',')
|
||||||
.map(x => x.trim().toUpperCase())
|
.map(x => x.trim().toUpperCase())
|
||||||
.filter(x => x)) {
|
.filter(x => x)) {
|
||||||
if (upperReqHosts.some(x => x === upperNoProxyItem)) {
|
if (upperNoProxyItem === '*' ||
|
||||||
|
upperReqHosts.some(x => x === upperNoProxyItem ||
|
||||||
|
x.endsWith(`.${upperNoProxyItem}`) ||
|
||||||
|
(upperNoProxyItem.startsWith('.') &&
|
||||||
|
x.endsWith(`${upperNoProxyItem}`)))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
exports.checkBypass = checkBypass;
|
exports.checkBypass = checkBypass;
|
||||||
|
function isLoopbackAddress(host) {
|
||||||
|
const hostLower = host.toLowerCase();
|
||||||
|
return (hostLower === 'localhost' ||
|
||||||
|
hostLower.startsWith('127.') ||
|
||||||
|
hostLower.startsWith('[::1]') ||
|
||||||
|
hostLower.startsWith('[0:0:0:0:0:0:0:1]'));
|
||||||
|
}
|
||||||
//# sourceMappingURL=proxy.js.map
|
//# sourceMappingURL=proxy.js.map
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
@ -2688,19 +2722,63 @@ exports["default"] = _default;
|
|||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
/***/ 258:
|
/***/ 713:
|
||||||
|
/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
|
||||||
|
|
||||||
|
const core = __nccwpck_require__(186)
|
||||||
|
const { wait } = __nccwpck_require__(312)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main function for the action.
|
||||||
|
* @returns {Promise<void>} Resolves when the action is complete.
|
||||||
|
*/
|
||||||
|
async function run() {
|
||||||
|
try {
|
||||||
|
const ms = core.getInput('milliseconds', { required: true })
|
||||||
|
|
||||||
|
// Debug logs are only output if the `ACTIONS_STEP_DEBUG` secret is true
|
||||||
|
core.debug(`Waiting ${ms} milliseconds ...`)
|
||||||
|
|
||||||
|
// Log the current timestamp, wait, then log the new timestamp
|
||||||
|
core.debug(new Date().toTimeString())
|
||||||
|
await wait(parseInt(ms, 10))
|
||||||
|
core.debug(new Date().toTimeString())
|
||||||
|
|
||||||
|
// Set outputs for other workflow steps to use
|
||||||
|
core.setOutput('time', new Date().toTimeString())
|
||||||
|
} catch (error) {
|
||||||
|
// Fail the workflow run if an error occurs
|
||||||
|
core.setFailed(error.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
run
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ 312:
|
||||||
/***/ ((module) => {
|
/***/ ((module) => {
|
||||||
|
|
||||||
let wait = function (milliseconds) {
|
/**
|
||||||
return new Promise((resolve) => {
|
* Wait for a number of milliseconds.
|
||||||
if (typeof milliseconds !== 'number') {
|
*
|
||||||
throw new Error('milliseconds not a number');
|
* @param {number} milliseconds The number of milliseconds to wait.
|
||||||
|
* @returns {Promise<string>} Resolves with 'done!' after the wait is over.
|
||||||
|
*/
|
||||||
|
async function wait(milliseconds) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
if (isNaN(milliseconds)) {
|
||||||
|
throw new Error('milliseconds not a number')
|
||||||
}
|
}
|
||||||
setTimeout(() => resolve("done!"), milliseconds)
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = wait;
|
setTimeout(() => resolve('done!'), milliseconds)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { wait }
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
@ -2834,31 +2912,15 @@ module.exports = require("util");
|
|||||||
var __webpack_exports__ = {};
|
var __webpack_exports__ = {};
|
||||||
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
|
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
|
||||||
(() => {
|
(() => {
|
||||||
const core = __nccwpck_require__(186);
|
/**
|
||||||
const wait = __nccwpck_require__(258);
|
* The entrypoint for the action.
|
||||||
|
*/
|
||||||
|
const { run } = __nccwpck_require__(713)
|
||||||
|
|
||||||
|
run()
|
||||||
// most @actions toolkit packages have async methods
|
|
||||||
async function run() {
|
|
||||||
try {
|
|
||||||
const ms = core.getInput('milliseconds');
|
|
||||||
core.info(`Waiting ${ms} milliseconds ...`);
|
|
||||||
|
|
||||||
core.debug((new Date()).toTimeString()); // debug is only output if you set the secret `ACTIONS_RUNNER_DEBUG` to true
|
|
||||||
await wait(parseInt(ms));
|
|
||||||
core.info((new Date()).toTimeString());
|
|
||||||
|
|
||||||
core.setOutput('time', new Date().toTimeString());
|
|
||||||
} catch (error) {
|
|
||||||
core.setFailed(error.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
run();
|
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
module.exports = __webpack_exports__;
|
module.exports = __webpack_exports__;
|
||||||
/******/ })()
|
/******/ })()
|
||||||
;
|
;
|
||||||
//# sourceMappingURL=index.js.map
|
|
1
dist/index.js.map
generated
vendored
1
dist/index.js.map
generated
vendored
File diff suppressed because one or more lines are too long
1
dist/sourcemap-register.js
generated
vendored
1
dist/sourcemap-register.js
generated
vendored
File diff suppressed because one or more lines are too long
21
index.js
21
index.js
@ -1,21 +0,0 @@
|
|||||||
const core = require('@actions/core');
|
|
||||||
const wait = require('./wait');
|
|
||||||
|
|
||||||
|
|
||||||
// most @actions toolkit packages have async methods
|
|
||||||
async function run() {
|
|
||||||
try {
|
|
||||||
const ms = core.getInput('milliseconds');
|
|
||||||
core.info(`Waiting ${ms} milliseconds ...`);
|
|
||||||
|
|
||||||
core.debug((new Date()).toTimeString()); // debug is only output if you set the secret `ACTIONS_RUNNER_DEBUG` to true
|
|
||||||
await wait(parseInt(ms));
|
|
||||||
core.info((new Date()).toTimeString());
|
|
||||||
|
|
||||||
core.setOutput('time', new Date().toTimeString());
|
|
||||||
} catch (error) {
|
|
||||||
core.setFailed(error.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
run();
|
|
@ -1,24 +0,0 @@
|
|||||||
const wait = require('./wait');
|
|
||||||
const process = require('process');
|
|
||||||
const cp = require('child_process');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
test('throws invalid number', async () => {
|
|
||||||
await expect(wait('foo')).rejects.toThrow('milliseconds not a number');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('wait 500 ms', async () => {
|
|
||||||
const start = new Date();
|
|
||||||
await wait(500);
|
|
||||||
const end = new Date();
|
|
||||||
var delta = Math.abs(end - start);
|
|
||||||
expect(delta).toBeGreaterThanOrEqual(500);
|
|
||||||
});
|
|
||||||
|
|
||||||
// shows how the runner will run a javascript action with env / stdout protocol
|
|
||||||
test('test runs', () => {
|
|
||||||
process.env['INPUT_MILLISECONDS'] = 100;
|
|
||||||
const ip = path.join(__dirname, 'index.js');
|
|
||||||
const result = cp.execSync(`node ${ip}`, {env: process.env}).toString();
|
|
||||||
console.log(result);
|
|
||||||
})
|
|
6
src/index.js
Normal file
6
src/index.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* The entrypoint for the action.
|
||||||
|
*/
|
||||||
|
const { run } = require('./main')
|
||||||
|
|
||||||
|
run()
|
30
src/main.js
Normal file
30
src/main.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
const core = require('@actions/core')
|
||||||
|
const { wait } = require('./wait')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main function for the action.
|
||||||
|
* @returns {Promise<void>} Resolves when the action is complete.
|
||||||
|
*/
|
||||||
|
async function run() {
|
||||||
|
try {
|
||||||
|
const ms = core.getInput('milliseconds', { required: true })
|
||||||
|
|
||||||
|
// Debug logs are only output if the `ACTIONS_STEP_DEBUG` secret is true
|
||||||
|
core.debug(`Waiting ${ms} milliseconds ...`)
|
||||||
|
|
||||||
|
// Log the current timestamp, wait, then log the new timestamp
|
||||||
|
core.debug(new Date().toTimeString())
|
||||||
|
await wait(parseInt(ms, 10))
|
||||||
|
core.debug(new Date().toTimeString())
|
||||||
|
|
||||||
|
// Set outputs for other workflow steps to use
|
||||||
|
core.setOutput('time', new Date().toTimeString())
|
||||||
|
} catch (error) {
|
||||||
|
// Fail the workflow run if an error occurs
|
||||||
|
core.setFailed(error.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
run
|
||||||
|
}
|
17
src/wait.js
Normal file
17
src/wait.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* Wait for a number of milliseconds.
|
||||||
|
*
|
||||||
|
* @param {number} milliseconds The number of milliseconds to wait.
|
||||||
|
* @returns {Promise<string>} Resolves with 'done!' after the wait is over.
|
||||||
|
*/
|
||||||
|
async function wait(milliseconds) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
if (isNaN(milliseconds)) {
|
||||||
|
throw new Error('milliseconds not a number')
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => resolve('done!'), milliseconds)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { wait }
|
Reference in New Issue
Block a user