Skip to content

Commit

Permalink
Add people plugin (#48)
Browse files Browse the repository at this point in the history
  • Loading branch information
lowlighter authored Jan 11, 2021
1 parent c5723ad commit 4ef1b73
Show file tree
Hide file tree
Showing 12 changed files with 279 additions and 7 deletions.
60 changes: 58 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,19 +164,36 @@ But there's more with [plugins](https://github.com/lowlighter/metrics/tree/maste
</tr>
<tr>
<th><a href="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/lowlighter/metrics#-gists">🎫 Gists plugin</a></th>
<th><a href="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/lowlighter/metrics#%EF%B8%8F-base-content">🗃️ Header special features</a></th>
<th><a href="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/lowlighter/metrics#-people">🧑‍🤝‍🧑 People plugin <sup><code>🚧 @master</code></sup></a></th>
</tr>
<tr>
<td>
<a href="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/lowlighter/metrics#-gists">
<img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.gists.svg" alt="" width="400">
</a>
</td>
<td>
<a href="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/lowlighter/metrics#-people">
<img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.people.followers.svg" alt="" width="400">
</a>
<details><summary>Followed people version</summary>
<a href="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/lowlighter/metrics#-habits">
<img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.people.following.svg" alt="" width="400">
</a>
</details>
</td>
</tr>
<tr>
<th><a href="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/lowlighter/metrics#%EF%B8%8F-base-content">🗃️ Header special features</a></th>
<th></th>
</tr>
<tr>
<td>
<a href="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/lowlighter/metrics#%EF%B8%8F-base-content">
<img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.header.svg" alt="" width="400">
</a>
</td>
<td></td>
</tr>
<tr>
<td colspan="2" align="center">
Expand Down Expand Up @@ -534,6 +551,7 @@ Used template defaults to the `classic` one.
<th><span title="Stars">🌟</span></th>
<th><span title="Stargazers">✨</span></th>
<th><span title="Gists">🎫</span></th>
<th><span title="People">🧑‍🤝‍🧑</span></th>
</tr>
<tr>
<th>Classic</th>
Expand All @@ -550,10 +568,11 @@ Used template defaults to the `classic` one.
<td data-for="tweets">✔️</td>
<td data-for="posts">✔️</td>
<td data-for="habits">✔️</td>
<th><span title="Available on @master">✔️<sup>M</sup></span></th>
<td data-for="activity"><span title="Available on @master">✔️<sup>M</sup></span></td>
<td data-for="stars">✔️</td>
<td data-for="stargazers">✔️</td>
<td data-for="gists">✔️</td>
<td data-for="people"><span title="Available on @master">✔️<sup>M</sup></span></td>
</tr>
<tr>
<th>Terminal</th>
Expand All @@ -574,6 +593,7 @@ Used template defaults to the `classic` one.
<td data-for="stars">❌</td>
<td data-for="stargazers">❌</td>
<td data-for="gists">✔️</td>
<td data-for="people">❌</td>
</tr>
<tr>
<th>Repository<sup>R</sup></th>
Expand All @@ -594,6 +614,7 @@ Used template defaults to the `classic` one.
<td data-for="stars">❌</td>
<td data-for="stargazers">✔️</td>
<td data-for="gists">❌</td>
<td data-for="people">❌</td>
</tr>
</table>

Expand Down Expand Up @@ -1381,6 +1402,41 @@ Add the following to your workflow :

</details>

### 🧑‍🤝‍🧑 People

🚧 This plugin is available as pre-release on @master branch (unstable)

The *people* plugin displays your followers and followed users' avatars.

![People plugin](https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.people.svg)

<details>
<summary>💬 About</summary>

It will consume an additional GitHub request per group of 100 users fetched.

Add the following to your workflow :
```yaml
- uses: lowlighter/metrics@master
with:
# ... other options
plugin_people: yes
plugin_people_types: followers, following
plugin_people_limit: 28
plugin_people_size: 28 # Size in pixels of displayed avatars
```

It is possible to use [identicons](https://github.blog/2013-08-14-identicons/) instead of their avatar for privacy purposes.

```yaml
- uses: lowlighter/metrics@master
with:
# ... other options
plugin_people_identicons: yes
```

</details>

### 🔧 Other options

A few additional options are available.
Expand Down
33 changes: 31 additions & 2 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ inputs:
description: Number of activity events to display
default: 5

# Disacard older events
# Discard older events
# Use 0 to display activity whatever the date
plugin_activity_days:
description: Maximum activity event age
Expand All @@ -400,6 +400,35 @@ inputs:
description: Events to display
default: all

# Display followed and following users
plugin_people:
description: Display
default: no

# Limit the number of users displayed
plugin_people_limit:
description: Number of users to display per categorie
default: 28

# Configure image size of users' avatar
plugin_people_size:
description: Size of users' avatars
default: 28

# List of users categories to display (comma separated)
# Supported values are:
# - "followers"
# - "following"
plugin_people_types:
description: Categories to display
default: followers, following

# Display GitHub identicons instead of users' real avatar
# Mostly for privacy purposes
plugin_people_identicons:
description: Use identicons instead of real avatars
default: no

# ====================================================================================
# Options below are mostly used for testing

Expand Down Expand Up @@ -497,7 +526,7 @@ runs:
set -e
echo "Is released version: $METRICS_IS_RELEASED"
# Rebuild image for unreleased version
if [[ $METRICS_IS_RELEASED ]]; then
if [[ "$METRICS_IS_RELEASED" -gt "0" ]]; then
echo "Using released version $METRICS_TAG, will pull docker image from GitHub registry"
METRICS_IMAGE=ghcr.io/lowlighter/metrics:$METRICS_TAG
# Use registry for released version
Expand Down
3 changes: 3 additions & 0 deletions settings.example.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@
},
"activity":{ "//":"Activity plugin",
"enabled":false, "//":"Enable or disable recent activity display"
},
"people":{ "//":"People plugin",
"enabled":false, "//":"Enable or disable people display"
}
}
}
10 changes: 10 additions & 0 deletions source/app/action/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@
stars:{enabled:input.bool("plugin_stars")},
stargazers:{enabled:input.bool("plugin_stargazers")},
activity:{enabled:input.bool("plugin_activity")},
people:{enabled:input.bool("plugin_people")},
}
let q = Object.fromEntries(Object.entries(plugins).filter(([key, plugin]) => plugin.enabled).map(([key]) => [key, true]))
info("Plugins enabled", Object.entries(plugins).filter(([key, plugin]) => plugin.enabled).map(([key]) => key))
Expand Down Expand Up @@ -223,6 +224,15 @@
for (const option of ["filter"])
info(`Activity ${option}`, q[`activity.${option}`] = input.array(`plugin_activity_${option}`))
}
//People
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"])
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}`))
}

//Repositories to use
const repositories = input.number("repositories")
Expand Down
2 changes: 1 addition & 1 deletion source/app/metrics.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
//Additional SVG transformations
if (/svg/.test(mime)) {
//Optimize rendering
if ((conf.optimize)&&(!q.raw)) {
if ((conf.settings?.optimize)&&(!q.raw)) {
console.debug(`metrics/compute/${login} > optimize`)
const svgo = new SVGO({full:true, plugins:[{cleanupAttrs:true}, {inlineStyles:false}]})
const {data:optimized} = await svgo.optimize(rendered)
Expand Down
24 changes: 24 additions & 0 deletions source/app/mocks.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,30 @@
}
})
}
//People query
if (/^query People /.test(query)) {
console.debug(`metrics/compute/mocks > mocking graphql api result > People`)
const type = query.match(/(?<type>followers|following)[(]/)?.groups?.type ?? "(unknown type)"
return /after: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"/m.test(query) ? ({
user:{
[type]:{
edges:[],
}
}
}) : ({
user:{
[type]:{
edges:new Array(Math.ceil(20+80*Math.random())).fill(null).map(() => ({
cursor:"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
node:{
login:"user",
avatarUrl:"https://github.com/identicons/user.png",
}
}))
}
}
})
}
//Unmocked call
return target(...args)
}
Expand Down
53 changes: 53 additions & 0 deletions source/plugins/people/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//Setup
export default async function ({login, graphql, q, queries, imports}, {enabled = false} = {}) {
//Plugin execution
try {
//Check if plugin is enabled and requirements are met
if ((!enabled)||(!q.people))
return null

//Parameters override
let {"people.limit":limit = 28, "people.types":types = "followers, following", "people.size":size = 28, "people.identicons":identicons = false} = q
//Limit
limit = Math.max(1, limit)
//Repositories projects
types = decodeURIComponent(types ?? "").split(",").map(type => type.trim()).filter(type => ["followers", "following"].includes(type)) ?? []

//Retrieve followers from graphql api
console.debug(`metrics/compute/${login}/plugins > people > querying api`)
const result = {followers:[], following:[]}
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))
//Limit people
if (limit > 0) {
console.debug(`metrics/compute/${login}/plugins > people > keeping only ${limit} ${type}`)
result[type].splice(limit)
}
//Hide real avator with identicons if enabled
if (identicons) {
console.debug(`metrics/compute/${login}/plugins > people > using identicons`)
result[type].map(user => user.avatarUrl = `https://github.com/identicons/${user.login}.png`)
}
//Convert avatars to base64
console.debug(`metrics/compute/${login}/plugins > people > loading avatars`)
await Promise.all(result[type].map(async user => user.avatar = await imports.imgb64(user.avatarUrl)))
}

//Results
return {types, size, ...result}
}
//Handle errors
catch (error) {
throw {error:{message:"An error occured", instance:error}}
}
}
2 changes: 1 addition & 1 deletion source/plugins/projects/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//Parameters override
let {"projects.limit":limit = 4, "projects.repositories":repositories = ""} = q
//Repositories projects
repositories = repositories?.split(",").map(repository => repository.trim()).filter(repository => /[-\w]+[/][-\w]+[/]projects[/]\d+/.test(repository)) ?? []
repositories = decodeURIComponent(repositories ?? "").split(",").map(repository => repository.trim()).filter(repository => /[-\w]+[/][-\w]+[/]projects[/]\d+/.test(repository)) ?? []
//Limit
limit = Math.max(repositories.length, Math.min(100, Number(limit)))
//Retrieve user owned projects from graphql api
Expand Down
14 changes: 14 additions & 0 deletions source/queries/people.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
query People {
user(login: "$login") {
login
$type($after first: 100) {
edges {
cursor
node {
login
avatarUrl(size: $size)
}
}
}
}
}
60 changes: 60 additions & 0 deletions source/templates/classic/image.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 4ef1b73

Please sign in to comment.