mirror of
https://github.com/actions/github-script.git
synced 2026-06-07 01:24:24 +00:00
feat: add script-file input for lint-friendly external JS scripts
Closes #714 Inline `script` is a YAML string — invisible to linters and IDEs. The common workaround was wrapping a `require` call inside the inline script, which still needs boilerplate and assumes a path convention. New optional `script-file` input that accepts a path to a JS file. The file must `module.exports` an async function receiving the standard IoC dependency bag (`github`, `octokit`, `getOctokit`, `context`, `core`, `exec`, `glob`, `io`, `require`). ```yaml - uses: actions/checkout@v4 - uses: actions/github-script@v9 with: script-file: .github/scripts/my-script.js ``` `script` and `script-file` are mutually exclusive — exactly one must be provided. Relative paths resolve against `$GITHUB_WORKSPACE`; absolute paths are used as-is. - `action.yml` — adds `script-file` input; makes `script` optional - `src/script-file.ts` — path resolution and script loading logic - `src/args.ts` — `AsyncFunctionArguments` extracted from `async-function.ts` so neither execution path depends on the other - `src/main.ts` — mutual-exclusion validation; dispatches to the right execution path - `types/non-webpack-require.ts` — corrects `__non_webpack_require__` type from deprecated `NodeRequire` / wrong `NodeJS.RequireResolve` to `NodeJS.Require` - `__test__/script-file.test.ts` — 10 tests covering path resolution, arg forwarding, error cases - `README.md` — new `## Script file` section with usage, IoC bag table, path resolution rules - `.github/fixtures/script-file/` — fixture JS files for integration tests - `.github/workflows/integration.yml` — 10 new integration test jobs: happy path (relative path, absolute path, all IoC args, json/string encoding, require-in-file) and error cases (both inputs set, neither set, nonexistent file, non-function export, file:// protocol)
This commit is contained in:
parent
3a2844b7e9
commit
67c280d263
18 changed files with 519 additions and 97 deletions
104
README.md
104
README.md
|
|
@ -27,8 +27,9 @@ You are welcome to still raise bugs in this repo.
|
|||
|
||||
### This action
|
||||
|
||||
To use this action, provide an input named `script` that contains the body of an asynchronous JavaScript function call.
|
||||
The following arguments will be provided:
|
||||
To use this action, provide either a `script` input (the body of an async function, inline in your workflow YAML) or a `script-file` input (a path to a JS file that `module.exports` an async function). Exactly one of the two must be provided.
|
||||
|
||||
The following arguments are available to both forms:
|
||||
|
||||
- `github` A pre-authenticated
|
||||
[octokit/rest.js](https://octokit.github.io/rest.js) client with pagination plugins
|
||||
|
|
@ -201,6 +202,56 @@ By default, the following status codes will not be retried: `400, 401, 403, 404,
|
|||
|
||||
These retries are implemented using the [octokit/plugin-retry.js](https://github.com/octokit/plugin-retry.js) plugin. The retries use [exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff) to space out retries. ([source](https://github.com/octokit/plugin-retry.js/blob/9a2443746c350b3beedec35cf26e197ea318a261/src/error-request.ts#L13))
|
||||
|
||||
## Script file
|
||||
|
||||
Coding long JS logic in yaml is not linted as JS/TS.
|
||||
Instead of providing the `script` inline, you can use `script-file` to point to a JS file in your repository. The file must proide `module.exports` as an function (that may be async) — making it a proper module that linters and IDEs can fully analyse.
|
||||
|
||||
The action handler is called with a single [IoC](https://en.wikipedia.org/wiki/Inversion_of_control) dependency bag (defined in [`src/args.ts`](src/args.ts)). Its members are the same as those available to the inline `script`:
|
||||
|
||||
| Name | Description |
|
||||
| --- | --- |
|
||||
| `github` | Pre-authenticated [octokit/rest.js](https://octokit.github.io/rest.js) client |
|
||||
| `octokit` | Alias for `github` |
|
||||
| `getOctokit` | Factory for additional authenticated Octokit clients (see [Creating additional clients](#creating-additional-clients-with-getoctokit)) |
|
||||
| `context` | [Workflow run context](https://github.com/actions/toolkit/blob/main/packages/github/src/context.ts) |
|
||||
| `core` | [@actions/core](https://github.com/actions/toolkit/tree/main/packages/core) |
|
||||
| `exec` | [@actions/exec](https://github.com/actions/toolkit/tree/main/packages/exec) |
|
||||
| `glob` | [@actions/glob](https://github.com/actions/toolkit/tree/main/packages/glob) |
|
||||
| `io` | [@actions/io](https://github.com/actions/toolkit/tree/main/packages/io) |
|
||||
| `require` | Wrapped `require` that resolves relative paths and local `node_modules` |
|
||||
|
||||
**Path resolution:** relative paths are resolved against `$GITHUB_WORKSPACE`; absolute paths are used as-is. The `file://` protocol is not supported.
|
||||
|
||||
`script` and `script-file` are mutually exclusive — exactly one must be provided.
|
||||
|
||||
```yaml
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/github-script@v9
|
||||
with:
|
||||
script-file: .github/scripts/my-script.js
|
||||
```
|
||||
|
||||
The action handler:
|
||||
|
||||
JS: `.github/scripts/my-script.js`
|
||||
|
||||
```js
|
||||
module.exports = async ({github, context, core /* destructure what you need */}) => {
|
||||
// your logic here
|
||||
}
|
||||
```
|
||||
|
||||
or TS: `.github/scripts/my-script.ts`
|
||||
|
||||
```ts
|
||||
import type {AsyncFunctionArguments} from '@actions/github-script'
|
||||
|
||||
module.exports = async ({github, context, core /* destructure what you need */}: AsyncFunctionArguments) => {
|
||||
// your logic here
|
||||
}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Note that `github-token` is optional in this action, and the input is there
|
||||
|
|
@ -377,52 +428,19 @@ jobs:
|
|||
- uses: actions/checkout@v4
|
||||
- uses: actions/github-script@v9
|
||||
with:
|
||||
script: |
|
||||
const script = require('./path/to/script.js')
|
||||
console.log(script({github, context}))
|
||||
script-file: ./path/to/script.js
|
||||
|
||||
```
|
||||
|
||||
And then export a function from your module:
|
||||
|
||||
```javascript
|
||||
module.exports = ({github, context}) => {
|
||||
module.exports = ({github, context }) => {
|
||||
return context.payload.client_payload.value
|
||||
}
|
||||
```
|
||||
|
||||
Note that because you can't `require` things like the GitHub context or
|
||||
Actions Toolkit libraries, you'll want to pass them as arguments to your
|
||||
external function.
|
||||
|
||||
Additionally, you'll want to use the [checkout
|
||||
action](https://github.com/actions/checkout) to make sure your script file is
|
||||
available.
|
||||
|
||||
### Run a separate file with an async function
|
||||
|
||||
You can also use async functions in this manner, as long as you `await` it in
|
||||
the inline script.
|
||||
|
||||
In your workflow:
|
||||
|
||||
```yaml
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
echo-input:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/github-script@v9
|
||||
env:
|
||||
SHA: '${{env.parentSHA}}'
|
||||
with:
|
||||
script: |
|
||||
const script = require('./path/to/script.js')
|
||||
await script({github, context, core})
|
||||
```
|
||||
|
||||
And then export an async function from your module:
|
||||
The exported function may be async if you like:
|
||||
|
||||
```javascript
|
||||
module.exports = async ({github, context, core}) => {
|
||||
|
|
@ -436,6 +454,14 @@ module.exports = async ({github, context, core}) => {
|
|||
}
|
||||
```
|
||||
|
||||
Note that because you can't `require` things like the GitHub context or
|
||||
Actions Toolkit libraries, you'll want to accept them as arguments to your
|
||||
external function: Your action is called with an [IoC](https://en.wikipedia.org/wiki/Inversion_of_control) dependency bag - destructure from it whatever you need. Check the docs above in the **Script file** section.
|
||||
|
||||
Additionally, you'll want to use the [checkout
|
||||
action](https://github.com/actions/checkout) to make sure your script file is
|
||||
available.
|
||||
|
||||
### Use npm packages
|
||||
|
||||
Like importing your own files above, you can also use installed modules.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue