diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5424ac7..7d44aec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,7 @@ name: Continuous Integration on: + workflow_dispatch: pull_request: push: branches: @@ -49,12 +50,24 @@ jobs: id: checkout uses: actions/checkout@v4 + - name: Test Local Action (sweep) + id: sweep-test + uses: ./ + with: + actionToTake: 'sweep' + lowerBound: 50 + + - name: Print Output (sweep) + id: output-sweep + run: echo "${{ steps.sweep-test.outputs.remaining }}" + - name: Test Local Action - id: test-action + id: sleep-test uses: ./ with: - milliseconds: 1000 + actionToTake: 'sleep' + lowerBound: 1500 - - name: Print Output - id: output - run: echo "${{ steps.test-action.outputs.time }}" + - name: Print Output (sleep) + id: output-sleep + run: echo "${{ steps.sleep-test.outputs.remaining }}" diff --git a/README.md b/README.md index 9044967..4963283 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,11 @@ [![GitHub Super-Linter](https://github.com/actions/typescript-action/actions/workflows/linter.yml/badge.svg)](https://github.com/super-linter/super-linter) ![CI](https://github.com/actions/typescript-action/actions/workflows/ci.yml/badge.svg) -This action can be used to obtain the remaining Github API quota and act accordingly. +This action can be used to obtain the remaining Github API quota and act +accordingly. ## Development + ### Initial Setup After you've cloned the repository to your local machine or codespace, you'll @@ -44,6 +46,7 @@ need to perform some initial setup steps before you can develop your action. ... ``` + ## Update the Action Code The [`src/`](./src/) directory is the heart of the action! This contains the diff --git a/action.yml b/action.yml index 30a28a2..97f19e2 100644 --- a/action.yml +++ b/action.yml @@ -1,11 +1,15 @@ name: 'Sweep or sleep action' -description: 'This action can be used to obtain the remaining Github API quota and act accordingly.' +description: + 'This action can be used to obtain the remaining Github API quota and act + accordingly.' author: 'Matthias Zepper' # Define your inputs here. inputs: actionToTake: - description: 'Action to take if the API limit is underrun: Sweep (fail) or sleep (wait for quota renewal).' + description: + 'Action to take if the API limit is underrun: Sweep (fail) or sleep (wait + for quota renewal).' required: false default: 'sweep' lowerBound: @@ -13,7 +17,9 @@ inputs: required: false default: '50' resource: - description: 'Github API quota to use for the action: One of "core", "search", "graphql", "integration_manifest" or "code_scanning_upload"' + description: + 'Github API quota to use for the action: One of "core", "search", + "graphql", "integration_manifest" or "code_scanning_upload"' required: false default: 'core' token: diff --git a/src/main.ts b/src/main.ts index b0bcab1..06fdbb2 100644 --- a/src/main.ts +++ b/src/main.ts @@ -3,10 +3,10 @@ import * as github from '@actions/github' import { sleep } from './sleep' interface Resource { - limit: number; - remaining: number; - reset: number; - used: number; + limit: number + remaining: number + reset: number + used: number } /** @@ -15,64 +15,80 @@ interface Resource { */ export async function run(): Promise { try { - let lowerBound: number = parseInt(core.getInput('lowerBound')) || 50 let actionToTake: string = core.getInput('actionToTake') || 'sweep' let resource: string = core.getInput('resource') || 'core' - let token: string = core.getInput('token') || String(process.env.GITHUB_TOKEN) + let token: string = + core.getInput('token') || String(process.env.GITHUB_TOKEN) // corroborate that resource is one of the valid resource types / quotas: - if (![ "core", "search", "graphql", "integration_manifest", "code_scanning_upload"].includes(resource)) { - core.setFailed(`The resource must be either core, graphql, search, integration_manifest, or code_scanning_upload.`) + if ( + ![ + 'core', + 'search', + 'graphql', + 'integration_manifest', + 'code_scanning_upload' + ].includes(resource) + ) { + core.setFailed( + `The resource must be either core, graphql, search, integration_manifest, or code_scanning_upload.` + ) } if (!token) { - core.setFailed("Please provide a Github token") + core.setFailed('Please provide a Github token') } - // retrieve the number of remaining API requests const octoKit = github.getOctokit(token) const rateLimit = await octoKit.rest.rateLimit.get() core.debug(JSON.stringify(rateLimit)) // retrieve the property of the rateLimit object that corresponds to the resource - const resourceData: Resource = rateLimit.data.resources[resource as keyof typeof rateLimit.data.resources] as Resource + const resourceData: Resource = rateLimit.data.resources[ + resource as keyof typeof rateLimit.data.resources + ] as Resource const remaining: number = resourceData.remaining || -1 const reset: number = resourceData.reset || -1 if (remaining < 0 || reset < 0) { - - core.setFailed("Github API rateLimit could not be retrieved.") - + core.setFailed('Github API rateLimit could not be retrieved.') } else { - core.exportVariable('remaining', remaining) core.setOutput('remaining', remaining) - if (remaining > lowerBound) { - - core.info(`The API limit is plentiful: ${remaining} requests on ${resource} remain.`) - + if (remaining > lowerBound) { + core.info( + `The API limit is plentiful: ${remaining} requests on ${resource} remain.` + ) } else { - - core.info(`The API limit is dangerously low: ${remaining} requests on ${resource} remain.`) + core.info( + `The API limit is dangerously low: ${remaining} requests on ${resource} remain.` + ) switch (actionToTake) { case 'sleep': // calculate the number of seconds until the rate limit resets (getTime() returns milliseconds, the API UTC epoch seconds) - const seconds_to_reset = reset - Math.round((new Date()).getTime() / 1000) + const seconds_to_reset = + reset - Math.round(new Date().getTime() / 1000) const minutes = Math.floor(seconds_to_reset / 60) - core.info(`The API limit will reset in ${minutes} minutes and ${(seconds_to_reset % 60)} seconds.`) + core.info( + `The API limit will reset in ${minutes} minutes and ${ + seconds_to_reset % 60 + } seconds.` + ) // sleep n milliseconds + 5 seconds past the reset time to ensure the limit has been reset - await sleep(seconds_to_reset*1000+5000) + await sleep(seconds_to_reset * 1000 + 5000) core.info(`The API limit has been reset. Farewell!`) break default: - core.setFailed(`The API limit of ${resource} was too low to proceed.`) + core.setFailed( + `The API limit of ${resource} was too low to proceed.` + ) } } }