mirror of
https://github.com/actions/github-script.git
synced 2026-05-13 11:26:55 +00:00
Compare commits
22 Commits
v7.1.0
...
salmanmkc/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dae91cface | ||
|
|
450193c5ab | ||
|
|
b67a972797 | ||
|
|
c0078b2072 | ||
|
|
c36bdc0a3a | ||
|
|
b588811d63 | ||
|
|
135f4fc944 | ||
|
|
8a9be95424 | ||
|
|
728b23b52d | ||
|
|
f80dad6b51 | ||
|
|
baada7bb39 | ||
|
|
d053ab3e3c | ||
|
|
4389015762 | ||
|
|
6599b4813b | ||
|
|
ed597411d8 | ||
|
|
2dc352e4ba | ||
|
|
01e118c8d0 | ||
|
|
8b222ac82e | ||
|
|
adc0eeac99 | ||
|
|
20fe497b3f | ||
|
|
e7b7f222b1 | ||
|
|
2c81ba05f3 |
@@ -5,7 +5,7 @@ runs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '20.x'
|
node-version: '24.x'
|
||||||
cache: npm
|
cache: npm
|
||||||
|
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
|
|||||||
48
.github/workflows/integration.yml
vendored
48
.github/workflows/integration.yml
vendored
@@ -155,21 +155,51 @@ jobs:
|
|||||||
result-encoding: string
|
result-encoding: string
|
||||||
- run: |
|
- run: |
|
||||||
echo "- Validating user-agent default"
|
echo "- Validating user-agent default"
|
||||||
expected="actions/github-script octokit-core.js/"
|
ua="${{steps.user-agent-default.outputs.result}}"
|
||||||
if [[ "${{steps.user-agent-default.outputs.result}}" != "$expected"* ]]; then
|
if [[ "$ua" != "actions/github-script octokit-core.js/"* ]] && [[ "$ua" != "actions/github-script actions_orchestration_id/"* ]]; then
|
||||||
echo $'::error::\u274C' "Expected user-agent to start with '$expected', got ${{steps.user-agent-default.outputs.result}}"
|
echo $'::error::\u274C' "Expected user-agent to start with 'actions/github-script', got $ua"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo "- Validating user-agent set to a value"
|
echo "- Validating user-agent set to a value"
|
||||||
expected="foobar octokit-core.js/"
|
ua="${{steps.user-agent-set.outputs.result}}"
|
||||||
if [[ "${{steps.user-agent-set.outputs.result}}" != "$expected"* ]]; then
|
if [[ "$ua" != "foobar octokit-core.js/"* ]] && [[ "$ua" != "foobar actions_orchestration_id/"* ]]; then
|
||||||
echo $'::error::\u274C' "Expected user-agent to start with '$expected', got ${{steps.user-agent-set.outputs.result}}"
|
echo $'::error::\u274C' "Expected user-agent to start with 'foobar', got $ua"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo "- Validating user-agent set to an empty string"
|
echo "- Validating user-agent set to an empty string"
|
||||||
expected="octokit-core.js/"
|
ua="${{steps.user-agent-empty.outputs.result}}"
|
||||||
if [[ "${{steps.user-agent-empty.outputs.result}}" != "$expected"* ]]; then
|
if [[ "$ua" != "actions/github-script octokit-core.js/"* ]] && [[ "$ua" != "actions/github-script actions_orchestration_id/"* ]]; then
|
||||||
echo $'::error::\u274C' "Expected user-agent to start with '$expected', got ${{steps.user-agent-empty.outputs.result}}"
|
echo $'::error::\u274C' "Expected user-agent to start with 'actions/github-script', got $ua"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo $'\u2705 Test passed' | tee -a $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
test-get-octokit:
|
||||||
|
name: 'Integration test: getOctokit'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Create secondary client with getOctokit
|
||||||
|
uses: ./
|
||||||
|
id: secondary-client
|
||||||
|
env:
|
||||||
|
APP_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
script: |
|
||||||
|
const appOctokit = getOctokit(process.env.APP_TOKEN)
|
||||||
|
const {data} = await appOctokit.rest.repos.get({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo
|
||||||
|
})
|
||||||
|
|
||||||
|
return `${appOctokit !== github}:${data.full_name}`
|
||||||
|
result-encoding: string
|
||||||
|
- run: |
|
||||||
|
echo "- Validating secondary client output"
|
||||||
|
expected="true:${{ github.repository }}"
|
||||||
|
if [[ "${{steps.secondary-client.outputs.result}}" != "$expected" ]]; then
|
||||||
|
echo $'::error::\u274C' "Expected '$expected', got ${{steps.secondary-client.outputs.result}}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo $'\u2705 Test passed' | tee -a $GITHUB_STEP_SUMMARY
|
echo $'\u2705 Test passed' | tee -a $GITHUB_STEP_SUMMARY
|
||||||
|
|||||||
2
.licenses/npm/@types/node.dep.yml
generated
2
.licenses/npm/@types/node.dep.yml
generated
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: "@types/node"
|
name: "@types/node"
|
||||||
version: 20.9.0
|
version: 24.1.0
|
||||||
type: npm
|
type: npm
|
||||||
summary: TypeScript definitions for node
|
summary: TypeScript definitions for node
|
||||||
homepage: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node
|
homepage: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node
|
||||||
|
|||||||
6
.licenses/npm/undici-types.dep.yml
generated
6
.licenses/npm/undici-types.dep.yml
generated
@@ -1,15 +1,17 @@
|
|||||||
---
|
---
|
||||||
name: undici-types
|
name: undici-types
|
||||||
version: 5.26.5
|
version: 7.8.0
|
||||||
type: npm
|
type: npm
|
||||||
summary: A stand-alone types package for Undici
|
summary: A stand-alone types package for Undici
|
||||||
homepage: https://undici.nodejs.org
|
homepage: https://undici.nodejs.org
|
||||||
license: mit
|
license: mit
|
||||||
licenses:
|
licenses:
|
||||||
- sources: Auto-generated MIT license text
|
- sources: LICENSE
|
||||||
text: |
|
text: |
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) Matteo Collina and Undici contributors
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
in the Software without restriction, including without limitation the rights
|
in the Software without restriction, including without limitation the rights
|
||||||
|
|||||||
44
README.md
44
README.md
@@ -53,6 +53,14 @@ documentation.
|
|||||||
|
|
||||||
## Breaking Changes
|
## Breaking Changes
|
||||||
|
|
||||||
|
### V8
|
||||||
|
|
||||||
|
Version 8 of this action updated the runtime to Node 24 - https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#runs-for-javascript-actions
|
||||||
|
|
||||||
|
All scripts are now run with Node 24 instead of Node 20 and are affected by any breaking changes between Node 20 and 24.
|
||||||
|
|
||||||
|
**This requires a minimum Actions Runner version of [v2.327.1](https://github.com/actions/runner/releases/tag/v2.327.1)**
|
||||||
|
|
||||||
### V7
|
### V7
|
||||||
|
|
||||||
Version 7 of this action updated the runtime to Node 20 - https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#runs-for-javascript-actions
|
Version 7 of this action updated the runtime to Node 20 - https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#runs-for-javascript-actions
|
||||||
@@ -91,7 +99,7 @@ and potential `SyntaxError`s when the expression is not valid JavaScript code (p
|
|||||||
To pass inputs, set `env` vars on the action step and reference them in your script with `process.env`:
|
To pass inputs, set `env` vars on the action step and reference them in your script with `process.env`:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/github-script@v7
|
- uses: actions/github-script@v8
|
||||||
env:
|
env:
|
||||||
TITLE: ${{ github.event.pull_request.title }}
|
TITLE: ${{ github.event.pull_request.title }}
|
||||||
with:
|
with:
|
||||||
@@ -110,7 +118,7 @@ The return value of the script will be in the step's outputs under the
|
|||||||
"result" key.
|
"result" key.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/github-script@v7
|
- uses: actions/github-script@v8
|
||||||
id: set-result
|
id: set-result
|
||||||
with:
|
with:
|
||||||
script: return "Hello!"
|
script: return "Hello!"
|
||||||
@@ -129,7 +137,7 @@ output of a github-script step. For some workflows, string encoding is preferred
|
|||||||
`result-encoding` input:
|
`result-encoding` input:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/github-script@v7
|
- uses: actions/github-script@v8
|
||||||
id: my-script
|
id: my-script
|
||||||
with:
|
with:
|
||||||
result-encoding: string
|
result-encoding: string
|
||||||
@@ -141,7 +149,7 @@ output of a github-script step. For some workflows, string encoding is preferred
|
|||||||
By default, requests made with the `github` instance will not be retried. You can configure this with the `retries` option:
|
By default, requests made with the `github` instance will not be retried. You can configure this with the `retries` option:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/github-script@v7
|
- uses: actions/github-script@v8
|
||||||
id: my-script
|
id: my-script
|
||||||
with:
|
with:
|
||||||
result-encoding: string
|
result-encoding: string
|
||||||
@@ -159,7 +167,7 @@ In this example, request failures from `github.rest.issues.get()` will be retrie
|
|||||||
You can also configure which status codes should be exempt from retries via the `retry-exempt-status-codes` option:
|
You can also configure which status codes should be exempt from retries via the `retry-exempt-status-codes` option:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/github-script@v7
|
- uses: actions/github-script@v8
|
||||||
id: my-script
|
id: my-script
|
||||||
with:
|
with:
|
||||||
result-encoding: string
|
result-encoding: string
|
||||||
@@ -188,7 +196,7 @@ By default, github-script will use the token provided to your workflow.
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- name: View context attributes
|
- name: View context attributes
|
||||||
uses: actions/github-script@v7
|
uses: actions/github-script@v8
|
||||||
with:
|
with:
|
||||||
script: console.log(context)
|
script: console.log(context)
|
||||||
```
|
```
|
||||||
@@ -204,7 +212,7 @@ jobs:
|
|||||||
comment:
|
comment:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/github-script@v7
|
- uses: actions/github-script@v8
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
github.rest.issues.createComment({
|
github.rest.issues.createComment({
|
||||||
@@ -226,7 +234,7 @@ jobs:
|
|||||||
apply-label:
|
apply-label:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/github-script@v7
|
- uses: actions/github-script@v8
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
github.rest.issues.addLabels({
|
github.rest.issues.addLabels({
|
||||||
@@ -248,7 +256,7 @@ jobs:
|
|||||||
welcome:
|
welcome:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/github-script@v7
|
- uses: actions/github-script@v8
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
// Get a list of all issues created by the PR opener
|
// Get a list of all issues created by the PR opener
|
||||||
@@ -293,7 +301,7 @@ jobs:
|
|||||||
diff:
|
diff:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/github-script@v7
|
- uses: actions/github-script@v8
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const diff_url = context.payload.pull_request.diff_url
|
const diff_url = context.payload.pull_request.diff_url
|
||||||
@@ -317,7 +325,7 @@ jobs:
|
|||||||
list-issues:
|
list-issues:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/github-script@v7
|
- uses: actions/github-script@v8
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const query = `query($owner:String!, $name:String!, $label:String!) {
|
const query = `query($owner:String!, $name:String!, $label:String!) {
|
||||||
@@ -351,7 +359,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/github-script@v7
|
- uses: actions/github-script@v8
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const script = require('./path/to/script.js')
|
const script = require('./path/to/script.js')
|
||||||
@@ -389,7 +397,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/github-script@v7
|
- uses: actions/github-script@v8
|
||||||
env:
|
env:
|
||||||
SHA: '${{env.parentSHA}}'
|
SHA: '${{env.parentSHA}}'
|
||||||
with:
|
with:
|
||||||
@@ -433,7 +441,7 @@ jobs:
|
|||||||
- run: npm ci
|
- run: npm ci
|
||||||
# or one-off:
|
# or one-off:
|
||||||
- run: npm install execa
|
- run: npm install execa
|
||||||
- uses: actions/github-script@v7
|
- uses: actions/github-script@v8
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const execa = require('execa')
|
const execa = require('execa')
|
||||||
@@ -463,7 +471,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/github-script@v7
|
- uses: actions/github-script@v8
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const { default: printStuff } = await import('${{ github.workspace }}/src/print-stuff.js')
|
const { default: printStuff } = await import('${{ github.workspace }}/src/print-stuff.js')
|
||||||
@@ -507,7 +515,7 @@ jobs:
|
|||||||
apply-label:
|
apply-label:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/github-script@v7
|
- uses: actions/github-script@v8
|
||||||
with:
|
with:
|
||||||
github-token: ${{ secrets.MY_PAT }}
|
github-token: ${{ secrets.MY_PAT }}
|
||||||
script: |
|
script: |
|
||||||
@@ -531,7 +539,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/github-script@v7
|
- uses: actions/github-script@v8
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const exitCode = await exec.exec('echo', ['hello'])
|
const exitCode = await exec.exec('echo', ['hello'])
|
||||||
@@ -549,7 +557,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/github-script@v7
|
- uses: actions/github-script@v8
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const {
|
const {
|
||||||
|
|||||||
@@ -8,6 +8,94 @@ describe('callAsyncFunction', () => {
|
|||||||
expect(result).toEqual('bar')
|
expect(result).toEqual('bar')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('passes getOctokit through the script context', async () => {
|
||||||
|
const getOctokit = jest.fn().mockReturnValue('secondary-client')
|
||||||
|
|
||||||
|
const result = await callAsyncFunction(
|
||||||
|
{getOctokit} as any,
|
||||||
|
"return getOctokit('token')"
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(getOctokit).toHaveBeenCalledWith('token')
|
||||||
|
expect(result).toEqual('secondary-client')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('getOctokit creates client independent from github', async () => {
|
||||||
|
const github = {rest: {issues: 'primary'}}
|
||||||
|
const getOctokit = jest.fn().mockReturnValue({rest: {issues: 'secondary'}})
|
||||||
|
|
||||||
|
const result = await callAsyncFunction(
|
||||||
|
{github, getOctokit} as any,
|
||||||
|
`
|
||||||
|
const secondary = getOctokit('other-token')
|
||||||
|
return {
|
||||||
|
primary: github.rest.issues,
|
||||||
|
secondary: secondary.rest.issues,
|
||||||
|
different: github !== secondary
|
||||||
|
}
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
primary: 'primary',
|
||||||
|
secondary: 'secondary',
|
||||||
|
different: true
|
||||||
|
})
|
||||||
|
expect(getOctokit).toHaveBeenCalledWith('other-token')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('getOctokit passes options through', async () => {
|
||||||
|
const getOctokit = jest.fn().mockReturnValue('client-with-opts')
|
||||||
|
|
||||||
|
const result = await callAsyncFunction(
|
||||||
|
{getOctokit} as any,
|
||||||
|
`return getOctokit('my-token', { baseUrl: 'https://ghes.example.com/api/v3' })`
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(getOctokit).toHaveBeenCalledWith('my-token', {
|
||||||
|
baseUrl: 'https://ghes.example.com/api/v3'
|
||||||
|
})
|
||||||
|
expect(result).toEqual('client-with-opts')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('getOctokit supports plugins', async () => {
|
||||||
|
const getOctokit = jest.fn().mockReturnValue('client-with-plugins')
|
||||||
|
|
||||||
|
const result = await callAsyncFunction(
|
||||||
|
{getOctokit} as any,
|
||||||
|
`return getOctokit('my-token', { previews: ['v3'] }, 'pluginA', 'pluginB')`
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(getOctokit).toHaveBeenCalledWith(
|
||||||
|
'my-token',
|
||||||
|
{previews: ['v3']},
|
||||||
|
'pluginA',
|
||||||
|
'pluginB'
|
||||||
|
)
|
||||||
|
expect(result).toEqual('client-with-plugins')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('multiple getOctokit calls produce independent clients', async () => {
|
||||||
|
const getOctokit = jest
|
||||||
|
.fn()
|
||||||
|
.mockReturnValueOnce({id: 'client-a'})
|
||||||
|
.mockReturnValueOnce({id: 'client-b'})
|
||||||
|
|
||||||
|
const result = await callAsyncFunction(
|
||||||
|
{getOctokit} as any,
|
||||||
|
`
|
||||||
|
const a = getOctokit('token-a')
|
||||||
|
const b = getOctokit('token-b')
|
||||||
|
return { a: a.id, b: b.id, different: a !== b }
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(getOctokit).toHaveBeenCalledTimes(2)
|
||||||
|
expect(getOctokit).toHaveBeenNthCalledWith(1, 'token-a')
|
||||||
|
expect(getOctokit).toHaveBeenNthCalledWith(2, 'token-b')
|
||||||
|
expect(result).toEqual({a: 'client-a', b: 'client-b', different: true})
|
||||||
|
})
|
||||||
|
|
||||||
test('throws on ReferenceError', async () => {
|
test('throws on ReferenceError', async () => {
|
||||||
expect.assertions(1)
|
expect.assertions(1)
|
||||||
|
|
||||||
|
|||||||
268
__test__/create-configured-getoctokit.test.ts
Normal file
268
__test__/create-configured-getoctokit.test.ts
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
|
||||||
|
import {createConfiguredGetOctokit} from '../src/create-configured-getoctokit'
|
||||||
|
|
||||||
|
describe('createConfiguredGetOctokit', () => {
|
||||||
|
const mockRetryPlugin = jest.fn()
|
||||||
|
const mockRequestLogPlugin = jest.fn()
|
||||||
|
|
||||||
|
function makeMockGetOctokit() {
|
||||||
|
return jest.fn().mockReturnValue('mock-client')
|
||||||
|
}
|
||||||
|
|
||||||
|
test('passes token and merged defaults to underlying getOctokit', () => {
|
||||||
|
const raw = makeMockGetOctokit()
|
||||||
|
const defaults = {
|
||||||
|
userAgent: 'actions/github-script actions_orchestration_id/abc',
|
||||||
|
retry: {enabled: true},
|
||||||
|
request: {retries: 3}
|
||||||
|
}
|
||||||
|
|
||||||
|
const wrapped = createConfiguredGetOctokit(
|
||||||
|
raw as any,
|
||||||
|
defaults,
|
||||||
|
mockRetryPlugin,
|
||||||
|
mockRequestLogPlugin
|
||||||
|
)
|
||||||
|
wrapped('my-token' as any)
|
||||||
|
|
||||||
|
expect(raw).toHaveBeenCalledWith(
|
||||||
|
'my-token',
|
||||||
|
expect.objectContaining({
|
||||||
|
userAgent: 'actions/github-script actions_orchestration_id/abc',
|
||||||
|
retry: {enabled: true},
|
||||||
|
request: {retries: 3}
|
||||||
|
}),
|
||||||
|
mockRetryPlugin,
|
||||||
|
mockRequestLogPlugin
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('user options override top-level defaults', () => {
|
||||||
|
const raw = makeMockGetOctokit()
|
||||||
|
const defaults = {
|
||||||
|
userAgent: 'default-agent',
|
||||||
|
previews: ['v3']
|
||||||
|
}
|
||||||
|
|
||||||
|
const wrapped = createConfiguredGetOctokit(raw as any, defaults)
|
||||||
|
wrapped('tok' as any, {userAgent: 'custom-agent'} as any)
|
||||||
|
|
||||||
|
expect(raw).toHaveBeenCalledWith(
|
||||||
|
'tok',
|
||||||
|
expect.objectContaining({userAgent: 'custom-agent', previews: ['v3']})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('deep-merges request so partial overrides preserve retries', () => {
|
||||||
|
const raw = makeMockGetOctokit()
|
||||||
|
const defaults = {
|
||||||
|
request: {retries: 3, agent: 'proxy-agent', fetch: 'proxy-fetch'}
|
||||||
|
}
|
||||||
|
|
||||||
|
const wrapped = createConfiguredGetOctokit(raw as any, defaults)
|
||||||
|
wrapped('tok' as any, {request: {timeout: 5000}} as any)
|
||||||
|
|
||||||
|
expect(raw).toHaveBeenCalledWith(
|
||||||
|
'tok',
|
||||||
|
expect.objectContaining({
|
||||||
|
request: {
|
||||||
|
retries: 3,
|
||||||
|
agent: 'proxy-agent',
|
||||||
|
fetch: 'proxy-fetch',
|
||||||
|
timeout: 5000
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('deep-merges retry so partial overrides preserve existing settings', () => {
|
||||||
|
const raw = makeMockGetOctokit()
|
||||||
|
const defaults = {
|
||||||
|
retry: {enabled: true, retries: 3}
|
||||||
|
}
|
||||||
|
|
||||||
|
const wrapped = createConfiguredGetOctokit(raw as any, defaults)
|
||||||
|
wrapped('tok' as any, {retry: {retries: 5}} as any)
|
||||||
|
|
||||||
|
expect(raw).toHaveBeenCalledWith(
|
||||||
|
'tok',
|
||||||
|
expect.objectContaining({
|
||||||
|
retry: {enabled: true, retries: 5}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('user can override request.retries explicitly', () => {
|
||||||
|
const raw = makeMockGetOctokit()
|
||||||
|
const defaults = {request: {retries: 3}}
|
||||||
|
|
||||||
|
const wrapped = createConfiguredGetOctokit(raw as any, defaults)
|
||||||
|
wrapped('tok' as any, {request: {retries: 0}} as any)
|
||||||
|
|
||||||
|
expect(raw).toHaveBeenCalledWith(
|
||||||
|
'tok',
|
||||||
|
expect.objectContaining({request: {retries: 0}})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('user plugins are appended after default plugins', () => {
|
||||||
|
const raw = makeMockGetOctokit()
|
||||||
|
const customPlugin = jest.fn()
|
||||||
|
|
||||||
|
const wrapped = createConfiguredGetOctokit(
|
||||||
|
raw as any,
|
||||||
|
{},
|
||||||
|
mockRetryPlugin,
|
||||||
|
mockRequestLogPlugin
|
||||||
|
)
|
||||||
|
wrapped('tok' as any, {} as any, customPlugin as any)
|
||||||
|
|
||||||
|
expect(raw).toHaveBeenCalledWith(
|
||||||
|
'tok',
|
||||||
|
expect.any(Object),
|
||||||
|
mockRetryPlugin,
|
||||||
|
mockRequestLogPlugin,
|
||||||
|
customPlugin
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('duplicate plugins are deduplicated', () => {
|
||||||
|
const raw = makeMockGetOctokit()
|
||||||
|
|
||||||
|
const wrapped = createConfiguredGetOctokit(
|
||||||
|
raw as any,
|
||||||
|
{},
|
||||||
|
mockRetryPlugin,
|
||||||
|
mockRequestLogPlugin
|
||||||
|
)
|
||||||
|
// User passes retry again — should not duplicate
|
||||||
|
wrapped('tok' as any, {} as any, mockRetryPlugin as any)
|
||||||
|
|
||||||
|
expect(raw).toHaveBeenCalledWith(
|
||||||
|
'tok',
|
||||||
|
expect.any(Object),
|
||||||
|
mockRetryPlugin,
|
||||||
|
mockRequestLogPlugin
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('applies defaults when no user options provided', () => {
|
||||||
|
const raw = makeMockGetOctokit()
|
||||||
|
const defaults = {
|
||||||
|
userAgent: 'actions/github-script',
|
||||||
|
retry: {enabled: true},
|
||||||
|
request: {retries: 3}
|
||||||
|
}
|
||||||
|
|
||||||
|
const wrapped = createConfiguredGetOctokit(
|
||||||
|
raw as any,
|
||||||
|
defaults,
|
||||||
|
mockRetryPlugin
|
||||||
|
)
|
||||||
|
wrapped('tok' as any)
|
||||||
|
|
||||||
|
expect(raw).toHaveBeenCalledWith(
|
||||||
|
'tok',
|
||||||
|
{
|
||||||
|
userAgent: 'actions/github-script',
|
||||||
|
retry: {enabled: true},
|
||||||
|
request: {retries: 3}
|
||||||
|
},
|
||||||
|
mockRetryPlugin
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('baseUrl: undefined from user does not clobber default', () => {
|
||||||
|
const raw = makeMockGetOctokit()
|
||||||
|
const defaults = {baseUrl: 'https://ghes.example.com/api/v3'}
|
||||||
|
|
||||||
|
const wrapped = createConfiguredGetOctokit(raw as any, defaults)
|
||||||
|
wrapped('tok' as any, {baseUrl: undefined} as any)
|
||||||
|
|
||||||
|
const calledOpts = raw.mock.calls[0][1]
|
||||||
|
expect(calledOpts.baseUrl).toBe('https://ghes.example.com/api/v3')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('undefined values in nested request are stripped', () => {
|
||||||
|
const raw = makeMockGetOctokit()
|
||||||
|
const defaults = {request: {retries: 3, agent: 'proxy'}}
|
||||||
|
|
||||||
|
const wrapped = createConfiguredGetOctokit(raw as any, defaults)
|
||||||
|
wrapped('tok' as any, {request: {retries: undefined, timeout: 5000}} as any)
|
||||||
|
|
||||||
|
const calledOpts = raw.mock.calls[0][1]
|
||||||
|
expect(calledOpts.request).toEqual({
|
||||||
|
retries: 3,
|
||||||
|
agent: 'proxy',
|
||||||
|
timeout: 5000
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('undefined values in nested retry are stripped', () => {
|
||||||
|
const raw = makeMockGetOctokit()
|
||||||
|
const defaults = {retry: {enabled: true, retries: 3}}
|
||||||
|
|
||||||
|
const wrapped = createConfiguredGetOctokit(raw as any, defaults)
|
||||||
|
wrapped('tok' as any, {retry: {enabled: undefined, retries: 5}} as any)
|
||||||
|
|
||||||
|
const calledOpts = raw.mock.calls[0][1]
|
||||||
|
expect(calledOpts.retry).toEqual({enabled: true, retries: 5})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('each call creates an independent client', () => {
|
||||||
|
const raw = jest
|
||||||
|
.fn()
|
||||||
|
.mockReturnValueOnce('client-a')
|
||||||
|
.mockReturnValueOnce('client-b')
|
||||||
|
|
||||||
|
const wrapped = createConfiguredGetOctokit(raw as any, {})
|
||||||
|
const a = wrapped('token-a' as any)
|
||||||
|
const b = wrapped('token-b' as any)
|
||||||
|
|
||||||
|
expect(a).toBe('client-a')
|
||||||
|
expect(b).toBe('client-b')
|
||||||
|
expect(raw).toHaveBeenCalledTimes(2)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('does not mutate defaultOptions between calls', () => {
|
||||||
|
const raw = makeMockGetOctokit()
|
||||||
|
const defaults = {
|
||||||
|
request: {retries: 3},
|
||||||
|
retry: {enabled: true}
|
||||||
|
}
|
||||||
|
const originalDefaults = JSON.parse(JSON.stringify(defaults))
|
||||||
|
|
||||||
|
const wrapped = createConfiguredGetOctokit(raw as any, defaults)
|
||||||
|
wrapped(
|
||||||
|
'tok' as any,
|
||||||
|
{request: {timeout: 5000}, retry: {retries: 10}} as any
|
||||||
|
)
|
||||||
|
wrapped('tok' as any, {request: {timeout: 9000}} as any)
|
||||||
|
|
||||||
|
expect(defaults).toEqual(originalDefaults)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('falsy-but-valid values are preserved, only undefined is stripped', () => {
|
||||||
|
const raw = makeMockGetOctokit()
|
||||||
|
const defaults = {baseUrl: 'https://ghes.example.com/api/v3'}
|
||||||
|
|
||||||
|
const wrapped = createConfiguredGetOctokit(raw as any, defaults)
|
||||||
|
wrapped(
|
||||||
|
'tok' as any,
|
||||||
|
{
|
||||||
|
log: null,
|
||||||
|
retries: 0,
|
||||||
|
debug: false,
|
||||||
|
userAgent: ''
|
||||||
|
} as any
|
||||||
|
)
|
||||||
|
|
||||||
|
const calledOpts = raw.mock.calls[0][1]
|
||||||
|
expect(calledOpts.log).toBeNull()
|
||||||
|
expect(calledOpts.retries).toBe(0)
|
||||||
|
expect(calledOpts.debug).toBe(false)
|
||||||
|
expect(calledOpts.userAgent).toBe('')
|
||||||
|
expect(calledOpts.baseUrl).toBe('https://ghes.example.com/api/v3')
|
||||||
|
})
|
||||||
|
})
|
||||||
102
__test__/getoctokit-integration.test.ts
Normal file
102
__test__/getoctokit-integration.test.ts
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
|
||||||
|
import {callAsyncFunction} from '../src/async-function'
|
||||||
|
|
||||||
|
// Create a mock getOctokit that returns Octokit-like objects.
|
||||||
|
// Real @actions/github integration is tested in the CI workflow
|
||||||
|
// (integration.yml test-get-octokit job). Here we verify the
|
||||||
|
// script context wiring — getOctokit is passed through and
|
||||||
|
// callable from user scripts.
|
||||||
|
function mockGetOctokit(token: string, options?: any) {
|
||||||
|
return {
|
||||||
|
_token: token,
|
||||||
|
_options: options,
|
||||||
|
rest: {
|
||||||
|
issues: {get: async () => ({data: {id: 1}})},
|
||||||
|
pulls: {get: async () => ({data: {id: 2}})}
|
||||||
|
},
|
||||||
|
graphql: async () => ({}),
|
||||||
|
request: async () => ({})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('getOctokit integration via callAsyncFunction', () => {
|
||||||
|
test('getOctokit creates a functional client in script scope', async () => {
|
||||||
|
const result = await callAsyncFunction(
|
||||||
|
{getOctokit: mockGetOctokit} as any,
|
||||||
|
`
|
||||||
|
const client = getOctokit('fake-token-for-test')
|
||||||
|
return {
|
||||||
|
hasRest: typeof client.rest === 'object',
|
||||||
|
hasGraphql: typeof client.graphql === 'function',
|
||||||
|
hasRequest: typeof client.request === 'function',
|
||||||
|
hasIssues: typeof client.rest.issues === 'object',
|
||||||
|
hasPulls: typeof client.rest.pulls === 'object'
|
||||||
|
}
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
hasRest: true,
|
||||||
|
hasGraphql: true,
|
||||||
|
hasRequest: true,
|
||||||
|
hasIssues: true,
|
||||||
|
hasPulls: true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('secondary client is independent from primary github client', async () => {
|
||||||
|
const primary = mockGetOctokit('primary-token')
|
||||||
|
|
||||||
|
const result = await callAsyncFunction(
|
||||||
|
{github: primary, getOctokit: mockGetOctokit} as any,
|
||||||
|
`
|
||||||
|
const secondary = getOctokit('secondary-token')
|
||||||
|
return {
|
||||||
|
bothHaveRest: typeof github.rest === 'object' && typeof secondary.rest === 'object',
|
||||||
|
areDistinct: github !== secondary
|
||||||
|
}
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
bothHaveRest: true,
|
||||||
|
areDistinct: true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('getOctokit accepts options for GHES base URL', async () => {
|
||||||
|
const result = await callAsyncFunction(
|
||||||
|
{getOctokit: mockGetOctokit} as any,
|
||||||
|
`
|
||||||
|
const client = getOctokit('fake-token', {
|
||||||
|
baseUrl: 'https://ghes.example.com/api/v3'
|
||||||
|
})
|
||||||
|
return typeof client.rest === 'object'
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(result).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('multiple getOctokit calls produce independent clients with different tokens', async () => {
|
||||||
|
const result = await callAsyncFunction(
|
||||||
|
{getOctokit: mockGetOctokit} as any,
|
||||||
|
`
|
||||||
|
const clientA = getOctokit('token-a')
|
||||||
|
const clientB = getOctokit('token-b')
|
||||||
|
return {
|
||||||
|
aHasRest: typeof clientA.rest === 'object',
|
||||||
|
bHasRest: typeof clientB.rest === 'object',
|
||||||
|
areDistinct: clientA !== clientB
|
||||||
|
}
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
aHasRest: true,
|
||||||
|
bHasRest: true,
|
||||||
|
areDistinct: true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -36,5 +36,5 @@ outputs:
|
|||||||
result:
|
result:
|
||||||
description: The return value of the script, stringified with `JSON.stringify`
|
description: The return value of the script, stringified with `JSON.stringify`
|
||||||
runs:
|
runs:
|
||||||
using: node20
|
using: node24
|
||||||
main: dist/index.js
|
main: dist/index.js
|
||||||
|
|||||||
57
dist/index.js
vendored
57
dist/index.js
vendored
@@ -36188,6 +36188,42 @@ function callAsyncFunction(args, source) {
|
|||||||
return fn(...Object.values(args));
|
return fn(...Object.values(args));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
;// CONCATENATED MODULE: ./src/create-configured-getoctokit.ts
|
||||||
|
function stripUndefined(obj) {
|
||||||
|
const result = {};
|
||||||
|
for (const [key, value] of Object.entries(obj)) {
|
||||||
|
if (value !== undefined) {
|
||||||
|
;
|
||||||
|
result[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
function createConfiguredGetOctokit(rawGetOctokit, defaultOptions, ...defaultPlugins) {
|
||||||
|
return (token, options, ...additionalPlugins) => {
|
||||||
|
const userOpts = stripUndefined(options || {});
|
||||||
|
const defaultRequest = defaultOptions.request;
|
||||||
|
const userRequestRaw = userOpts.request;
|
||||||
|
const userRequest = userRequestRaw ? stripUndefined(userRequestRaw) : {};
|
||||||
|
const defaultRetry = defaultOptions.retry;
|
||||||
|
const userRetryRaw = userOpts.retry;
|
||||||
|
const userRetry = userRetryRaw ? stripUndefined(userRetryRaw) : {};
|
||||||
|
const merged = {
|
||||||
|
...defaultOptions,
|
||||||
|
...userOpts,
|
||||||
|
request: { ...(defaultRequest || {}), ...userRequest },
|
||||||
|
retry: { ...(defaultRetry || {}), ...userRetry }
|
||||||
|
};
|
||||||
|
const allPlugins = [...defaultPlugins];
|
||||||
|
for (const plugin of additionalPlugins) {
|
||||||
|
if (!allPlugins.includes(plugin)) {
|
||||||
|
allPlugins.push(plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rawGetOctokit(token, merged, ...allPlugins);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
;// CONCATENATED MODULE: ./src/retry-options.ts
|
;// CONCATENATED MODULE: ./src/retry-options.ts
|
||||||
|
|
||||||
function getRetryOptions(retries, exemptStatusCodes, defaultOptions) {
|
function getRetryOptions(retries, exemptStatusCodes, defaultOptions) {
|
||||||
@@ -36256,6 +36292,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() {
|
||||||
@@ -36267,9 +36304,11 @@ async function main() {
|
|||||||
const retries = parseInt(core.getInput('retries'));
|
const retries = parseInt(core.getInput('retries'));
|
||||||
const exemptStatusCodes = parseNumberArray(core.getInput('retry-exempt-status-codes'));
|
const exemptStatusCodes = parseNumberArray(core.getInput('retry-exempt-status-codes'));
|
||||||
const [retryOpts, requestOpts] = getRetryOptions(retries, exemptStatusCodes, utils.defaults);
|
const [retryOpts, requestOpts] = getRetryOptions(retries, exemptStatusCodes, utils.defaults);
|
||||||
|
const baseUserAgent = userAgent || 'actions/github-script';
|
||||||
|
const finalUserAgent = getUserAgentWithOrchestrationId(baseUserAgent);
|
||||||
const opts = {
|
const opts = {
|
||||||
log: debug ? console : undefined,
|
log: debug ? console : undefined,
|
||||||
userAgent: userAgent || undefined,
|
userAgent: finalUserAgent,
|
||||||
previews: previews ? previews.split(',') : undefined,
|
previews: previews ? previews.split(',') : undefined,
|
||||||
retry: retryOpts,
|
retry: retryOpts,
|
||||||
request: requestOpts
|
request: requestOpts
|
||||||
@@ -36281,12 +36320,14 @@ async function main() {
|
|||||||
}
|
}
|
||||||
const github = (0,lib_github.getOctokit)(token, opts, plugin_retry_dist_node.retry, dist_node.requestLog);
|
const github = (0,lib_github.getOctokit)(token, opts, plugin_retry_dist_node.retry, dist_node.requestLog);
|
||||||
const script = core.getInput('script', { required: true });
|
const script = core.getInput('script', { required: true });
|
||||||
|
const configuredGetOctokit = createConfiguredGetOctokit(lib_github.getOctokit, opts, plugin_retry_dist_node.retry, dist_node.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 result = await callAsyncFunction({
|
||||||
require: wrapRequire,
|
require: wrapRequire,
|
||||||
__original_require__: require,
|
__original_require__: require,
|
||||||
github,
|
github,
|
||||||
octokit: github,
|
octokit: github,
|
||||||
|
getOctokit: configuredGetOctokit,
|
||||||
context: lib_github.context,
|
context: lib_github.context,
|
||||||
core: core,
|
core: core,
|
||||||
exec: exec,
|
exec: exec,
|
||||||
@@ -36313,6 +36354,20 @@ function handleError(err) {
|
|||||||
console.error(err);
|
console.error(err);
|
||||||
core.setFailed(`Unhandled error: ${err}`);
|
core.setFailed(`Unhandled error: ${err}`);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Gets the user agent string with orchestration ID appended if available
|
||||||
|
* @param userAgent The base user agent string
|
||||||
|
* @returns The user agent string with orchestration ID appended if ACTIONS_ORCHESTRATION_ID is set
|
||||||
|
*/
|
||||||
|
function getUserAgentWithOrchestrationId(userAgent) {
|
||||||
|
const orchestrationId = process.env['ACTIONS_ORCHESTRATION_ID'];
|
||||||
|
if (!orchestrationId) {
|
||||||
|
return userAgent;
|
||||||
|
}
|
||||||
|
// Sanitize orchestration ID - replace invalid characters with underscore
|
||||||
|
const sanitized = orchestrationId.replace(/[^a-zA-Z0-9._-]/g, '_');
|
||||||
|
return `${userAgent} actions_orchestration_id/${sanitized}`;
|
||||||
|
}
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|||||||
34
package-lock.json
generated
34
package-lock.json
generated
@@ -17,7 +17,7 @@
|
|||||||
"@octokit/core": "^5.0.1",
|
"@octokit/core": "^5.0.1",
|
||||||
"@octokit/plugin-request-log": "^4.0.0",
|
"@octokit/plugin-request-log": "^4.0.0",
|
||||||
"@octokit/plugin-retry": "^6.0.1",
|
"@octokit/plugin-retry": "^6.0.1",
|
||||||
"@types/node": "^20.9.0"
|
"@types/node": "^24.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^29.5.5",
|
"@types/jest": "^29.5.5",
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
"typescript": "^5.2.2"
|
"typescript": "^5.2.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20.0.0 <21.0.0"
|
"node": ">=24"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aashutoshrathi/word-wrap": {
|
"node_modules/@aashutoshrathi/word-wrap": {
|
||||||
@@ -1672,11 +1672,12 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "20.9.0",
|
"version": "24.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.1.0.tgz",
|
||||||
"integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==",
|
"integrity": "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~5.26.4"
|
"undici-types": "~7.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/semver": {
|
"node_modules/@types/semver": {
|
||||||
@@ -7113,9 +7114,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/undici-types": {
|
"node_modules/undici-types": {
|
||||||
"version": "5.26.5",
|
"version": "7.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz",
|
||||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
|
"integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/universal-user-agent": {
|
"node_modules/universal-user-agent": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
@@ -8652,11 +8654,11 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "20.9.0",
|
"version": "24.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.1.0.tgz",
|
||||||
"integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==",
|
"integrity": "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"undici-types": "~5.26.4"
|
"undici-types": "~7.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/semver": {
|
"@types/semver": {
|
||||||
@@ -12542,9 +12544,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"undici-types": {
|
"undici-types": {
|
||||||
"version": "5.26.5",
|
"version": "7.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz",
|
||||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
|
"integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="
|
||||||
},
|
},
|
||||||
"universal-user-agent": {
|
"universal-user-agent": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/github-script",
|
"name": "@actions/github-script",
|
||||||
"description": "A GitHub action for executing a simple script",
|
"description": "A GitHub action for executing a simple script",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=24"
|
||||||
|
},
|
||||||
"version": "7.0.1",
|
"version": "7.0.1",
|
||||||
"author": "GitHub",
|
"author": "GitHub",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"types": "types/async-function.d.ts",
|
"types": "types/async-function.d.ts",
|
||||||
"private": true,
|
|
||||||
"engines": {
|
|
||||||
"node": ">=20.0.0 <21.0.0"
|
|
||||||
},
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "npm run build:types && ncc build src/main.ts",
|
"build": "npm run build:types && ncc build src/main.ts",
|
||||||
"build:types": "tsc src/async-function.ts -t es5 --declaration --allowJs --emitDeclarationOnly --outDir types",
|
"build:types": "tsc src/async-function.ts -t es5 --declaration --allowJs --emitDeclarationOnly --outDir types",
|
||||||
@@ -47,7 +46,7 @@
|
|||||||
"@octokit/core": "^5.0.1",
|
"@octokit/core": "^5.0.1",
|
||||||
"@octokit/plugin-request-log": "^4.0.0",
|
"@octokit/plugin-request-log": "^4.0.0",
|
||||||
"@octokit/plugin-retry": "^6.0.1",
|
"@octokit/plugin-retry": "^6.0.1",
|
||||||
"@types/node": "^20.9.0"
|
"@types/node": "^24.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^29.5.5",
|
"@types/jest": "^29.5.5",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import * as core from '@actions/core'
|
|||||||
import * as exec from '@actions/exec'
|
import * as exec from '@actions/exec'
|
||||||
import {Context} from '@actions/github/lib/context'
|
import {Context} from '@actions/github/lib/context'
|
||||||
import {GitHub} from '@actions/github/lib/utils'
|
import {GitHub} from '@actions/github/lib/utils'
|
||||||
|
import {getOctokit} from '@actions/github'
|
||||||
import * as glob from '@actions/glob'
|
import * as glob from '@actions/glob'
|
||||||
import * as io from '@actions/io'
|
import * as io from '@actions/io'
|
||||||
|
|
||||||
@@ -12,6 +13,7 @@ export declare type AsyncFunctionArguments = {
|
|||||||
core: typeof core
|
core: typeof core
|
||||||
github: InstanceType<typeof GitHub>
|
github: InstanceType<typeof GitHub>
|
||||||
octokit: InstanceType<typeof GitHub>
|
octokit: InstanceType<typeof GitHub>
|
||||||
|
getOctokit: typeof getOctokit
|
||||||
exec: typeof exec
|
exec: typeof exec
|
||||||
glob: typeof glob
|
glob: typeof glob
|
||||||
io: typeof io
|
io: typeof io
|
||||||
|
|||||||
53
src/create-configured-getoctokit.ts
Normal file
53
src/create-configured-getoctokit.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import {getOctokit} from '@actions/github'
|
||||||
|
import {GitHub} from '@actions/github/lib/utils'
|
||||||
|
import {OctokitOptions, OctokitPlugin} from '@octokit/core/dist-types/types'
|
||||||
|
|
||||||
|
type GetOctokit = typeof getOctokit
|
||||||
|
|
||||||
|
function stripUndefined<T extends Record<string, unknown>>(obj: T): Partial<T> {
|
||||||
|
const result: Partial<T> = {}
|
||||||
|
for (const [key, value] of Object.entries(obj)) {
|
||||||
|
if (value !== undefined) {
|
||||||
|
;(result as Record<string, unknown>)[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createConfiguredGetOctokit(
|
||||||
|
rawGetOctokit: GetOctokit,
|
||||||
|
defaultOptions: OctokitOptions,
|
||||||
|
...defaultPlugins: OctokitPlugin[]
|
||||||
|
): GetOctokit {
|
||||||
|
return (
|
||||||
|
token: string,
|
||||||
|
options?: OctokitOptions,
|
||||||
|
...additionalPlugins: OctokitPlugin[]
|
||||||
|
): InstanceType<typeof GitHub> => {
|
||||||
|
const userOpts = stripUndefined(options || {})
|
||||||
|
const defaultRequest = defaultOptions.request
|
||||||
|
const userRequestRaw = userOpts.request as
|
||||||
|
| Record<string, unknown>
|
||||||
|
| undefined
|
||||||
|
const userRequest = userRequestRaw ? stripUndefined(userRequestRaw) : {}
|
||||||
|
const defaultRetry = defaultOptions.retry
|
||||||
|
const userRetryRaw = userOpts.retry as Record<string, unknown> | undefined
|
||||||
|
const userRetry = userRetryRaw ? stripUndefined(userRetryRaw) : {}
|
||||||
|
|
||||||
|
const merged: OctokitOptions = {
|
||||||
|
...defaultOptions,
|
||||||
|
...userOpts,
|
||||||
|
request: {...(defaultRequest || {}), ...userRequest},
|
||||||
|
retry: {...(defaultRetry || {}), ...userRetry}
|
||||||
|
}
|
||||||
|
|
||||||
|
const allPlugins = [...defaultPlugins]
|
||||||
|
for (const plugin of additionalPlugins) {
|
||||||
|
if (!allPlugins.includes(plugin)) {
|
||||||
|
allPlugins.push(plugin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rawGetOctokit(token, merged, ...allPlugins)
|
||||||
|
}
|
||||||
|
}
|
||||||
31
src/main.ts
31
src/main.ts
@@ -8,6 +8,7 @@ import {requestLog} from '@octokit/plugin-request-log'
|
|||||||
import {retry} from '@octokit/plugin-retry'
|
import {retry} from '@octokit/plugin-retry'
|
||||||
import {RequestRequestOptions} from '@octokit/types'
|
import {RequestRequestOptions} from '@octokit/types'
|
||||||
import {callAsyncFunction} from './async-function'
|
import {callAsyncFunction} from './async-function'
|
||||||
|
import {createConfiguredGetOctokit} from './create-configured-getoctokit'
|
||||||
import {RetryOptions, getRetryOptions, parseNumberArray} from './retry-options'
|
import {RetryOptions, getRetryOptions, parseNumberArray} from './retry-options'
|
||||||
import {wrapRequire} from './wrap-require'
|
import {wrapRequire} from './wrap-require'
|
||||||
|
|
||||||
@@ -39,9 +40,12 @@ async function main(): Promise<void> {
|
|||||||
defaultGitHubOptions
|
defaultGitHubOptions
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const baseUserAgent = userAgent || 'actions/github-script'
|
||||||
|
const finalUserAgent = getUserAgentWithOrchestrationId(baseUserAgent)
|
||||||
|
|
||||||
const opts: Options = {
|
const opts: Options = {
|
||||||
log: debug ? console : undefined,
|
log: debug ? console : undefined,
|
||||||
userAgent: userAgent || undefined,
|
userAgent: finalUserAgent,
|
||||||
previews: previews ? previews.split(',') : undefined,
|
previews: previews ? previews.split(',') : undefined,
|
||||||
retry: retryOpts,
|
retry: retryOpts,
|
||||||
request: requestOpts
|
request: requestOpts
|
||||||
@@ -56,6 +60,13 @@ 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 script = core.getInput('script', {required: true})
|
||||||
|
|
||||||
|
const configuredGetOctokit = createConfiguredGetOctokit(
|
||||||
|
getOctokit,
|
||||||
|
opts,
|
||||||
|
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 result = await callAsyncFunction(
|
||||||
{
|
{
|
||||||
@@ -63,6 +74,7 @@ async function main(): Promise<void> {
|
|||||||
__original_require__: __non_webpack_require__,
|
__original_require__: __non_webpack_require__,
|
||||||
github,
|
github,
|
||||||
octokit: github,
|
octokit: github,
|
||||||
|
getOctokit: configuredGetOctokit,
|
||||||
context,
|
context,
|
||||||
core,
|
core,
|
||||||
exec,
|
exec,
|
||||||
@@ -96,3 +108,20 @@ function handleError(err: any): void {
|
|||||||
console.error(err)
|
console.error(err)
|
||||||
core.setFailed(`Unhandled error: ${err}`)
|
core.setFailed(`Unhandled error: ${err}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the user agent string with orchestration ID appended if available
|
||||||
|
* @param userAgent The base user agent string
|
||||||
|
* @returns The user agent string with orchestration ID appended if ACTIONS_ORCHESTRATION_ID is set
|
||||||
|
*/
|
||||||
|
function getUserAgentWithOrchestrationId(userAgent: string): string {
|
||||||
|
const orchestrationId = process.env['ACTIONS_ORCHESTRATION_ID']
|
||||||
|
if (!orchestrationId) {
|
||||||
|
return userAgent
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sanitize orchestration ID - replace invalid characters with underscore
|
||||||
|
const sanitized = orchestrationId.replace(/[^a-zA-Z0-9._-]/g, '_')
|
||||||
|
|
||||||
|
return `${userAgent} actions_orchestration_id/${sanitized}`
|
||||||
|
}
|
||||||
|
|||||||
2
types/async-function.d.ts
vendored
2
types/async-function.d.ts
vendored
@@ -3,6 +3,7 @@ import * as core from '@actions/core';
|
|||||||
import * as exec from '@actions/exec';
|
import * as exec from '@actions/exec';
|
||||||
import { Context } from '@actions/github/lib/context';
|
import { Context } from '@actions/github/lib/context';
|
||||||
import { GitHub } from '@actions/github/lib/utils';
|
import { GitHub } from '@actions/github/lib/utils';
|
||||||
|
import { getOctokit } from '@actions/github';
|
||||||
import * as glob from '@actions/glob';
|
import * as glob from '@actions/glob';
|
||||||
import * as io from '@actions/io';
|
import * as io from '@actions/io';
|
||||||
export declare type AsyncFunctionArguments = {
|
export declare type AsyncFunctionArguments = {
|
||||||
@@ -10,6 +11,7 @@ export declare type AsyncFunctionArguments = {
|
|||||||
core: typeof core;
|
core: typeof core;
|
||||||
github: InstanceType<typeof GitHub>;
|
github: InstanceType<typeof GitHub>;
|
||||||
octokit: InstanceType<typeof GitHub>;
|
octokit: InstanceType<typeof GitHub>;
|
||||||
|
getOctokit: typeof getOctokit;
|
||||||
exec: typeof exec;
|
exec: typeof exec;
|
||||||
glob: typeof glob;
|
glob: typeof glob;
|
||||||
io: typeof io;
|
io: typeof io;
|
||||||
|
|||||||
Reference in New Issue
Block a user