feat(app/action): improved setup error handling for exceeded rate-limit (#1008) [skip ci]
This commit is contained in:
@@ -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")
|
||||
}
|
||||
})()
|
||||
|
||||
Reference in New Issue
Block a user