diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 512e134c7..ade6760df 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -2,13 +2,15 @@ name: Integration on: push: {branches: main} + pull_request: {branches: main} jobs: - integration: + test-return: runs-on: ubuntu-latest steps: + - uses: actions/checkout@v2 - id: output-set - uses: actions/github-script@main + uses: ./ with: script: return core.getInput('input-value') result-encoding: string @@ -17,3 +19,39 @@ jobs: if [[ "${{steps.output-set.outputs.result}}" != "output" ]]; then exit 1 fi + + test-relative-require: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - id: output-set + uses: ./ + with: + script: return require('./package.json').name + result-encoding: string + input-value: output + - run: | + if [[ "${{steps.output-set.outputs.result}}" != "github-script" ]]; then + exit 1 + fi + + test-npm-require: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/cache@v1 + with: + path: ~/.npm + key: ${{runner.os}}-npm-${{hashFiles('**/package-lock.json')}} + restore-keys: ${{runner.os}}-npm- + - run: npm ci + - id: output-set + uses: ./ + with: + script: return require('@actions/core/package.json').name + result-encoding: string + input-value: output + - run: | + if [[ "${{steps.output-set.outputs.result}}" != "@actions/core" ]]; then + exit 1 + fi diff --git a/README.md b/README.md index 4c1eb0a16..31669d523 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,12 @@ arguments will be provided: - `core` A reference to the [@actions/core](https://github.com/actions/toolkit/tree/main/packages/core) package - `glob` A reference to the [@actions/glob](https://github.com/actions/toolkit/tree/main/packages/glob) package - `io` A reference to the [@actions/io](https://github.com/actions/toolkit/tree/main/packages/io) package +- `require` A proxy wrapper around the normal Node.js `require` to enable + requiring relative paths (relative to the current working directory) and + requiring npm packages installed in the current working directory. If for + some reason you need the non-wrapped `require`, there is an escape hatch + available: `__original_require__` is the original value of `require` without + our wrapping applied. Since the `script` is just a function body, these values will already be defined, so you don't have to (see examples below). @@ -38,7 +44,7 @@ The return value of the script will be in the step's outputs under the "result" key. ```yaml -- uses: actions/github-script@v3 +- uses: actions/github-script@v4 id: set-result with: script: return "Hello!" @@ -57,7 +63,7 @@ output of a github-script step. For some workflows, string encoding is preferred `result-encoding` input: ```yaml -- uses: actions/github-script@v3 +- uses: actions/github-script@v4 id: my-script with: github-token: ${{secrets.GITHUB_TOKEN}} @@ -76,7 +82,7 @@ By default, github-script will use the token provided to your workflow. ```yaml - name: View context attributes - uses: actions/github-script@v3 + uses: actions/github-script@v4 with: script: console.log(context) ``` @@ -92,7 +98,7 @@ jobs: comment: runs-on: ubuntu-latest steps: - - uses: actions/github-script@v3 + - uses: actions/github-script@v4 with: github-token: ${{secrets.GITHUB_TOKEN}} script: | @@ -115,7 +121,7 @@ jobs: apply-label: runs-on: ubuntu-latest steps: - - uses: actions/github-script@v3 + - uses: actions/github-script@v4 with: github-token: ${{secrets.GITHUB_TOKEN}} script: | @@ -136,7 +142,7 @@ jobs: welcome: runs-on: ubuntu-latest steps: - - uses: actions/github-script@v3 + - uses: actions/github-script@v4 with: github-token: ${{secrets.GITHUB_TOKEN}} script: | @@ -180,7 +186,7 @@ jobs: diff: runs-on: ubuntu-latest steps: - - uses: actions/github-script@v3 + - uses: actions/github-script@v4 with: github-token: ${{secrets.GITHUB_TOKEN}} script: | @@ -205,7 +211,7 @@ jobs: list-issues: runs-on: ubuntu-latest steps: - - uses: actions/github-script@v3 + - uses: actions/github-script@v4 with: github-token: ${{secrets.GITHUB_TOKEN}} script: | @@ -240,15 +246,13 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: actions/github-script@v3 + - uses: actions/github-script@v4 with: script: | - const script = require(`${process.env.GITHUB_WORKSPACE}/path/to/script.js`) + const script = require('./path/to/script.js') console.log(script({github, context})) ``` -_Note that the script path given to `require()` must be an **absolute path** in this case, hence using [`GITHUB_WORKSPACE`](https://docs.github.com/en/actions/configuring-and-managing-workflows/using-environment-variables#default-environment-variables)._ - And then export a function from your module: ```javascript @@ -280,26 +284,26 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: actions/github-script@v3 + - uses: actions/github-script@v4 env: - SHA: "${{env.parentSHA}}" + SHA: '${{env.parentSHA}}' with: script: | - const script = require(`${process.env.GITHUB_WORKSPACE}/path/to/script.js`) + const script = require('./path/to/script.js') await script({github, context, core}) ``` And then export an async function from your module: ```javascript -module.exports = async ({ github, context, core }) => { - const { SHA } = process.env - const commit = await github.repos.getCommit({ - owner: context.repo.owner, - repo: context.repo.repo, - ref: `${SHA}` - }) - core.exportVariable('author', commit.data.commit.author.email); +module.exports = async ({github, context, core}) => { + const {SHA} = process.env + const commit = await github.repos.getCommit({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: `${SHA}` + }) + core.exportVariable('author', commit.data.commit.author.email) } ``` @@ -321,10 +325,10 @@ jobs: - run: npm ci # or one-off: - run: npm install execa - - uses: actions/github-script@v3 + - uses: actions/github-script@v4 with: script: | - const execa = require(`${process.env.GITHUB_WORKSPACE}/node_modules/execa`) + const execa = require('execa') const { stdout } = await execa('echo', ['hello', 'world']) @@ -342,7 +346,7 @@ jobs: echo-input: runs-on: ubuntu-latest steps: - - uses: actions/github-script@v3 + - uses: actions/github-script@v4 env: FIRST_NAME: Mona LAST_NAME: Octocat diff --git a/dist/index.js b/dist/index.js index 096668f4d..2dd846e66 100644 --- a/dist/index.js +++ b/dist/index.js @@ -2883,6 +2883,43 @@ function escapeProperty(s) { module.exports = require("assert"); +/***/ }), + +/***/ 366: +/***/ (function(__unusedmodule, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "wrapRequire", function() { return wrapRequire; }); +/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(622); +/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_0__); + +const wrapRequire = new Proxy(require, { + apply: (target, thisArg, [moduleID]) => { + if (moduleID.startsWith('.')) { + moduleID = path__WEBPACK_IMPORTED_MODULE_0__.resolve(moduleID); + return target.apply(thisArg, [moduleID]); + } + try { + return target.apply(thisArg, [moduleID]); + } + catch (err) { + const modulePath = target.resolve.apply(thisArg, [ + moduleID, + { + // Webpack does not have an escape hatch for getting the actual + // module, other than `eval`. + paths: eval('module').paths.concat(process.cwd()) + } + ]); + return target.apply(thisArg, [modulePath]); + } + }, + get: (target, prop, receiver) => { + Reflect.get(target, prop, receiver); + } +}); + + /***/ }), /***/ 413: @@ -6121,12 +6158,16 @@ function callAsyncFunction(args, source) { return fn(...Object.values(args)); } +// EXTERNAL MODULE: ./src/wrap-require.ts +var wrap_require = __webpack_require__(366); + // CONCATENATED MODULE: ./src/main.ts + process.on('unhandledRejection', handleError); main().catch(handleError); async function main() { @@ -6144,7 +6185,15 @@ async function main() { const github = Object(lib_github.getOctokit)(token, opts); const script = Object(core.getInput)('script', { required: true }); // Using property/value shorthand on `require` (e.g. `{require}`) causes compilation errors. - const result = await callAsyncFunction({ require: __webpack_require__(875), github, context: lib_github.context, core: core, glob: glob, io: io }, script); + const result = await callAsyncFunction({ + require: wrap_require.wrapRequire, + __original_require__: require, + github, + context: lib_github.context, + core: core, + glob: glob, + io: io + }, script); let encoding = Object(core.getInput)('result-encoding'); encoding = encoding ? encoding : 'json'; let output; @@ -6901,25 +6950,6 @@ function expand(str, isTop) { -/***/ }), - -/***/ 875: -/***/ (function(module) { - -function webpackEmptyContext(req) { - if (typeof req === 'number' && __webpack_require__.m[req]) - return __webpack_require__(req); -try { return require(req) } -catch (e) { if (e.code !== 'MODULE_NOT_FOUND') throw e } -var e = new Error("Cannot find module '" + req + "'"); - e.code = 'MODULE_NOT_FOUND'; - throw e; -} -webpackEmptyContext.keys = function() { return []; }; -webpackEmptyContext.resolve = webpackEmptyContext; -module.exports = webpackEmptyContext; -webpackEmptyContext.id = 875; - /***/ }), /***/ 877: @@ -8743,14 +8773,15 @@ function regExpEscape (s) { /******/ function(__webpack_require__) { // webpackRuntimeModules /******/ "use strict"; /******/ -/******/ /* webpack/runtime/make namespace object */ +/******/ /* webpack/runtime/compat get default export */ /******/ !function() { -/******/ // define __esModule on exports -/******/ __webpack_require__.r = function(exports) { -/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { -/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); -/******/ } -/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; /******/ }; /******/ }(); /******/ @@ -8765,6 +8796,17 @@ function regExpEscape (s) { /******/ }; /******/ }(); /******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ !function() { +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ }(); +/******/ /******/ /* webpack/runtime/create fake namespace object */ /******/ !function() { /******/ // create a fake namespace object @@ -8784,17 +8826,5 @@ function regExpEscape (s) { /******/ }; /******/ }(); /******/ -/******/ /* webpack/runtime/compat get default export */ -/******/ !function() { -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ }(); -/******/ /******/ } ); \ No newline at end of file diff --git a/package.json b/package.json index 3e953650d..a68abc2ad 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "github-script", "description": "A GitHub action for executing a simple script", - "version": "3.1.1", + "version": "4.0.0", "author": "GitHub", "license": "MIT", "main": "dist/index.js", diff --git a/src/async-function.ts b/src/async-function.ts index 64d12abf2..7483414ed 100644 --- a/src/async-function.ts +++ b/src/async-function.ts @@ -13,6 +13,7 @@ type AsyncFunctionArguments = { glob: typeof glob io: typeof io require: NodeRequire + __original_require__: NodeRequire } export function callAsyncFunction( diff --git a/src/main.ts b/src/main.ts index dd47f2c22..c0668c626 100644 --- a/src/main.ts +++ b/src/main.ts @@ -3,6 +3,7 @@ import {context, getOctokit} from '@actions/github' import * as glob from '@actions/glob' import * as io from '@actions/io' import {callAsyncFunction} from './async-function' +import {wrapRequire} from './wrap-require' process.on('unhandledRejection', handleError) main().catch(handleError) @@ -29,7 +30,15 @@ async function main(): Promise { // Using property/value shorthand on `require` (e.g. `{require}`) causes compilation errors. const result = await callAsyncFunction( - {require: require, github, context, core, glob, io}, + { + require: wrapRequire, + __original_require__: __non_webpack_require__, + github, + context, + core, + glob, + io + }, script ) diff --git a/src/wrap-require.ts b/src/wrap-require.ts new file mode 100644 index 000000000..d7e45ef3f --- /dev/null +++ b/src/wrap-require.ts @@ -0,0 +1,29 @@ +import * as path from 'path' + +export const wrapRequire = new Proxy(__non_webpack_require__, { + apply: (target, thisArg, [moduleID]) => { + if (moduleID.startsWith('.')) { + moduleID = path.resolve(moduleID) + return target.apply(thisArg, [moduleID]) + } + + try { + return target.apply(thisArg, [moduleID]) + } catch (err) { + const modulePath = target.resolve.apply(thisArg, [ + moduleID, + { + // Webpack does not have an escape hatch for getting the actual + // module, other than `eval`. + paths: eval('module').paths.concat(process.cwd()) + } + ]) + + return target.apply(thisArg, [modulePath]) + } + }, + + get: (target, prop, receiver) => { + Reflect.get(target, prop, receiver) + } +}) diff --git a/types/non-webpack-require.ts b/types/non-webpack-require.ts new file mode 100644 index 000000000..71052e7a4 --- /dev/null +++ b/types/non-webpack-require.ts @@ -0,0 +1 @@ +declare const __non_webpack_require__: NodeRequire