mirror of
https://github.com/tiennm99/awesome-advent-of-code.git
synced 2026-10-17 16:12:49 +00:00
105 lines
2.7 KiB
JavaScript
105 lines
2.7 KiB
JavaScript
const core = require('@actions/core')
|
|
const { setTimeout: sleep } = require('timers/promises')
|
|
|
|
// limit size of each request to avoid getting timed out
|
|
const chunkSize = 100
|
|
|
|
// limit request rate to one chunk per requestWaitTime (seconds) to avoid exceeding secondary rate limits
|
|
// https://docs.github.com/en/graphql/overview/rate-limits-and-node-limits-for-the-graphql-api#secondary-rate-limits
|
|
const requestWaitTime = 5
|
|
let lastRequestTime = 0
|
|
|
|
// retry the request if it fails, throw if request fails requestRetries times
|
|
// wait requestRetryTime (seconds) before retrying the first time, doubling time with each retry
|
|
const requestRetries = 5
|
|
const requestRetryTime = 30
|
|
|
|
module.exports = async function updateRepos (octokit, repos) {
|
|
let responses = []
|
|
|
|
for (let i = 0; i < repos.length; i += chunkSize) {
|
|
const chunk = repos.slice(i, i + chunkSize)
|
|
responses.push(await queryRepos(octokit, chunk))
|
|
}
|
|
|
|
return responses.flatMap(response => {
|
|
return Object.entries(response).map(([key, obj]) => {
|
|
const index = parseInt(key.replace('index', ''))
|
|
|
|
if (obj === null) {
|
|
return repos.find(repo => repo.index === index)
|
|
} else {
|
|
return {
|
|
index,
|
|
owner: obj.owner.login,
|
|
name: obj.name,
|
|
lastCommit: obj.defaultBranchRef.target.committedDate
|
|
}
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
async function queryRepos (octokit, repos) {
|
|
const query = buildQuery(repos)
|
|
const waitTime = lastRequestTime + requestWaitTime * 1000 - Date.now()
|
|
|
|
if (waitTime > 0) {
|
|
core.info(`waiting ${Math.round(waitTime / 1000)} seconds...`)
|
|
await sleep(waitTime)
|
|
}
|
|
|
|
lastRequestTime = Date.now()
|
|
let nextRetryTime = requestRetryTime
|
|
|
|
for (let i = 1; ; i++) {
|
|
try {
|
|
return await octokit.graphql(query)
|
|
} catch (error) {
|
|
if (error.errors !== undefined) {
|
|
const softFail = error.errors.every(
|
|
e => e.message.indexOf('Could not resolve to a Repository') !== -1
|
|
)
|
|
|
|
if (softFail) {
|
|
core.info(error)
|
|
return error.data
|
|
}
|
|
}
|
|
|
|
if (i < requestRetries) {
|
|
core.info(error)
|
|
core.info(`retrying in ${nextRetryTime} seconds...`)
|
|
await sleep(nextRetryTime * 1000)
|
|
nextRetryTime *= 2
|
|
} else {
|
|
throw error
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function buildQuery (repos) {
|
|
const frag = `fragment props on Repository {
|
|
owner {
|
|
login
|
|
}
|
|
name
|
|
defaultBranchRef {
|
|
target {
|
|
... on Commit {
|
|
committedDate
|
|
}
|
|
}
|
|
}
|
|
}`
|
|
|
|
const query = repos
|
|
.map(repo => {
|
|
return `index${repo.index}: repository(owner: "${repo.owner}", name: "${repo.name}") { ...props }`
|
|
})
|
|
.join('\n')
|
|
|
|
return `${frag}\n\n{\n${query}\n}`
|
|
}
|