feat(app/action): improved setup error handling for exceeded rate-limit (#1008) [skip ci]

This commit is contained in:
Simon Lecoq
2022-04-23 20:36:26 +02:00
committed by GitHub
parent 5eef11b5c7
commit c3ea358446

View File

@@ -68,6 +68,12 @@ async function retry(func, {retries = 1, delay = 0} = {}) {
return null
}
//Process exit
function quit(reason) {
const code = {success:0, skipped:0, failed:1}[reason] ?? 0
process.exit(code)
}
//=====================================================================================================
//Runner
@@ -81,11 +87,11 @@ async function retry(func, {retries = 1, delay = 0} = {}) {
if ((github.context.eventName === "push") && (github.context.payload?.head_commit)) {
if (/\[Skip GitHub Action\]/.test(github.context.payload.head_commit.message)) {
console.log("Skipped because [Skip GitHub Action] is in commit message")
process.exit(0)
quit("skipped")
}
if (/Auto-generated metrics for run #\d+/.test(github.context.payload.head_commit.message)) {
console.log("Skipped because this seems to be an automated pull request merge")
process.exit(0)
quit("skipped")
}
}
@@ -163,6 +169,7 @@ async function retry(func, {retries = 1, delay = 0} = {}) {
throw new Error("You must provide a valid GitHub personal token to gather your metrics (see https://github.com/lowlighter/metrics/blob/master/.github/readme/partials/documentation/setup/action.md for more informations)")
conf.settings.token = token
const api = {}
const resources = {}
api.graphql = octokit.graphql.defaults({headers:{authorization:`token ${token}`}})
info("Github GraphQL API", "ok")
const octoraw = github.getOctokit(token)
@@ -174,8 +181,24 @@ async function retry(func, {retries = 1, delay = 0} = {}) {
Object.assign(api, await mocks(api))
info("Use mocked API", true)
}
//Test token validity
//Test token validity and requests count
else if (!/^NOT_NEEDED$/.test(token)) {
//Check rate limit
const {data} = await api.rest.rateLimit.get().catch(() => ({data:{resources:{}}}))
Object.assign(resources, data.resources)
info("API requests (REST)", resources.core ? `${resources.core.remaining}/${resources.core.limit}` : "(unknown)")
info("API requests (GraphQL)", resources.graphql ? `${resources.graphql.remaining}/${resources.graphql.limit}` : "(unknown)")
info("API requests (search)", resources.search ? `${resources.search.remaining}/${resources.search.limit}` : "(unknown)")
if ((!resources.core.remaining)||(!resources.graphql.remaining)) {
console.warn("::warning::It seems you have reached your API requests limit. Please retry later.")
info.break()
console.log("Nothing can be done currently, thanks for using metrics!")
quit("skipped")
}
if (!resources.search.remaining)
console.warn("::warning::It seems you have reached your Search API requests limit. Some plugins may return less accurate results.")
//Check scopes
try {
const {headers} = await api.rest.request("HEAD /")
if (!("x-oauth-scopes" in headers)) {
throw new Error(
@@ -184,6 +207,10 @@ async function retry(func, {retries = 1, delay = 0} = {}) {
}
info("Token validity", "seems ok")
}
catch {
info("Token validity", "(could not verify)")
}
}
//Extract octokits
const {graphql, rest} = api
@@ -404,9 +431,9 @@ async function retry(func, {retries = 1, delay = 0} = {}) {
if (_action === "none") {
info.break()
console.log("Success, thanks for using metrics!")
process.exit(0)
}
//Perform output action
else {
//Cache embed svg for markdown outputs
if (/markdown/.test(convert)) {
const regex = /(?<match><img class="metrics-cachable" data-name="(?<name>[\s\S]+?)" src="data:image[/](?<format>(?:svg[+]xml)|jpeg|png);base64,(?<content>[/+=\w]+?)">)/
@@ -557,6 +584,19 @@ async function retry(func, {retries = 1, delay = 0} = {}) {
} while (--attempts)
}
}
}
//Consumed API requests
{
info.break()
info.section("Consumed API requests")
info(" * provided that no other app used your quota during execution", "")
const {data:current} = await api.rest.rateLimit.get().catch(() => ({data:{resources:{}}}))
for (const type of ["core", "graphql", "search"]) {
const used = resources[type].remaining - current.resources[type].remaining
info({core:"REST API", graphql:"GraphQL API", search:"Search API"}[type], (Number.isFinite(used)&&(used >= 0)) ? used : "(unknown)")
}
}
//Delay
if (delay) {
@@ -568,7 +608,7 @@ async function retry(func, {retries = 1, delay = 0} = {}) {
//Success
info.break()
console.log("Success, thanks for using metrics!")
process.exit(0)
quit("success")
}
//Errors
catch (error) {
@@ -579,6 +619,6 @@ async function retry(func, {retries = 1, delay = 0} = {}) {
console.log(log)
}
core.setFailed(error.message)
process.exit(1)
quit("failed")
}
})()