People plugin : repository template support (#78)
This commit is contained in:
47
README.md
47
README.md
@@ -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">
|
<img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.people.following.svg" alt="" width="400">
|
||||||
</a>
|
</a>
|
||||||
</details>
|
</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>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -1528,7 +1543,8 @@ Add the following to your workflow:
|
|||||||
|
|
||||||
### 🧑🤝🧑 People
|
### 🧑🤝🧑 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.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -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.
|
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:
|
Add the following to your workflow:
|
||||||
```yaml
|
```yaml
|
||||||
- uses: lowlighter/metrics@latest
|
- 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
|
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>
|
</details>
|
||||||
|
|
||||||
### 🌸 Anilist
|
### 🌸 Anilist
|
||||||
|
|||||||
20
action.yml
20
action.yml
@@ -469,13 +469,29 @@ inputs:
|
|||||||
default: 28
|
default: 28
|
||||||
|
|
||||||
# List of users categories to display (comma separated)
|
# List of users categories to display (comma separated)
|
||||||
# Supported values are:
|
# For user's metrics, supported values are:
|
||||||
# - "followers"
|
# - "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:
|
plugin_people_types:
|
||||||
description: Categories to display
|
description: Categories to display
|
||||||
default: followers, following
|
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
|
# Display GitHub identicons instead of users' real avatar
|
||||||
# Mostly for privacy purposes
|
# Mostly for privacy purposes
|
||||||
plugin_people_identicons:
|
plugin_people_identicons:
|
||||||
|
|||||||
@@ -239,7 +239,7 @@
|
|||||||
if (plugins.people.enabled) {
|
if (plugins.people.enabled) {
|
||||||
for (const option of ["limit", "size"])
|
for (const option of ["limit", "size"])
|
||||||
info(`People ${option}`, q[`people.${option}`] = input.number(`plugin_people_${option}`))
|
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}`))
|
info(`People ${option}`, q[`people.${option}`] = input.array(`plugin_people_${option}`))
|
||||||
for (const option of ["identicons"])
|
for (const option of ["identicons"])
|
||||||
info(`People ${option}`, q[`people.${option}`] = input.bool(`plugin_people_${option}`))
|
info(`People ${option}`, q[`people.${option}`] = input.bool(`plugin_people_${option}`))
|
||||||
|
|||||||
@@ -362,7 +362,7 @@
|
|||||||
}) : ({
|
}) : ({
|
||||||
user:{
|
user:{
|
||||||
[type]:{
|
[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",
|
cursor:"MOCKED_CURSOR",
|
||||||
node:{
|
node:{
|
||||||
login,
|
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
|
//Unmocked call
|
||||||
return target(...args)
|
return target(...args)
|
||||||
}
|
}
|
||||||
@@ -389,6 +449,8 @@
|
|||||||
getViews:rest.repos.getViews,
|
getViews:rest.repos.getViews,
|
||||||
getContributorsStats:rest.repos.getContributorsStats,
|
getContributorsStats:rest.repos.getContributorsStats,
|
||||||
listCommits:rest.repos.listCommits,
|
listCommits:rest.repos.listCommits,
|
||||||
|
listContributors:rest.repos.listContributors,
|
||||||
|
getByUsername:rest.users.getByUsername,
|
||||||
}
|
}
|
||||||
|
|
||||||
//Raw request
|
//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
|
//Axios mocking
|
||||||
|
|||||||
@@ -76,7 +76,7 @@
|
|||||||
stars:"🌟 Recently starred repositories",
|
stars:"🌟 Recently starred repositories",
|
||||||
stargazers:"✨ Stargazers over last weeks",
|
stargazers:"✨ Stargazers over last weeks",
|
||||||
activity:"📰 Recent activity",
|
activity:"📰 Recent activity",
|
||||||
people:"🧑🤝🧑 Followers and followed",
|
people:"🧑🤝🧑 People",
|
||||||
anilist:"🌸 Anilist",
|
anilist:"🌸 Anilist",
|
||||||
base:"🗃️ Base content",
|
base:"🗃️ Base content",
|
||||||
"base.header":"Header",
|
"base.header":"Header",
|
||||||
@@ -120,6 +120,7 @@
|
|||||||
"people.size":{text:"Limit", type:"number", min:16, max:64},
|
"people.size":{text:"Limit", type:"number", min:16, max:64},
|
||||||
"people.limit":{text:"Limit", type:"number", min:1, max:9999},
|
"people.limit":{text:"Limit", type:"number", min:1, max:9999},
|
||||||
"people.types":{text:"Types", placeholder:"followers, following"},
|
"people.types":{text:"Types", placeholder:"followers, following"},
|
||||||
|
"people.thanks":{text:"Special thanks", placeholder:"user1, user2, ..."},
|
||||||
"people.identicons":{text:"Use identicons", type:"boolean"},
|
"people.identicons":{text:"Use identicons", type:"boolean"},
|
||||||
"anilist.medias":{text:"Medias to display", placeholder:"anime, manga"},
|
"anilist.medias":{text:"Medias to display", placeholder:"anime, manga"},
|
||||||
"anilist.sections":{text:"Sections to display", placeholder:"favorites, watching, reading, characters"},
|
"anilist.sections":{text:"Sections to display", placeholder:"favorites, watching, reading, characters"},
|
||||||
@@ -157,6 +158,7 @@
|
|||||||
"people.size":28,
|
"people.size":28,
|
||||||
"people.limit":28,
|
"people.limit":28,
|
||||||
"people.types":"followers, following",
|
"people.types":"followers, following",
|
||||||
|
"people.thanks":"",
|
||||||
"people.identicons":false,
|
"people.identicons":false,
|
||||||
"anilist.medias":"anime, manga",
|
"anilist.medias":"anime, manga",
|
||||||
"anilist.sections":"favorites",
|
"anilist.sections":"favorites",
|
||||||
|
|||||||
@@ -222,17 +222,25 @@
|
|||||||
}) : null),
|
}) : null),
|
||||||
//People
|
//People
|
||||||
...(set.plugins.enabled.people ? ({
|
...(set.plugins.enabled.people ? ({
|
||||||
people:{
|
get people() {
|
||||||
types:options["people.types"].split(",").map(x => x.trim()),
|
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"],
|
size:options["people.size"],
|
||||||
followers:new Array(Number(options["people.limit"])).fill(null).map(_ => ({
|
...(Object.fromEntries(types.map(type => [
|
||||||
login:faker.internet.userName(),
|
type,
|
||||||
avatar:"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==",
|
new Array(Number(options["people.limit"])).fill(null).map(_ => ({
|
||||||
})),
|
|
||||||
following:new Array(Number(options["people.limit"])).fill(null).map(_ => ({
|
|
||||||
login:faker.internet.userName(),
|
login:faker.internet.userName(),
|
||||||
avatar:"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==",
|
avatar:"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==",
|
||||||
}))
|
}))
|
||||||
|
]))),
|
||||||
|
thanks:options["people.thanks"].split(",").map(x => x.trim()).map(login => ({
|
||||||
|
login,
|
||||||
|
avatar:"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==",
|
||||||
|
}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}) : null),
|
}) : null),
|
||||||
//Music
|
//Music
|
||||||
|
|||||||
@@ -1,33 +1,66 @@
|
|||||||
//Setup
|
//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
|
//Plugin execution
|
||||||
try {
|
try {
|
||||||
//Check if plugin is enabled and requirements are met
|
//Check if plugin is enabled and requirements are met
|
||||||
if ((!enabled)||(!q.people))
|
if ((!enabled)||(!q.people))
|
||||||
return null
|
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
|
//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
|
||||||
limit = Math.max(1, limit)
|
limit = Math.max(1, limit)
|
||||||
//Repositories projects
|
//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
|
//Retrieve followers from graphql api
|
||||||
console.debug(`metrics/compute/${login}/plugins > people > querying 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) {
|
for (const type of types) {
|
||||||
//Iterate through people
|
//Iterate through people
|
||||||
console.debug(`metrics/compute/${login}/plugins > people > retrieving ${type}`)
|
console.debug(`metrics/compute/${login}/plugins > people > retrieving ${type}`)
|
||||||
|
//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 cursor = null
|
||||||
let pushed = 0
|
let pushed = 0
|
||||||
do {
|
do {
|
||||||
console.debug(`metrics/compute/${login}/plugins > people > retrieving ${type} after ${cursor}`)
|
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}"` : ""}))
|
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
|
cursor = edges?.[edges?.length-1]?.cursor
|
||||||
result[type].push(...edges.map(({node}) => node))
|
result[type].push(...edges.map(({node}) => node[context.sponsorships[type]] ?? node))
|
||||||
pushed = edges.length
|
pushed = edges.length
|
||||||
} while ((pushed)&&(cursor))
|
} while ((pushed)&&(cursor)&&(result[type].length <= limit))
|
||||||
|
}
|
||||||
//Limit people
|
//Limit people
|
||||||
if (limit > 0) {
|
if (limit > 0) {
|
||||||
console.debug(`metrics/compute/${login}/plugins > people > keeping only ${limit} ${type}`)
|
console.debug(`metrics/compute/${login}/plugins > people > keeping only ${limit} ${type}`)
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
query Repository {
|
query PeopleRepository {
|
||||||
user(login: "$login") {
|
user(login: "$login") {
|
||||||
repository(name: "$repository") {
|
repository(name: "$repository") {
|
||||||
$type(first: 100) {
|
$type($after first: 100) {
|
||||||
pageInfo {
|
edges {
|
||||||
hasNextPage
|
cursor
|
||||||
endCursor
|
node {
|
||||||
}
|
|
||||||
nodes {
|
|
||||||
avatarUrl(size: 24)
|
|
||||||
login
|
login
|
||||||
|
avatarUrl(size: $size)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
18
source/queries/people.sponsors.graphql
Normal file
18
source/queries/people.sponsors.graphql
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,11 +15,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<% if (plugins.people.types?.includes("followers")) { %>
|
<% for (const type of plugins.people.types) { %>
|
||||||
<section>
|
<section>
|
||||||
<h2 class="field">
|
<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>
|
<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>
|
</h2>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<section class="people">
|
<section class="people">
|
||||||
@@ -29,27 +33,7 @@
|
|||||||
<%= plugins.people.error.message %>
|
<%= plugins.people.error.message %>
|
||||||
</div>
|
</div>
|
||||||
<% } else { %>
|
<% } 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="" /><% } %>
|
<% 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>
|
|
||||||
<% } %>
|
|
||||||
<% 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="" /><% } %>
|
|
||||||
<% } %>
|
<% } %>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,5 +4,6 @@
|
|||||||
"languages",
|
"languages",
|
||||||
"projects",
|
"projects",
|
||||||
"pagespeed",
|
"pagespeed",
|
||||||
"stargazers"
|
"stargazers",
|
||||||
|
"people"
|
||||||
]
|
]
|
||||||
43
source/templates/repository/partials/people.ejs
Normal file
43
source/templates/repository/partials/people.ejs
Normal 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>
|
||||||
|
<% } %>
|
||||||
|
<% } %>
|
||||||
|
<% } %>
|
||||||
@@ -15,6 +15,11 @@
|
|||||||
console.debug(`metrics/compute/${login}/${repo} > retrieving single repository ${repo}`)
|
console.debug(`metrics/compute/${login}/${repo} > retrieving single repository ${repo}`)
|
||||||
const {user:{repository}} = await graphql(queries.repository({login, repo}))
|
const {user:{repository}} = await graphql(queries.repository({login, repo}))
|
||||||
data.user.repositories.nodes = [repository]
|
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
|
//Get commit activity
|
||||||
console.debug(`metrics/compute/${login}/${repo} > querying api for commits`)
|
console.debug(`metrics/compute/${login}/${repo} > querying api for commits`)
|
||||||
|
|||||||
@@ -286,6 +286,27 @@
|
|||||||
plugin_people:true,
|
plugin_people:true,
|
||||||
plugin_people_types:"following",
|
plugin_people_types:"following",
|
||||||
}, {skip:["terminal", "repository"]}],
|
}, {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)", {
|
["People plugin (identicons)", {
|
||||||
plugin_people:true,
|
plugin_people:true,
|
||||||
plugin_people_identicons:true,
|
plugin_people_identicons:true,
|
||||||
|
|||||||
Reference in New Issue
Block a user