diff --git a/README.md b/README.md index 138ca00..8aa27aa 100644 --- a/README.md +++ b/README.md @@ -79,22 +79,19 @@ contents of this directory with your own code. There are a few things to keep in mind when writing your action code: - Most GitHub Actions toolkit and CI/CD operations are processed asynchronously. - In `index.ts`, you will see that the action is run in an `async` function. + In `main.ts`, you will see that the action is run in an `async` function. ```javascript - import * as core from '@actions/core'; - ... + import * as core from '@actions/core' + //... async function run() { try { - ... - } - catch (error) { - core.setFailed(error.message); + //... + } catch (error) { + core.setFailed(error.message) } } - - run() ``` For more information about the GitHub Actions toolkit, see the diff --git a/__tests__/index.test.ts b/__tests__/index.test.ts index 8d7a010..34a4dfe 100644 --- a/__tests__/index.test.ts +++ b/__tests__/index.test.ts @@ -1,80 +1,17 @@ /** * Unit tests for the action's entrypoint, src/index.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_`. */ -import * as core from '@actions/core' -import * as index from '../src/index' - -// Mock the GitHub Actions core library -const debugMock = jest.spyOn(core, 'debug') -const getInputMock = jest.spyOn(core, 'getInput') -const setFailedMock = jest.spyOn(core, 'setFailed') -const setOutputMock = jest.spyOn(core, 'setOutput') +import * as main from '../src/main' // Mock the action's entrypoint -const runMock = jest.spyOn(index, 'run') +const runMock = jest.spyOn(main, 'run').mockImplementation() -// Other utilities -const timeRegex = /^\d{2}:\d{2}:\d{2}/ +describe('index', () => { + it('calls run when imported', async () => { + // eslint-disable-next-line @typescript-eslint/no-require-imports + require('../src/index') -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: string): string => { - switch (name) { - case 'milliseconds': - return '500' - default: - return '' - } - }) - - await index.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: string): string => { - switch (name) { - case 'milliseconds': - return 'this is not a number' - default: - return '' - } - }) - - await index.run() - expect(runMock).toHaveReturned() - - // Verify that all of the core library functions were called correctly - expect(setFailedMock).toHaveBeenNthCalledWith( - 1, - 'milliseconds not a number' - ) + expect(runMock).toHaveBeenCalled() }) }) diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts new file mode 100644 index 0000000..7a25abc --- /dev/null +++ b/__tests__/main.test.ts @@ -0,0 +1,80 @@ +/** + * 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_`. + */ + +import * as core from '@actions/core' +import * as main from '../src/main' + +// Mock the GitHub Actions core library +const debugMock = jest.spyOn(core, 'debug') +const getInputMock = jest.spyOn(core, 'getInput') +const setFailedMock = jest.spyOn(core, 'setFailed') +const setOutputMock = jest.spyOn(core, 'setOutput') + +// 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: string): string => { + 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: string): string => { + 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' + ) + }) +}) diff --git a/dist/index.js b/dist/index.js index b6fbd26..b07bcaa 100644 --- a/dist/index.js +++ b/dist/index.js @@ -2722,7 +2722,7 @@ exports["default"] = _default; /***/ }), -/***/ 144: +/***/ 399: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; @@ -2777,8 +2777,6 @@ async function run() { } } exports.run = run; -// eslint-disable-next-line @typescript-eslint/no-floating-promises -run(); /***/ }), @@ -2934,12 +2932,22 @@ module.exports = require("util"); /******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = __dirname + "/"; /******/ /************************************************************************/ -/******/ -/******/ // startup -/******/ // Load entry module and return exports -/******/ // This entry module is referenced by other modules so it can't be inlined -/******/ var __webpack_exports__ = __nccwpck_require__(144); -/******/ module.exports = __webpack_exports__; -/******/ +var __webpack_exports__ = {}; +// This entry need to be wrapped in an IIFE because it need to be in strict mode. +(() => { +"use strict"; +var exports = __webpack_exports__; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +/** + * The entrypoint for the action. + */ +const main_1 = __nccwpck_require__(399); +// eslint-disable-next-line @typescript-eslint/no-floating-promises +(0, main_1.run)(); + +})(); + +module.exports = __webpack_exports__; /******/ })() ; \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index b6f3f31..b08f970 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,29 +1,7 @@ -import * as core from '@actions/core' -import { wait } from './wait' - /** - * The main function for the action. - * @returns {Promise} Resolves when the action is complete. + * The entrypoint for the action. */ -export async function run(): Promise { - try { - const ms: string = core.getInput('milliseconds') - - // 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 - if (error instanceof Error) core.setFailed(error.message) - } -} +import { run } from './main' // eslint-disable-next-line @typescript-eslint/no-floating-promises run() diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..c804f90 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,26 @@ +import * as core from '@actions/core' +import { wait } from './wait' + +/** + * The main function for the action. + * @returns {Promise} Resolves when the action is complete. + */ +export async function run(): Promise { + try { + const ms: string = core.getInput('milliseconds') + + // 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 + if (error instanceof Error) core.setFailed(error.message) + } +}