This commit is contained in:
osher 2026-04-26 09:06:35 +00:00 committed by GitHub
commit f805cf5885
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 519 additions and 97 deletions

View file

@ -0,0 +1,5 @@
module.exports = async ({github, octokit, getOctokit, context, core, exec, glob, io, require}) => {
return [github, octokit, getOctokit, context, core, exec, glob, io, require]
.map(arg => typeof arg)
.every(t => t === 'function' || t === 'object')
}

1
.github/fixtures/script-file/basic.js vendored Normal file
View file

@ -0,0 +1 @@
module.exports = async () => 'hello from script-file'

View file

@ -0,0 +1 @@
module.exports = async ({context}) => ({repo: context.repo.repo, owner: context.repo.owner})

View file

@ -0,0 +1 @@
module.exports = 42

View file

@ -0,0 +1 @@
module.exports = async ({require}) => require('./sibling-module').value

View file

@ -0,0 +1 @@
module.exports = {value: 'loaded-by-require'}

View file

@ -361,3 +361,174 @@ jobs:
echo $'::error::\u274C' "Expected base-url to equal '$expected', got $actual" echo $'::error::\u274C' "Expected base-url to equal '$expected', got $actual"
exit 1 exit 1
fi fi
test-script-file-basic:
name: 'Integration test: script-file - relative path, string return'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- id: act
uses: ./
with:
script-file: .github/fixtures/script-file/basic.js
result-encoding: string
- run: |
expected="hello from script-file"
if [[ "${{ steps.act.outputs.result }}" != "$expected" ]]; then
echo $'::error::❌' "Expected '$expected', got ${{ steps.act.outputs.result }}"
exit 1
fi
echo $'✅ Test passed' | tee -a $GITHUB_STEP_SUMMARY
test-script-file-absolute-path:
name: 'Integration test: script-file - absolute path'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- id: act
uses: ./
with:
script-file: ${{ github.workspace }}/.github/fixtures/script-file/basic.js
result-encoding: string
- run: |
expected="hello from script-file"
if [[ "${{ steps.act.outputs.result }}" != "$expected" ]]; then
echo $'::error::❌' "Expected '$expected', got ${{ steps.act.outputs.result }}"
exit 1
fi
echo $'✅ Test passed' | tee -a $GITHUB_STEP_SUMMARY
test-script-file-all-ioc-args:
name: 'Integration test: script-file - all IoC args available'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- id: act
uses: ./
with:
script-file: .github/fixtures/script-file/all-args.js
- run: |
if [[ "${{ steps.act.outputs.result }}" != "true" ]]; then
echo $'::error::❌' "Expected all IoC args to be present, got ${{ steps.act.outputs.result }}"
exit 1
fi
echo $'✅ Test passed' | tee -a $GITHUB_STEP_SUMMARY
test-script-file-result-encoding-json:
name: 'Integration test: script-file - result-encoding json'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- id: act
uses: ./
with:
script-file: .github/fixtures/script-file/json-return.js
- run: |
expected='{"repo":"${{ github.event.repository.name }}","owner":"${{ github.repository_owner }}"}'
if [[ "${{ steps.act.outputs.result }}" != "$expected" ]]; then
echo $'::error::❌' "Expected '$expected', got ${{ steps.act.outputs.result }}"
exit 1
fi
echo $'✅ Test passed' | tee -a $GITHUB_STEP_SUMMARY
test-script-file-require-in-file:
name: 'Integration test: script-file - require inside script file'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- id: act
uses: ./
with:
script-file: .github/fixtures/script-file/sibling-caller.js
result-encoding: string
- run: |
expected="loaded-by-require"
if [[ "${{ steps.act.outputs.result }}" != "$expected" ]]; then
echo $'::error::❌' "Expected '$expected', got ${{ steps.act.outputs.result }}"
exit 1
fi
echo $'✅ Test passed' | tee -a $GITHUB_STEP_SUMMARY
test-script-file-conflict-both:
name: 'Integration test: script-file - fails when both script and script-file are set'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- id: act
continue-on-error: true
uses: ./
with:
script: return 1
script-file: .github/fixtures/script-file/basic.js
- run: |
if [[ "${{ steps.act.outcome }}" != "failure" ]]; then
echo $'::error::❌' "Expected step to fail when both inputs are set"
exit 1
fi
echo $'✅ Test passed' | tee -a $GITHUB_STEP_SUMMARY
test-script-file-conflict-neither:
name: 'Integration test: script-file - fails when neither script nor script-file is set'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- id: act
continue-on-error: true
uses: ./
- run: |
if [[ "${{ steps.act.outcome }}" != "failure" ]]; then
echo $'::error::❌' "Expected step to fail when no input is set"
exit 1
fi
echo $'✅ Test passed' | tee -a $GITHUB_STEP_SUMMARY
test-script-file-nonexistent-file:
name: 'Integration test: script-file - fails on nonexistent file'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- id: act
continue-on-error: true
uses: ./
with:
script-file: .github/fixtures/script-file/does-not-exist.js
- run: |
if [[ "${{ steps.act.outcome }}" != "failure" ]]; then
echo $'::error::❌' "Expected step to fail for nonexistent file"
exit 1
fi
echo $'✅ Test passed' | tee -a $GITHUB_STEP_SUMMARY
test-script-file-non-function-export:
name: 'Integration test: script-file - fails when file does not export a function'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- id: act
continue-on-error: true
uses: ./
with:
script-file: .github/fixtures/script-file/not-a-function.js
- run: |
if [[ "${{ steps.act.outcome }}" != "failure" ]]; then
echo $'::error::❌' "Expected step to fail for non-function export"
exit 1
fi
echo $'✅ Test passed' | tee -a $GITHUB_STEP_SUMMARY
test-script-file-file-protocol-rejected:
name: 'Integration test: script-file - fails for file:// protocol'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- id: act
continue-on-error: true
uses: ./
with:
script-file: file://${{ github.workspace }}/.github/fixtures/script-file/basic.js
- run: |
if [[ "${{ steps.act.outcome }}" != "failure" ]]; then
echo $'::error::❌' "Expected step to fail for file:// protocol"
exit 1
fi
echo $'✅ Test passed' | tee -a $GITHUB_STEP_SUMMARY

104
README.md
View file

@ -27,8 +27,9 @@ You are welcome to still raise bugs in this repo.
### This action ### This action
To use this action, provide an input named `script` that contains the body of an asynchronous JavaScript function call. 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 will be provided:
The following arguments are available to both forms:
- `github` A pre-authenticated - `github` A pre-authenticated
[octokit/rest.js](https://octokit.github.io/rest.js) client with pagination plugins [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)) 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 ## Examples
Note that `github-token` is optional in this action, and the input is there 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/checkout@v4
- uses: actions/github-script@v9 - uses: actions/github-script@v9
with: with:
script: | script-file: ./path/to/script.js
const script = require('./path/to/script.js')
console.log(script({github, context}))
``` ```
And then export a function from your module: And then export a function from your module:
```javascript ```javascript
module.exports = ({github, context}) => { module.exports = ({github, context }) => {
return context.payload.client_payload.value return context.payload.client_payload.value
} }
``` ```
Note that because you can't `require` things like the GitHub context or The exported function may be async if you like:
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:
```javascript ```javascript
module.exports = async ({github, context, core}) => { 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 ### Use npm packages
Like importing your own files above, you can also use installed modules. Like importing your own files above, you can also use installed modules.

View file

@ -0,0 +1,133 @@
import * as path from 'node:path'
import * as os from 'node:os'
import * as fs from 'node:fs'
import {callScriptFile, resolveScriptFilePath} from '../src/script-file'
const fullArgs = {
github: {},
octokit: {},
getOctokit: () => null,
context: {},
core: {},
exec: {},
glob: {},
io: {},
// eslint-disable-next-line @typescript-eslint/no-require-imports
require: require,
// eslint-disable-next-line @typescript-eslint/no-require-imports
__original_require__: require
}
describe('resolveScriptFilePath', () => {
test('rejects file:// protocol', () => {
expect(() => resolveScriptFilePath('file:///some/path.js')).toThrow(
'"script-file" must not use the "file://" protocol'
)
})
test('returns absolute path as-is', () => {
const abs = '/absolute/path/to/script.js'
expect(resolveScriptFilePath(abs)).toEqual(abs)
})
test('resolves relative path against GITHUB_WORKSPACE when set', () => {
const original = process.env['GITHUB_WORKSPACE']
process.env['GITHUB_WORKSPACE'] = '/workspace'
try {
expect(resolveScriptFilePath('scripts/run.js')).toEqual(
'/workspace/scripts/run.js'
)
} finally {
if (original === undefined) {
delete process.env['GITHUB_WORKSPACE']
} else {
process.env['GITHUB_WORKSPACE'] = original
}
}
})
})
describe('callScriptFile', () => {
let tmpDir: string
beforeEach(() => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'github-script-test-'))
})
afterEach(() => {
fs.rmSync(tmpDir, {recursive: true, force: true})
})
test('calls the exported function with args', async () => {
const scriptPath = path.join(tmpDir, 'script.js')
fs.writeFileSync(
scriptPath,
'module.exports = async ({core}) => core.value'
)
const result = await callScriptFile(
{...fullArgs, core: {value: 42}} as never,
scriptPath,
// eslint-disable-next-line @typescript-eslint/no-require-imports
require
)
expect(result).toEqual(42)
})
test('forwards all injected args to the exported function', async () => {
const scriptPath = path.join(tmpDir, 'all-args.js')
fs.writeFileSync(
scriptPath,
`module.exports = async (args) => Object.keys(args).sort()`
)
const result = await callScriptFile(
fullArgs as never,
scriptPath,
// eslint-disable-next-line @typescript-eslint/no-require-imports
require
)
expect(result).toEqual(Object.keys(fullArgs).sort())
})
test('throws when file does not export a function', async () => {
const scriptPath = path.join(tmpDir, 'not-a-fn.js')
fs.writeFileSync(scriptPath, 'module.exports = 42')
await expect(
// eslint-disable-next-line @typescript-eslint/no-require-imports
callScriptFile(fullArgs as never, scriptPath, require)
).rejects.toThrow('"script-file" must export a function, got number')
})
test('throws when file does not exist', async () => {
const scriptPath = path.join(tmpDir, 'nonexistent.js')
await expect(
// eslint-disable-next-line @typescript-eslint/no-require-imports
callScriptFile(fullArgs as never, scriptPath, require)
).rejects.toThrow()
})
test('propagates rejection from the exported function', async () => {
const scriptPath = path.join(tmpDir, 'throws.js')
fs.writeFileSync(
scriptPath,
"module.exports = async () => { throw new Error('boom') }"
)
await expect(
// eslint-disable-next-line @typescript-eslint/no-require-imports
callScriptFile(fullArgs as never, scriptPath, require)
).rejects.toThrow('boom')
})
test('rejects file:// path before loading', async () => {
await expect(
// eslint-disable-next-line @typescript-eslint/no-require-imports
callScriptFile(fullArgs as never, 'file:///some/path.js', require)
).rejects.toThrow('"script-file" must not use the "file://" protocol')
})
})

View file

@ -6,8 +6,15 @@ branding:
icon: code icon: code
inputs: inputs:
script: script:
description: The script to run description: The script to run (mutually exclusive with script-file)
required: true required: false
script-file:
description: |
A path to a JS file that exports an action handler. (mutually exclusive with script)
Path may be absolute, or relative to your repo root.
The handler may be async.
The handler is called with an IoC bag with {context, core, exec, github, octokit, getOctokit, glob, io, require} - destructure what you need.
required: false
github-token: github-token:
description: The GitHub token used to create an authenticated client description: The GitHub token used to create an authenticated client
default: ${{ github.token }} default: ${{ github.token }}

36
dist/index.js vendored
View file

@ -65029,6 +65029,25 @@ function parseNumberArray(listString) {
// EXTERNAL MODULE: external "path" // EXTERNAL MODULE: external "path"
var external_path_ = __nccwpck_require__(1017); var external_path_ = __nccwpck_require__(1017);
;// CONCATENATED MODULE: ./src/script-file.ts
function resolveScriptFilePath(scriptFile) {
if (scriptFile.startsWith('file://')) {
throw new Error('"script-file" must not use the "file://" protocol');
}
return external_path_.isAbsolute(scriptFile)
? scriptFile
: external_path_.resolve(process.env['GITHUB_WORKSPACE'], scriptFile);
}
async function callScriptFile(args, scriptFile, requireFn) {
const resolvedPath = resolveScriptFilePath(scriptFile);
const scriptFn = requireFn(resolvedPath);
if (typeof scriptFn !== 'function') {
throw new Error(`"script-file" must export a function, got ${typeof scriptFn}`);
}
return scriptFn(args);
}
;// CONCATENATED MODULE: ./src/wrap-require.ts ;// CONCATENATED MODULE: ./src/wrap-require.ts
const wrapRequire = new Proxy(require, { const wrapRequire = new Proxy(require, {
@ -65065,6 +65084,7 @@ const wrapRequire = new Proxy(require, {
process.on('unhandledRejection', handleError); process.on('unhandledRejection', handleError);
main().catch(handleError); main().catch(handleError);
async function main() { async function main() {
@ -65091,13 +65111,20 @@ async function main() {
opts.baseUrl = baseUrl; opts.baseUrl = baseUrl;
} }
const github = getOctokit(token, opts, retry, requestLog); const github = getOctokit(token, opts, retry, requestLog);
const script = core.getInput('script', { required: true }); const scriptInline = core.getInput('script');
const scriptFile = core.getInput('script-file');
if (scriptInline && scriptFile) {
throw new Error('Only one of "script" or "script-file" may be provided, not both');
}
if (!scriptInline && !scriptFile) {
throw new Error('One of "script" or "script-file" must be provided');
}
// Wrap getOctokit so secondary clients inherit retry, logging, // Wrap getOctokit so secondary clients inherit retry, logging,
// orchestration ID, and the action's retries input. // orchestration ID, and the action's retries input.
// Deep-copy opts to prevent shared references with the primary client. // Deep-copy opts to prevent shared references with the primary client.
const configuredGetOctokit = createConfiguredGetOctokit(getOctokit, { ...opts, retry: { ...opts.retry }, request: { ...opts.request } }, retry, requestLog); const configuredGetOctokit = createConfiguredGetOctokit(getOctokit, { ...opts, retry: { ...opts.retry }, request: { ...opts.request } }, retry, requestLog);
// Using property/value shorthand on `require` (e.g. `{require}`) causes compilation errors. // Using property/value shorthand on `require` (e.g. `{require}`) causes compilation errors.
const result = await callAsyncFunction({ const args = {
require: wrapRequire, require: wrapRequire,
__original_require__: require, __original_require__: require,
github, github,
@ -65108,7 +65135,10 @@ async function main() {
exec: exec, exec: exec,
glob: glob, glob: glob,
io: io io: io
}, script); };
const result = scriptFile
? await callScriptFile(args, scriptFile, require)
: await callAsyncFunction(args, scriptInline);
let encoding = core.getInput('result-encoding'); let encoding = core.getInput('result-encoding');
encoding = encoding ? encoding : 'json'; encoding = encoding ? encoding : 'json';
let output; let output;

18
src/args.ts Normal file
View file

@ -0,0 +1,18 @@
import * as core from '@actions/core'
import * as exec from '@actions/exec'
import type {context, getOctokit} from '@actions/github'
import * as glob from '@actions/glob'
import * as io from '@actions/io'
export type AsyncFunctionArguments = {
context: typeof context
core: typeof core
github: ReturnType<typeof getOctokit>
octokit: ReturnType<typeof getOctokit>
getOctokit: typeof getOctokit
exec: typeof exec
glob: typeof glob
io: typeof io
require: NodeJS.Require
__original_require__: NodeJS.Require
}

View file

@ -1,24 +1,8 @@
import * as core from '@actions/core' import type {AsyncFunctionArguments} from './args'
import * as exec from '@actions/exec' export type {AsyncFunctionArguments}
import type {context, getOctokit} from '@actions/github'
import * as glob from '@actions/glob'
import * as io from '@actions/io'
const AsyncFunction = Object.getPrototypeOf(async () => null).constructor const AsyncFunction = Object.getPrototypeOf(async () => null).constructor
export declare type AsyncFunctionArguments = {
context: typeof context
core: typeof core
github: ReturnType<typeof getOctokit>
octokit: ReturnType<typeof getOctokit>
getOctokit: typeof getOctokit
exec: typeof exec
glob: typeof glob
io: typeof io
require: NodeRequire
__original_require__: NodeRequire
}
export function callAsyncFunction<T>( export function callAsyncFunction<T>(
args: AsyncFunctionArguments, args: AsyncFunctionArguments,
source: string source: string

View file

@ -10,6 +10,7 @@ import {RequestRequestOptions} from '@octokit/types'
import {callAsyncFunction} from './async-function' import {callAsyncFunction} from './async-function'
import {createConfiguredGetOctokit} from './create-configured-getoctokit' import {createConfiguredGetOctokit} from './create-configured-getoctokit'
import {RetryOptions, getRetryOptions, parseNumberArray} from './retry-options' import {RetryOptions, getRetryOptions, parseNumberArray} from './retry-options'
import {callScriptFile} from './script-file'
import {wrapRequire} from './wrap-require' import {wrapRequire} from './wrap-require'
process.on('unhandledRejection', handleError) process.on('unhandledRejection', handleError)
@ -58,7 +59,17 @@ async function main(): Promise<void> {
} }
const github = getOctokit(token, opts, retry, requestLog) const github = getOctokit(token, opts, retry, requestLog)
const script = core.getInput('script', {required: true}) const scriptInline = core.getInput('script')
const scriptFile = core.getInput('script-file')
if (scriptInline && scriptFile) {
throw new Error(
'Only one of "script" or "script-file" may be provided, not both'
)
}
if (!scriptInline && !scriptFile) {
throw new Error('One of "script" or "script-file" must be provided')
}
// Wrap getOctokit so secondary clients inherit retry, logging, // Wrap getOctokit so secondary clients inherit retry, logging,
// orchestration ID, and the action's retries input. // orchestration ID, and the action's retries input.
@ -71,21 +82,22 @@ async function main(): Promise<void> {
) )
// Using property/value shorthand on `require` (e.g. `{require}`) causes compilation errors. // Using property/value shorthand on `require` (e.g. `{require}`) causes compilation errors.
const result = await callAsyncFunction( const args = {
{ require: wrapRequire,
require: wrapRequire, __original_require__: __non_webpack_require__,
__original_require__: __non_webpack_require__, github,
github, octokit: github,
octokit: github, getOctokit: configuredGetOctokit,
getOctokit: configuredGetOctokit, context,
context, core,
core, exec,
exec, glob,
glob, io
io }
},
script const result = scriptFile
) ? await callScriptFile(args, scriptFile, __non_webpack_require__)
: await callAsyncFunction(args, scriptInline)
let encoding = core.getInput('result-encoding') let encoding = core.getInput('result-encoding')
encoding = encoding ? encoding : 'json' encoding = encoding ? encoding : 'json'

29
src/script-file.ts Normal file
View file

@ -0,0 +1,29 @@
import * as path from 'path'
import type {AsyncFunctionArguments} from './args'
export function resolveScriptFilePath(scriptFile: string): string {
if (scriptFile.startsWith('file://')) {
throw new Error('"script-file" must not use the "file://" protocol')
}
return path.isAbsolute(scriptFile)
? scriptFile
: path.resolve(process.env['GITHUB_WORKSPACE']!, scriptFile)
}
export async function callScriptFile(
args: AsyncFunctionArguments,
scriptFile: string,
requireFn: NodeJS.Require
): Promise<unknown> {
const resolvedPath = resolveScriptFilePath(scriptFile)
const scriptFn = requireFn(resolvedPath)
if (typeof scriptFn !== 'function') {
throw new Error(
`"script-file" must export a function, got ${typeof scriptFn}`
)
}
return scriptFn(args)
}

18
types/args.d.ts vendored Normal file
View file

@ -0,0 +1,18 @@
/// <reference types="node" />
import * as core from '@actions/core';
import * as exec from '@actions/exec';
import type { context, getOctokit } from '@actions/github';
import * as glob from '@actions/glob';
import * as io from '@actions/io';
export type AsyncFunctionArguments = {
context: typeof context;
core: typeof core;
github: ReturnType<typeof getOctokit>;
octokit: ReturnType<typeof getOctokit>;
getOctokit: typeof getOctokit;
exec: typeof exec;
glob: typeof glob;
io: typeof io;
require: NodeJS.Require;
__original_require__: NodeJS.Require;
};

View file

@ -1,19 +1,3 @@
/// <reference types="node" /> import type { AsyncFunctionArguments } from './args';
import * as core from '@actions/core'; export type { AsyncFunctionArguments };
import * as exec from '@actions/exec';
import type { context, getOctokit } from '@actions/github';
import * as glob from '@actions/glob';
import * as io from '@actions/io';
export declare type AsyncFunctionArguments = {
context: typeof context;
core: typeof core;
github: ReturnType<typeof getOctokit>;
octokit: ReturnType<typeof getOctokit>;
getOctokit: typeof getOctokit;
exec: typeof exec;
glob: typeof glob;
io: typeof io;
require: NodeRequire;
__original_require__: NodeRequire;
};
export declare function callAsyncFunction<T>(args: AsyncFunctionArguments, source: string): Promise<T>; export declare function callAsyncFunction<T>(args: AsyncFunctionArguments, source: string): Promise<T>;

View file

@ -1 +1 @@
declare const __non_webpack_require__: NodeRequire declare const __non_webpack_require__: NodeJS.Require