People plugin : repository template support (#78)

This commit is contained in:
Simon Lecoq
2021-01-25 22:08:29 +01:00
committed by GitHub
parent c075d49e76
commit 4879ed0136
14 changed files with 343 additions and 63 deletions

View File

@@ -181,6 +181,21 @@ But there's more with [plugins](https://github.com/lowlighter/metrics/tree/maste
<img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.people.following.svg" alt="" width="400">
</a>
</details>
<details><summary>Special thanks version</summary>
<a href="#-habits">
<img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.people.thanks.svg" alt="" width="400">
</a>
</details>
<details><summary>Repository template version</summary>
<a href="#-habits">
<img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.people.repository.svg" alt="" width="400">
</a>
</details>
<details><summary>Sponsorships version</summary>
<a href="#-habits">
<img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.people.sponsorships.svg" alt="" width="400">
</a>
</details>
</td>
</tr>
<tr>
@@ -1528,7 +1543,8 @@ Add the following to your workflow:
### 🧑‍🤝‍🧑 People
The *people* plugin displays your followers and followed users' avatars.
The *people* plugin can display people you're following or sponsoring, and also users who're following or sponsoring you.
In repository mode, it's possible to display sponsors, stargazers, watchers.
![People plugin](https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.people.svg)
@@ -1537,6 +1553,24 @@ The *people* plugin displays your followers and followed users' avatars.
It will consume an additional GitHub request per group of 100 users fetched.
The following types are supported:
| Type | Alias | User metrics | Repository metrics |
| --------------- | ------------------------------------ | :----------------: | :----------------: |
| `followers` | | ✔️ | ❌ |
| `following` | `followed` | ✔️ | ❌ |
| `sponsoring`* | `sponsored`, `sponsorshipsAsSponsor` | ✔️ | ❌ |
| `sponsors`* | `sponsorshipsAsMaintainer` | ✔️ | ✔️ |
| `contributors`* | | ❌ | ✔️ |
| `stargazers`* | | ❌ | ✔️ |
| `watchers`* | | ❌ | ✔️ |
| `thanks`* | | ✔️ | ✔️ |
🚧 Types marked with * are available as pre-release on @master branch (unstable)
Sections will be ordered the same as specified in `plugin_people_types`.
`sponsors` for repositories will output the same as the owner's sponsors.
Add the following to your workflow:
```yaml
- uses: lowlighter/metrics@latest
@@ -1557,6 +1591,17 @@ It is possible to use [identicons](https://github.blog/2013-08-14-identicons/) i
plugin_people_identicons: yes
```
🚧 This feature is available as pre-release on @master branch (unstable)
It is possible to thanks personally users by adding the following to your workflow:
```yaml
- uses: lowlighter/metrics@master
with:
# ... other options
plugin_people_types: thanks
plugin_people_thanks: github-user-1, github-user-2, ...
```
</details>
### 🌸 Anilist

View File

@@ -469,13 +469,29 @@ inputs:
default: 28
# List of users categories to display (comma separated)
# Supported values are:
# For user's metrics, supported values are:
# - "followers"
# - "following"
# - "following"/"followed"
# - "sponsors"/"sponsorshipsAsMaintainer"
# - "sponsoring"/"sponsored"/"sponsorshipsAsSponsor"
# - "thanks" (see "plugin_people_thanks" below)
# For repositories' metrics, supported values are:
# - "contributors"
# - "stargazers"
# - "watchers"
# - "sponsors"/"sponsorshipsAsMaintainer"
# - "thanks" (see "plugin_people_thanks" below)
plugin_people_types:
description: Categories to display
default: followers, following
# List of users to thanks (comma seperated)
# When using "thanks" as a type, it'll display the users you listed in this option
# This can be used to create "Special thanks" badges that you can embed elsewhere
plugin_people_thanks:
description: Users to thanks in "thanks" section type
default: ""
# Display GitHub identicons instead of users' real avatar
# Mostly for privacy purposes
plugin_people_identicons:

View File

@@ -239,7 +239,7 @@
if (plugins.people.enabled) {
for (const option of ["limit", "size"])
info(`People ${option}`, q[`people.${option}`] = input.number(`plugin_people_${option}`))
for (const option of ["types"])
for (const option of ["types", "thanks"])
info(`People ${option}`, q[`people.${option}`] = input.array(`plugin_people_${option}`))
for (const option of ["identicons"])
info(`People ${option}`, q[`people.${option}`] = input.bool(`plugin_people_${option}`))

View File

@@ -362,7 +362,7 @@
}) : ({
user:{
[type]:{
edges:new Array(Math.ceil(20+80*Math.random())).fill(undefined).map((login = faker.internet.userName()) => ({
edges:new Array(Math.ceil(20+80*Math.random())).fill(null).map((login = faker.internet.userName()) => ({
cursor:"MOCKED_CURSOR",
node:{
login,
@@ -373,6 +373,66 @@
}
})
}
//People query (repositories)
if (/^query PeopleRepository /.test(query)) {
console.debug(`metrics/compute/mocks > mocking graphql api result > People`)
const type = query.match(/(?<type>stargazers|watchers)[(]/)?.groups?.type ?? "(unknown type)"
return /after: "MOCKED_CURSOR"/m.test(query) ? ({
user:{
repository:{
[type]:{
edges:[],
}
}
}
}) : ({
user:{
repository:{
[type]:{
edges:new Array(Math.ceil(20+80*Math.random())).fill(null).map((login = faker.internet.userName()) => ({
cursor:"MOCKED_CURSOR",
node:{
login,
avatarUrl:null,
}
}))
}
}
}
})
}
//People sponsors query
if (/^query PeopleSponsors /.test(query)) {
console.debug(`metrics/compute/mocks > mocking graphql api result > People`)
const type = query.match(/(?<type>sponsorshipsAsSponsor|sponsorshipsAsMaintainer)[(]/)?.groups?.type ?? "(unknown type)"
return /after: "MOCKED_CURSOR"/m.test(query) ? ({
user:{
login,
[type]:{
edges:[]
}
}
}) : ({
user:{
login,
[type]:{
edges:new Array(Math.ceil(20+80*Math.random())).fill(null).map((login = faker.internet.userName()) => ({
cursor:"MOCKED_CURSOR",
node:{
sponsorEntity:{
login:faker.internet.userName(),
avatarUrl:null,
},
sponsorable:{
login:faker.internet.userName(),
avatarUrl:null,
}
}
}))
}
}
})
}
//Unmocked call
return target(...args)
}
@@ -389,6 +449,8 @@
getViews:rest.repos.getViews,
getContributorsStats:rest.repos.getContributorsStats,
listCommits:rest.repos.listCommits,
listContributors:rest.repos.listContributors,
getByUsername:rest.users.getByUsername,
}
//Raw request
@@ -893,6 +955,49 @@
})
}
})
//Repository contributors
rest.repos.listContributors = new Proxy(unmocked.listContributors, {
apply:function(target, that, [{owner, repo}]) {
console.debug(`metrics/compute/mocks > mocking rest api result > rest.repos.listContributors`)
return ({
status:200,
url:`https://api.github.com/repos/${owner}/${repo}/contributors`,
headers: {
server:"GitHub.com",
status:"200 OK",
"x-oauth-scopes":"repo",
},
data:new Array(40+faker.random.number(60)).fill(null).map(() => ({
login:faker.internet.userName(),
avatar_url:null,
contributions:faker.random.number(1000),
}))
})
}
})
//User informations
rest.users.getByUsername = new Proxy(unmocked.getByUsername, {
apply:function(target, that, [{username}]) {
console.debug(`metrics/compute/mocks > mocking rest api result > rest.repos.getByUsername`)
return ({
status:200,
url:`'https://api.github.com/users/${username}/`,
headers: {
server:"GitHub.com",
status:"200 OK",
"x-oauth-scopes":"repo",
},
data:{
login:faker.internet.userName(),
avatar_url:null,
contributions:faker.random.number(1000),
}
})
}
})
}
//Axios mocking

View File

@@ -76,7 +76,7 @@
stars:"🌟 Recently starred repositories",
stargazers:"✨ Stargazers over last weeks",
activity:"📰 Recent activity",
people:"🧑‍🤝‍🧑 Followers and followed",
people:"🧑‍🤝‍🧑 People",
anilist:"🌸 Anilist",
base:"🗃️ Base content",
"base.header":"Header",
@@ -120,6 +120,7 @@
"people.size":{text:"Limit", type:"number", min:16, max:64},
"people.limit":{text:"Limit", type:"number", min:1, max:9999},
"people.types":{text:"Types", placeholder:"followers, following"},
"people.thanks":{text:"Special thanks", placeholder:"user1, user2, ..."},
"people.identicons":{text:"Use identicons", type:"boolean"},
"anilist.medias":{text:"Medias to display", placeholder:"anime, manga"},
"anilist.sections":{text:"Sections to display", placeholder:"favorites, watching, reading, characters"},
@@ -157,6 +158,7 @@
"people.size":28,
"people.limit":28,
"people.types":"followers, following",
"people.thanks":"",
"people.identicons":false,
"anilist.medias":"anime, manga",
"anilist.sections":"favorites",

View File

@@ -222,17 +222,25 @@
}) : null),
//People
...(set.plugins.enabled.people ? ({
people:{
types:options["people.types"].split(",").map(x => x.trim()),
size:options["people.size"],
followers:new Array(Number(options["people.limit"])).fill(null).map(_ => ({
login:faker.internet.userName(),
avatar:"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==",
})),
following:new Array(Number(options["people.limit"])).fill(null).map(_ => ({
login:faker.internet.userName(),
avatar:"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==",
}))
get people() {
const types = options["people.types"].split(",").map(x => x.trim())
.map(x => ({followed:"following", sponsors:"sponsorshipsAsMaintainer", sponsored:"sponsorshipsAsSponsor", sponsoring:"sponsorshipsAsSponsor"})[x] ?? x)
.filter(x => ["followers", "following", "sponsorshipsAsMaintainer", "sponsorshipsAsSponsor"].includes(x))
return {
types,
size:options["people.size"],
...(Object.fromEntries(types.map(type => [
type,
new Array(Number(options["people.limit"])).fill(null).map(_ => ({
login:faker.internet.userName(),
avatar:"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==",
}))
]))),
thanks:options["people.thanks"].split(",").map(x => x.trim()).map(login => ({
login,
avatar:"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==",
}))
}
}
}) : null),
//Music

View File

@@ -1,33 +1,66 @@
//Setup
export default async function ({login, graphql, q, queries, imports}, {enabled = false} = {}) {
export default async function ({login, data, graphql, rest, q, queries, imports}, {enabled = false} = {}) {
//Plugin execution
try {
//Check if plugin is enabled and requirements are met
if ((!enabled)||(!q.people))
return null
//Context
let context = {
mode:"user",
types:["followers", "following", "sponsorshipsAsMaintainer", "sponsorshipsAsSponsor", "thanks"],
default:"followers, following",
alias:{followed:"following", sponsors:"sponsorshipsAsMaintainer", sponsored:"sponsorshipsAsSponsor", sponsoring:"sponsorshipsAsSponsor"},
sponsorships:{sponsorshipsAsMaintainer:"sponsorEntity", sponsorshipsAsSponsor:"sponsorable"}
}
if (q.repo) {
console.debug(`metrics/compute/${login}/plugins > people > switched to repository mode`)
const {owner, repo} = data.user.repositories.nodes.map(({name:repo, owner:{login:owner}}) => ({repo, owner})).shift()
context = {...context, mode:"repo", types:["contributors", "stargazers", "watchers", "sponsorshipsAsMaintainer", "thanks"], default:"stargazers, watchers", owner, repo}
}
//Parameters override
let {"people.limit":limit = 28, "people.types":types = "followers, following", "people.size":size = 28, "people.identicons":identicons = false} = q
let {"people.limit":limit = 28, "people.types":types = context.default, "people.size":size = 28, "people.identicons":identicons = false, "people.thanks":thanks = []} = q
//Limit
limit = Math.max(1, limit)
//Repositories projects
types = decodeURIComponent(types ?? "").split(",").map(type => type.trim()).filter(type => ["followers", "following"].includes(type)) ?? []
types = [...new Set(decodeURIComponent(types ?? "").split(",").map(type => type.trim()).map(type => (context.alias[type] ?? type)).filter(type => context.types.includes(type)) ?? [])]
//Special thanks
thanks = decodeURIComponent(thanks ?? "").split(",").map(user => user.trim()).filter(user => user)
//Retrieve followers from graphql api
console.debug(`metrics/compute/${login}/plugins > people > querying api`)
const result = {followers:[], following:[]}
const result = Object.fromEntries(types.map(type => [type, []]))
for (const type of types) {
//Iterate through people
console.debug(`metrics/compute/${login}/plugins > people > retrieving ${type}`)
let cursor = null
let pushed = 0
do {
console.debug(`metrics/compute/${login}/plugins > people > retrieving ${type} after ${cursor}`)
const {user:{[type]:{edges}}} = await graphql(queries.people({login, type, size, after:cursor ? `after: "${cursor}"` : ""}))
cursor = edges?.[edges?.length-1]?.cursor
result[type].push(...edges.map(({node}) => node))
pushed = edges.length
} while ((pushed)&&(cursor))
//Rest
if (type === "contributors") {
const {owner, repo} = context
const {data:nodes} = await rest.repos.listContributors({owner, repo})
result[type].push(...nodes.map(({login, avatar_url}) => ({login, avatarUrl:avatar_url})))
}
else if (type === "thanks") {
const nodes = await Promise.all(thanks.map(async username => (await rest.users.getByUsername({username})).data))
result[type].push(...nodes.map(({login, avatar_url}) => ({login, avatarUrl:avatar_url})))
}
//GraphQL
else {
let cursor = null
let pushed = 0
do {
console.debug(`metrics/compute/${login}/plugins > people > retrieving ${type} after ${cursor}`)
const {[type]:{edges}} = (
type in context.sponsorships ? (await graphql(queries["people.sponsors"]({login:context.owner ?? login, type, size, after:cursor ? `after: "${cursor}"` : "", target:context.sponsorships[type]}))).user :
context.mode === "repo" ? (await graphql(queries["people.repository"]({login:context.owner, repository:context.repo, type, size, after:cursor ? `after: "${cursor}"` : ""}))).user.repository :
(await graphql(queries.people({login, type, size, after:cursor ? `after: "${cursor}"` : ""}))).user
)
cursor = edges?.[edges?.length-1]?.cursor
result[type].push(...edges.map(({node}) => node[context.sponsorships[type]] ?? node))
pushed = edges.length
} while ((pushed)&&(cursor)&&(result[type].length <= limit))
}
//Limit people
if (limit > 0) {
console.debug(`metrics/compute/${login}/plugins > people > keeping only ${limit} ${type}`)

View File

@@ -1,14 +1,13 @@
query Repository {
query PeopleRepository {
user(login: "$login") {
repository(name: "$repository") {
$type(first: 100) {
pageInfo {
hasNextPage
endCursor
}
nodes {
avatarUrl(size: 24)
login
$type($after first: 100) {
edges {
cursor
node {
login
avatarUrl(size: $size)
}
}
}
}

View File

@@ -0,0 +1,18 @@
query PeopleSponsors {
user(login: "$login") {
login
$type($after first: 100) {
edges {
cursor
node {
$target {
... on User {
login
avatarUrl(size: $size)
}
}
}
}
}
}
}

View File

@@ -15,11 +15,15 @@
</div>
</section>
<% } else { %>
<% if (plugins.people.types?.includes("followers")) { %>
<% for (const type of plugins.people.types) { %>
<section>
<h2 class="field">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M5.5 3.5a2 2 0 100 4 2 2 0 000-4zM2 5.5a3.5 3.5 0 115.898 2.549 5.507 5.507 0 013.034 4.084.75.75 0 11-1.482.235 4.001 4.001 0 00-7.9 0 .75.75 0 01-1.482-.236A5.507 5.507 0 013.102 8.05 3.49 3.49 0 012 5.5zM11 4a.75.75 0 100 1.5 1.5 1.5 0 01.666 2.844.75.75 0 00-.416.672v.352a.75.75 0 00.574.73c1.2.289 2.162 1.2 2.522 2.372a.75.75 0 101.434-.44 5.01 5.01 0 00-2.56-3.012A3 3 0 0011 4z"></path></svg>
<%= user.followers.totalCount %> follower<%= s(user.followers.totalCount) %>
<% if (type === "thanks") { %>
Special thanks
<% } else { %>
<%= user[type].totalCount %> <%= {followers:`follower${s(user[type].totalCount)}`, following:"followed", sponsorshipsAsSponsor:"sponsored", sponsorshipsAsMaintainer:`sponsor${s(user[type].totalCount)}`}[type] %>
<% } %>
</h2>
<div class="row">
<section class="people">
@@ -29,27 +33,7 @@
<%= plugins.people.error.message %>
</div>
<% } else { %>
<% for (const user of plugins.people.followers) { %><img class="avatar" src="data:image/png;base64,<%= user.avatar %>" width="<%= plugins.people.size %>" height="<%= plugins.people.size %>" alt="" /><% } %>
<% } %>
</section>
</div>
</section>
<% } %>
<% if (plugins.people.types?.includes("following")) { %>
<section>
<h2 class="field">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M5.5 3.5a2 2 0 100 4 2 2 0 000-4zM2 5.5a3.5 3.5 0 115.898 2.549 5.507 5.507 0 013.034 4.084.75.75 0 11-1.482.235 4.001 4.001 0 00-7.9 0 .75.75 0 01-1.482-.236A5.507 5.507 0 013.102 8.05 3.49 3.49 0 012 5.5zM11 4a.75.75 0 100 1.5 1.5 1.5 0 01.666 2.844.75.75 0 00-.416.672v.352a.75.75 0 00.574.73c1.2.289 2.162 1.2 2.522 2.372a.75.75 0 101.434-.44 5.01 5.01 0 00-2.56-3.012A3 3 0 0011 4z"></path></svg>
<%= user.following.totalCount %> followed
</h2>
<div class="row">
<section class="people">
<% if (plugins.people.error) { %>
<div class="field error">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg>
<%= plugins.people.error.message %>
</div>
<% } else { %>
<% for (const user of plugins.people.following) { %><img class="avatar" src="data:image/png;base64,<%= user.avatar %>" width="<%= plugins.people.size %>" height="<%= plugins.people.size %>" alt="" /><% } %>
<% for (const user of plugins.people[type]) { %><img class="avatar" src="data:image/png;base64,<%= user.avatar %>" width="<%= plugins.people.size %>" height="<%= plugins.people.size %>" alt="" /><% } %>
<% } %>
</section>
</div>

View File

@@ -4,5 +4,6 @@
"languages",
"projects",
"pagespeed",
"stargazers"
"stargazers",
"people"
]

View File

@@ -0,0 +1,43 @@
<% if (plugins.people) { %>
<% if (plugins.people.error) { %>
<section>
<h2 class="field">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M5.5 3.5a2 2 0 100 4 2 2 0 000-4zM2 5.5a3.5 3.5 0 115.898 2.549 5.507 5.507 0 013.034 4.084.75.75 0 11-1.482.235 4.001 4.001 0 00-7.9 0 .75.75 0 01-1.482-.236A5.507 5.507 0 013.102 8.05 3.49 3.49 0 012 5.5zM11 4a.75.75 0 100 1.5 1.5 1.5 0 01.666 2.844.75.75 0 00-.416.672v.352a.75.75 0 00.574.73c1.2.289 2.162 1.2 2.522 2.372a.75.75 0 101.434-.44 5.01 5.01 0 00-2.56-3.012A3 3 0 0011 4z"></path></svg>
People
</h2>
<div class="row">
<section>
<div class="field error">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg>
<%= plugins.people.error.message %>
</div>
</section>
</div>
</section>
<% } else { %>
<% for (const type of plugins.people.types) { %>
<section>
<h2 class="field">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M5.5 3.5a2 2 0 100 4 2 2 0 000-4zM2 5.5a3.5 3.5 0 115.898 2.549 5.507 5.507 0 013.034 4.084.75.75 0 11-1.482.235 4.001 4.001 0 00-7.9 0 .75.75 0 01-1.482-.236A5.507 5.507 0 013.102 8.05 3.49 3.49 0 012 5.5zM11 4a.75.75 0 100 1.5 1.5 1.5 0 01.666 2.844.75.75 0 00-.416.672v.352a.75.75 0 00.574.73c1.2.289 2.162 1.2 2.522 2.372a.75.75 0 101.434-.44 5.01 5.01 0 00-2.56-3.012A3 3 0 0011 4z"></path></svg>
<% if (type === "thanks") { %>
Special thanks
<% } else { %>
<%= repo[type].totalCount %> <%= {watchers:`watcher${s(repo[type].totalCount)}`, stargazers:`stargazer${s(repo[type].totalCount)}`, contributors:`contributor${s(repo[type].totalCount)}`, sponsorshipsAsSponsor:"sponsored", sponsorshipsAsMaintainer:`sponsor${s(repo[type].totalCount)}`}[type] %>
<% } %>
</h2>
<div class="row">
<section class="people">
<% if (plugins.people.error) { %>
<div class="field error">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg>
<%= plugins.people.error.message %>
</div>
<% } else { %>
<% for (const user of plugins.people[type]) { %><img class="avatar" src="data:image/png;base64,<%= user.avatar %>" width="<%= plugins.people.size %>" height="<%= plugins.people.size %>" alt="" /><% } %>
<% } %>
</section>
</div>
</section>
<% } %>
<% } %>
<% } %>

View File

@@ -15,6 +15,11 @@
console.debug(`metrics/compute/${login}/${repo} > retrieving single repository ${repo}`)
const {user:{repository}} = await graphql(queries.repository({login, repo}))
data.user.repositories.nodes = [repository]
data.repo = repository
//Contributors and sponsors
data.repo.contributors = {totalCount:(await rest.repos.listContributors({owner:data.repo.owner.login, repo})).data.length}
data.repo.sponsorshipsAsMaintainer = data.user.sponsorshipsAsMaintainer
//Get commit activity
console.debug(`metrics/compute/${login}/${repo} > querying api for commits`)

View File

@@ -286,6 +286,27 @@
plugin_people:true,
plugin_people_types:"following",
}, {skip:["terminal", "repository"]}],
["People plugin (sponsoring)", {
plugin_people:true,
plugin_people_types:"sponsoring",
}, {skip:["terminal", "repository"]}],
["People plugin (sponsors)", {
plugin_people:true,
plugin_people_types:"sponsors",
}, {skip:["terminal"]}],
["People plugin (stargazers)", {
plugin_people:true,
plugin_people_types:"stargazers",
}, {skip:["classic", "terminal"]}],
["People plugin (watchers)", {
plugin_people:true,
plugin_people_types:"watchers",
}, {skip:["classic", "terminal"]}],
["People plugin (thanks)", {
plugin_people:true,
plugin_people_types:"thanks",
plugin_people_thanks:"lowlighter",
}, {skip:["classic", "terminal"]}],
["People plugin (identicons)", {
plugin_people:true,
plugin_people_identicons:true,