77 lines
3.5 KiB
JavaScript
77 lines
3.5 KiB
JavaScript
//Setup
|
|
export default async function({login, q, imports, data, rest, graphql, queries, account}, {enabled = false} = {}) {
|
|
//Plugin execution
|
|
try {
|
|
//Check if plugin is enabled and requirements are met
|
|
if ((!enabled)||(!q.contributors))
|
|
return null
|
|
|
|
//Load inputs
|
|
let {head, base, ignored, contributions} = imports.metadata.plugins.contributors.inputs({data, account, q})
|
|
const repo = {owner:data.repo.owner.login, repo:data.repo.name}
|
|
|
|
//Retrieve head and base commits
|
|
console.debug(`metrics/compute/${login}/plugins > contributors > querying api head and base commits`)
|
|
const ref = {
|
|
head:(await graphql(queries.contributors.commit({...repo, expression:head}))).repository.object,
|
|
base:(await graphql(queries.contributors.commit({...repo, expression:base}))).repository.object,
|
|
}
|
|
|
|
//Get commit activity
|
|
console.debug(`metrics/compute/${login}/plugins > contributors > querying api for commits between [${ref.base?.abbreviatedOid ?? null}] and [${ref.head?.abbreviatedOid ?? null}]`)
|
|
const commits = []
|
|
for (let page = 1; ; page++) {
|
|
console.debug(`metrics/compute/${login}/plugins > contributors > loading page ${page}`)
|
|
try {
|
|
const {data:loaded} = await rest.repos.listCommits({...repo, per_page:100, page})
|
|
if (loaded.map(({sha}) => sha).includes(ref.base?.oid)) {
|
|
console.debug(`metrics/compute/${login}/plugins > contributors > reached ${ref.base?.oid}`)
|
|
commits.push(...loaded.slice(0, loaded.map(({sha}) => sha).indexOf(ref.base.oid)))
|
|
break
|
|
}
|
|
if (!loaded.length) {
|
|
console.debug(`metrics/compute/${login}/plugins > contributors > no more page to load`)
|
|
break
|
|
}
|
|
commits.push(...loaded)
|
|
}
|
|
catch (error) {
|
|
if (/Git Repository is empty/.test(error))
|
|
break
|
|
throw error
|
|
}
|
|
}
|
|
|
|
//Remove commits after head
|
|
const start = Math.max(0, commits.map(({sha}) => sha).indexOf(ref.head?.oid))
|
|
commits.splice(0, start)
|
|
console.debug(`metrics/compute/${login}/plugins > contributors > ${commits.length} commits loaded (${start} removed)`)
|
|
|
|
//Compute contributors and contributions
|
|
let contributors = {}
|
|
for (const {author:{login, avatar_url:avatar}, commit:{message = ""}} of commits) {
|
|
if ((!login)||(ignored.includes(login))) {
|
|
console.debug(`metrics/compute/${login}/plugins > contributors > ignored contributor "${login}"`)
|
|
continue
|
|
}
|
|
if (!(login in contributors))
|
|
contributors[login] = {avatar:await imports.imgb64(avatar), contributions:1, pr:[]}
|
|
else {
|
|
contributors[login].contributions++
|
|
contributors[login].pr.push(...(message.match(/(?<=[(])#\d+(?=[)])/g) ?? []))
|
|
}
|
|
}
|
|
contributors = Object.fromEntries(Object.entries(contributors).sort(([_an, a], [_bn, b]) => b.contributions - a.contributions))
|
|
|
|
//Filter pull requests
|
|
for (const contributor of Object.values(contributors))
|
|
contributor.pr = [...new Set(contributor.pr)]
|
|
|
|
//Results
|
|
return {head, base, ref, list:contributors, contributions}
|
|
}
|
|
//Handle errors
|
|
catch (error) {
|
|
throw {error:{message:"An error occured", instance:error}}
|
|
}
|
|
} |