From 621418948a2b1a2baace7dd8846696fb3b992a38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanislav=20Ochotnick=C3=BD?= Date: Thu, 10 Oct 2024 05:12:32 -0400 Subject: [PATCH] Add support for GitHub Enterprise Without this support octokit always tries to query api.github.com instead of GitHub Enterprise where it's running --- README.md | 10 ++++++++++ __tests__/schema.test.ts | 2 ++ action.yml | 4 ++++ dist/index.js | 9 ++++++--- src/github-api.ts | 3 ++- src/input.ts | 2 ++ src/main.ts | 2 +- src/schema.ts | 1 + 8 files changed, 28 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d57324c8..47742f84 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,7 @@ Full list of the options | NAME | DESCRIPTION | TYPE | DEFAULT | OPTIONS | | ----------------------------------- | -------------------------------------------------------------- | -------- | --------------------- | ---------------------------------------- | +| `github-api-url` | The Github API endpoint. Override for Github Enterprise usage. | `string` | `true` | `https://api.github.com` | | `github-token` | The GITHUB_TOKEN secret. You can use PAT if you want. | `string` | `${{ github.token }}` | | | `wait-seconds-before-first-polling` | Wait this interval before first polling | `number` | `10` | | | `min-interval-seconds` | Wait this interval or the multiplied value (and jitter) | `number` | `15` | | @@ -90,6 +91,15 @@ permissions: actions: read ``` +## Support for Github Enterprise + +To run this action in your Github Enterprise (GHE) instance you need to override `github-api-url`: + +```yaml +with: + github-api-url: 'https://ghe-host.acme.net/api/v3' +``` + ## outputs. - `dump`\ diff --git a/__tests__/schema.test.ts b/__tests__/schema.test.ts index 914a3aae..85b90303 100644 --- a/__tests__/schema.test.ts +++ b/__tests__/schema.test.ts @@ -8,6 +8,7 @@ import { deepStrictEqual } from 'node:assert/strict'; import { checkSync } from 'recheck'; const defaultOptions = Object.freeze({ + apiUrl: 'https://api.github.com', isEarlyExit: true, attemptLimits: 1000, waitList: [], @@ -21,6 +22,7 @@ const defaultOptions = Object.freeze({ test('Options keep given values', () => { optionsEqual({ + apiUrl: 'https://api.github.com', isEarlyExit: true, attemptLimits: 1000, waitList: [], diff --git a/action.yml b/action.yml index 3caf6267..e72ab456 100644 --- a/action.yml +++ b/action.yml @@ -9,6 +9,10 @@ inputs: description: 'The GITHUB_TOKEN secret' required: false default: ${{ github.token }} + github-api-url: + description: 'Github API URL' + required: true + default: 'https://api.github.com' wait-seconds-before-first-polling: description: 'Wait this seconds before first polling' required: false diff --git a/dist/index.js b/dist/index.js index 69350436..7e56688f 100644 --- a/dist/index.js +++ b/dist/index.js @@ -32618,6 +32618,7 @@ var WaitList = z2.array(WaitFilterCondition).readonly(); var SkipList = z2.array(SkipFilterCondition).readonly(); var retryMethods = z2.enum(["exponential_backoff", "equal_intervals"]); var Options = z2.object({ + apiUrl: z2.string().url(), waitList: WaitList, skipList: SkipList, initialDuration: Duration, @@ -32687,7 +32688,9 @@ function parseInput() { const isEarlyExit = (0, import_core.getBooleanInput)("early-exit", { required: true, trimWhitespace: true }); const shouldSkipSameWorkflow = (0, import_core.getBooleanInput)("skip-same-workflow", { required: true, trimWhitespace: true }); const isDryRun = (0, import_core.getBooleanInput)("dry-run", { required: true, trimWhitespace: true }); + const apiUrl = (0, import_core.getInput)("github-api-url", { required: true, trimWhitespace: true }); const options = Options.parse({ + apiUrl, initialDuration: Durationable.parse({ seconds: waitSecondsBeforeFirstPolling }), leastInterval: Durationable.parse({ seconds: minIntervalSeconds }), retryMethod, @@ -33808,8 +33811,8 @@ function paginateGraphQL(octokit) { // src/github-api.ts var PaginatableOctokit = Octokit.plugin(paginateGraphQL); -async function fetchChecks(token, trigger) { - const octokit = new PaginatableOctokit({ auth: token }); +async function fetchChecks(apiUrl, token, trigger) { + const octokit = new PaginatableOctokit({ auth: token, baseUrl: apiUrl }); const { repository: { object: { checkSuites } } } = await octokit.graphql.paginate( /* GraphQL */ ` @@ -34167,7 +34170,7 @@ async function run() { } const elapsed = mr.Duration.from({ milliseconds: Math.ceil(performance.now() - startedAt) }); (0, import_core3.startGroup)(`Polling ${attempts}: ${(/* @__PURE__ */ new Date()).toISOString()} # total elapsed ${readableDuration(elapsed)}`); - const checks = await fetchChecks(githubToken, trigger); + const checks = await fetchChecks(options.apiUrl, githubToken, trigger); const report = generateReport( getSummaries(checks, trigger), trigger, diff --git a/src/github-api.ts b/src/github-api.ts index 44c532f6..685793f9 100644 --- a/src/github-api.ts +++ b/src/github-api.ts @@ -6,10 +6,11 @@ import { Check, Trigger } from './schema.ts'; const PaginatableOctokit = Octokit.plugin(paginateGraphQL); export async function fetchChecks( + apiUrl: string, token: string, trigger: Trigger, ): Promise { - const octokit = new PaginatableOctokit({ auth: token }); + const octokit = new PaginatableOctokit({ auth: token, baseUrl: apiUrl }); const { repository: { object: { checkSuites } } } = await octokit.graphql.paginate< { repository: { object: { checkSuites: Commit['checkSuites'] } } } >( diff --git a/src/input.ts b/src/input.ts index 851eab28..828d4669 100644 --- a/src/input.ts +++ b/src/input.ts @@ -47,8 +47,10 @@ export function parseInput(): { trigger: Trigger; options: Options; githubToken: const isEarlyExit = getBooleanInput('early-exit', { required: true, trimWhitespace: true }); const shouldSkipSameWorkflow = getBooleanInput('skip-same-workflow', { required: true, trimWhitespace: true }); const isDryRun = getBooleanInput('dry-run', { required: true, trimWhitespace: true }); + const apiUrl = getInput('github-api-url', { required: true, trimWhitespace: true }); const options = Options.parse({ + apiUrl, initialDuration: Durationable.parse({ seconds: waitSecondsBeforeFirstPolling }), leastInterval: Durationable.parse({ seconds: minIntervalSeconds }), retryMethod, diff --git a/src/main.ts b/src/main.ts index 47c5d8f4..6f55f936 100644 --- a/src/main.ts +++ b/src/main.ts @@ -91,7 +91,7 @@ async function run(): Promise { // Put getting elapsed time before of fetchChecks to keep accuracy of the purpose const elapsed = Temporal.Duration.from({ milliseconds: Math.ceil(performance.now() - startedAt) }); startGroup(`Polling ${attempts}: ${(new Date()).toISOString()} # total elapsed ${readableDuration(elapsed)}`); - const checks = await fetchChecks(githubToken, trigger); + const checks = await fetchChecks(options.apiUrl, githubToken, trigger); const report = generateReport( getSummaries(checks, trigger), diff --git a/src/schema.ts b/src/schema.ts index 155f3a4e..5846abe0 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -109,6 +109,7 @@ export type RetryMethod = z.infer; // - Do not specify default values with zod. That is an action.yml role // - Do not include secrets here, for example githubToken. See https://github.com/colinhacks/zod/issues/1783 export const Options = z.object({ + apiUrl: z.string().url(), waitList: WaitList, skipList: SkipList, initialDuration: Duration,