Add new plugin topics (#12)
This commit is contained in:
44
.github/workflows/build.yml
vendored
44
.github/workflows/build.yml
vendored
@@ -180,3 +180,47 @@ jobs:
|
||||
plugin_gists: yes
|
||||
plugins_errors_fatal: yes
|
||||
dryrun: yes
|
||||
|
||||
- name: Topics plugin (stars)
|
||||
uses: lowlighter/metrics@master
|
||||
with:
|
||||
token: ${{ secrets.METRICS_TOKEN }}
|
||||
base: ""
|
||||
repositories: 1
|
||||
plugin_topics: yes
|
||||
plugin_topics_sort: stars
|
||||
plugins_errors_fatal: yes
|
||||
dryrun: yes
|
||||
|
||||
- name: Topics plugin (activity)
|
||||
uses: lowlighter/metrics@master
|
||||
with:
|
||||
token: ${{ secrets.METRICS_TOKEN }}
|
||||
base: ""
|
||||
repositories: 1
|
||||
plugin_topics: yes
|
||||
plugin_topics_sort: activity
|
||||
plugins_errors_fatal: yes
|
||||
dryrun: yes
|
||||
|
||||
- name: Topics plugin (starred)
|
||||
uses: lowlighter/metrics@master
|
||||
with:
|
||||
token: ${{ secrets.METRICS_TOKEN }}
|
||||
base: ""
|
||||
repositories: 1
|
||||
plugin_topics: yes
|
||||
plugin_topics_sort: starred
|
||||
plugins_errors_fatal: yes
|
||||
dryrun: yes
|
||||
|
||||
- name: Topics plugin (random)
|
||||
uses: lowlighter/metrics@master
|
||||
with:
|
||||
token: ${{ secrets.METRICS_TOKEN }}
|
||||
base: ""
|
||||
repositories: 1
|
||||
plugin_topics: yes
|
||||
plugin_topics_sort: random
|
||||
plugins_errors_fatal: yes
|
||||
dryrun: yes
|
||||
23
action.yml
23
action.yml
@@ -206,6 +206,29 @@ inputs:
|
||||
description: Display gists metrics
|
||||
default: no
|
||||
|
||||
# Topics plugins
|
||||
# Display starred topics
|
||||
plugin_topics:
|
||||
description: Display starred topics
|
||||
default: no
|
||||
|
||||
# Sorting method of topics
|
||||
# Supported values are :
|
||||
# - "stars" to sort them from most starred to least starred
|
||||
# - "activity" to sort them from most recent activity to least recent activity
|
||||
# - "starred" to sort them from your most recently starred to your least recently starred
|
||||
# - "random" to sort them randomly
|
||||
plugin_topics_sort:
|
||||
description: Sorting method of starred topics
|
||||
default: "stars"
|
||||
|
||||
# Limit the number of topics displayed
|
||||
# Between 1 and 20
|
||||
# If more topics must be displayed, they will be grouped in an ellipsis
|
||||
plugin_topics_limit:
|
||||
description: Number of starred topics to display
|
||||
default: 15
|
||||
|
||||
# Enable debug mode
|
||||
# Be sure to put all secrets in your repository secrets before to avoid any leaks !
|
||||
debug:
|
||||
|
||||
16
action/dist/index.js
vendored
16
action/dist/index.js
vendored
File diff suppressed because one or more lines are too long
@@ -83,6 +83,7 @@
|
||||
posts:{enabled:bool(core.getInput("plugin_posts"))},
|
||||
isocalendar:{enabled:bool(core.getInput("plugin_isocalendar"))},
|
||||
gists:{enabled:bool(core.getInput("plugin_gists"))},
|
||||
topics:{enabled:bool(core.getInput("plugin_topics"))},
|
||||
}
|
||||
let q = Object.fromEntries(Object.entries(plugins).filter(([key, plugin]) => plugin.enabled).map(([key]) => [key, true]))
|
||||
console.log(`Plugins enabled | ${Object.entries(plugins).filter(([key, plugin]) => plugin.enabled).map(([key]) => key).join(", ")}`)
|
||||
@@ -115,6 +116,13 @@
|
||||
q["isocalendar.duration"] = core.getInput("plugin_isocalendar_duration") ?? "half-year"
|
||||
console.log(`Isocalendar duration| ${q["isocalendar.duration"]}`)
|
||||
}
|
||||
//Topics
|
||||
if (plugins.topics.enabled) {
|
||||
for (const option of ["sort", "limit"])
|
||||
q[`topics.${option}`] = core.getInput(`plugin_topics_${option}`) || null
|
||||
console.log(`Topics sort mode | ${q["topics.sort"]}`)
|
||||
console.log(`Topics limit | ${q["topics.limit"]}`)
|
||||
}
|
||||
|
||||
//Repositories to use
|
||||
const repositories = Number(core.getInput("repositories")) || 100
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "metrics",
|
||||
"version": "2.5.0",
|
||||
"version": "2.6.0",
|
||||
"description": "Generate an user's GitHub metrics as SVG image format to embed somewhere else",
|
||||
"main": "index.mjs",
|
||||
"scripts": {
|
||||
|
||||
@@ -47,6 +47,9 @@
|
||||
},
|
||||
"gists":{ "//":"Gists plugin",
|
||||
"enabled":false, "//":"Enable or disable gists metrics"
|
||||
},
|
||||
"topics":{ "//":"Topics plugin",
|
||||
"enabled":false, "//":"Enable or disable starred topics display"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@
|
||||
posts:"Recent posts",
|
||||
isocalendar:"Isometric commit calendar",
|
||||
gists:"Gists metrics",
|
||||
topics:"Starred topics",
|
||||
"base.header":"Header",
|
||||
"base.activity":"Account activity",
|
||||
"base.community":"Community stats",
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
//Compute metrics
|
||||
console.debug(`metrics/compute/${login} > compute`)
|
||||
const computer = Templates[template].default || Templates[template]
|
||||
await computer({login, q}, {conf, data, rest, graphql, plugins}, {s, pending, imports:{plugins:Plugins, url, imgb64, axios, puppeteer, format, bytes, shuffle}})
|
||||
await computer({login, q}, {conf, data, rest, graphql, plugins}, {s, pending, imports:{plugins:Plugins, url, imgb64, axios, puppeteer, format, bytes, shuffle, htmlescape}})
|
||||
const promised = await Promise.all(pending)
|
||||
|
||||
//Check plugins errors
|
||||
@@ -113,6 +113,16 @@
|
||||
return array
|
||||
}
|
||||
|
||||
/** Escape html */
|
||||
function htmlescape(string) {
|
||||
return string
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """)
|
||||
.replace(/'/g, "'")
|
||||
}
|
||||
|
||||
/** Placeholder generator */
|
||||
function placeholder({data, conf, q}) {
|
||||
//Proxifier
|
||||
@@ -154,6 +164,7 @@
|
||||
followup:{issues:{count:0}, pr:{count:0}},
|
||||
habits:{indents:{style:`########`}},
|
||||
languages:{favorites:new Array(7).fill(null).map((_, x) => ({x, name:`######`, color:"#ebedf0", value:1/(x+1)}))},
|
||||
topics:{list:[...new Array(12).fill(null).map(() => ({name:`######`, description:`Lorem ipsum dolor sit amet, consectetur adipiscing elit.`, icon:null})), {name:`And ## more...`, description:"", icon:null}]},
|
||||
}[key]??{})]
|
||||
)),
|
||||
token:{scopes:[]},
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
import pagespeed from "./pagespeed/index.mjs"
|
||||
import posts from "./posts/index.mjs"
|
||||
import selfskip from "./selfskip/index.mjs"
|
||||
import topics from "./topics/index.mjs"
|
||||
import traffic from "./traffic/index.mjs"
|
||||
|
||||
//Exports
|
||||
@@ -25,5 +26,6 @@
|
||||
pagespeed,
|
||||
posts,
|
||||
selfskip,
|
||||
topics,
|
||||
traffic,
|
||||
}
|
||||
67
src/plugins/topics/index.mjs
Normal file
67
src/plugins/topics/index.mjs
Normal file
@@ -0,0 +1,67 @@
|
||||
//Setup
|
||||
export default async function ({login, imports, q}, {enabled = false} = {}) {
|
||||
//Plugin execution
|
||||
try {
|
||||
//Check if plugin is enabled and requirements are met
|
||||
if ((!enabled)||(!q.topics))
|
||||
return null
|
||||
//Parameters override
|
||||
let {"topics.sort":sort = "stars", "topics.limit":limit = 15} = q
|
||||
//Shuffle
|
||||
const shuffle = (sort === "random")
|
||||
//Sort method
|
||||
sort = {starred:"created", activity:"updated", stars:"stars", random:"created"}[sort] ?? "starred"
|
||||
//Limit
|
||||
limit = Math.max(1, Math.min(20, Number(limit)))
|
||||
//Start puppeteer and navigate to topics
|
||||
let topics = []
|
||||
console.debug(`metrics/compute/${login}/plugins > topics > starting browser`)
|
||||
const browser = await imports.puppeteer.launch({headless:true, executablePath:process.env.PUPPETEER_BROWSER_PATH, args:["--no-sandbox", "--disable-extensions", "--disable-setuid-sandbox", "--disable-dev-shm-usage"]})
|
||||
console.debug(`metrics/compute/${login}/plugins > topics > loaded ${await browser.version()}`)
|
||||
const page = await browser.newPage()
|
||||
//Iterate through pages
|
||||
for (let i = 1; i <= 100; i++) {
|
||||
//Load page
|
||||
console.debug(`metrics/compute/${login}/plugins > topics > loading page ${i}`)
|
||||
await page.goto(`https://github.com/stars/${login}/topics?direction=desc&page=${i}&sort=${sort}`)
|
||||
const frame = page.mainFrame()
|
||||
//Extract topics
|
||||
await Promise.race([frame.waitForSelector("ul.repo-list"), frame.waitForSelector(".blankslate")])
|
||||
const starred = await frame.evaluate(() => [...document.querySelectorAll("ul.repo-list li")].map(li => ({
|
||||
name:li.querySelector(".f3").innerText,
|
||||
description:li.querySelector(".f5").innerText,
|
||||
icon:li.querySelector("img")?.src ?? null,
|
||||
})))
|
||||
//Check if next page exists
|
||||
if (!starred.length)
|
||||
break
|
||||
topics.push(...starred)
|
||||
}
|
||||
//Shuffle topics
|
||||
if (shuffle)
|
||||
topics = imports.shuffle(topics)
|
||||
//Limit topics
|
||||
if (limit > 0) {
|
||||
console.debug(`metrics/compute/${login}/plugins > topics > keeping only ${limit} topics`)
|
||||
const removed = topics.slice(limit)
|
||||
topics = topics.slice(0, limit)
|
||||
topics.push({name:`And ${removed.length} more...`, description:removed.map(({name}) => name).join(", "), icon:null})
|
||||
}
|
||||
//Convert icons to base64
|
||||
for (const topic of topics) {
|
||||
if (topic.icon) {
|
||||
console.debug(`metrics/compute/${login}/plugins > topics > processing ${topic.name}`)
|
||||
topic.icon = await imports.imgb64(topic.icon)
|
||||
}
|
||||
//Escape HTML description
|
||||
topic.description = imports.htmlescape(topic.description)
|
||||
}
|
||||
//Results
|
||||
return {list:topics}
|
||||
}
|
||||
//Handle errors
|
||||
catch (error) {
|
||||
console.debug(error)
|
||||
throw {error:{message:`An error occured`}}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
+ (!!computed.plugins.posts)*64 + (computed.plugins.posts ? computed.plugins.posts.posts ? Math.max(0, computed.plugins.posts.posts.length)*40 : 0 : 0)
|
||||
+ (!!computed.plugins.isocalendar)*192 + (computed.plugins.isocalendar ? computed.plugins.isocalendar.duration === 'full-year' ? 100 : 0 : 0)
|
||||
+ (!!computed.plugins.gists)*68
|
||||
+ (!!computed.plugins.topics)*160
|
||||
+ Math.max(0, (((!!base.metadata)+(!!base.header)+((!!base.activity)||(!!base.community))+(!!base.repositories)+((!!computed.plugins.habits))+(!!computed.plugins.pagespeed)+(!!computed.plugins.languages)+(!!computed.plugins.music)+(!!computed.plugins.posts)+(!!computed.plugins.isocalendar)+(!!computed.plugins.gists))-1))*4
|
||||
%>">
|
||||
|
||||
@@ -396,6 +397,33 @@
|
||||
</section>
|
||||
<% } %>
|
||||
|
||||
<% if (computed.plugins.topics) { %>
|
||||
<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="M14.184 1.143a1.75 1.75 0 00-2.502-.57L.912 7.916a1.75 1.75 0 00-.53 2.32l.447.775a1.75 1.75 0 002.275.702l11.745-5.656a1.75 1.75 0 00.757-2.451l-1.422-2.464zm-1.657.669a.25.25 0 01.358.081l1.422 2.464a.25.25 0 01-.108.35l-2.016.97-1.505-2.605 1.85-1.26zM9.436 3.92l1.391 2.41-5.42 2.61-.942-1.63 4.97-3.39zM3.222 8.157l-1.466 1a.25.25 0 00-.075.33l.447.775a.25.25 0 00.325.1l1.598-.769-.83-1.436zm6.253 2.306a.75.75 0 00-.944-.252l-1.809.87a.75.75 0 00-.293.253L4.38 14.326a.75.75 0 101.238.848l1.881-2.75v2.826a.75.75 0 001.5 0v-2.826l1.881 2.75a.75.75 0 001.238-.848l-2.644-3.863z"></path></svg>
|
||||
Starred topics
|
||||
</h2>
|
||||
<div class="row">
|
||||
<% if (computed.plugins.topics.error) { %>
|
||||
<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>
|
||||
<%= computed.plugins.topics.error.message %>
|
||||
</div>
|
||||
</section>
|
||||
<% } else { %>
|
||||
<section>
|
||||
<div class="topics fill-width">
|
||||
<% for (const {name, description} of computed.plugins.topics.list) { %>
|
||||
<div class="label" title="<%= description %>"><%= name.toLocaleLowerCase() %></div>
|
||||
<% } %>
|
||||
</div>
|
||||
</section>
|
||||
<% } %>
|
||||
</div>
|
||||
</section>
|
||||
<% } %>
|
||||
|
||||
<% if (computed.plugins.music) { %>
|
||||
<section>
|
||||
<h2 class="field">
|
||||
|
||||
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 52 KiB |
@@ -113,6 +113,24 @@
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
/* Labels */
|
||||
.label {
|
||||
background-color: #F1F8FF;
|
||||
color: #0366D6;
|
||||
padding: 0 10px;
|
||||
font-weight: 500;
|
||||
line-height: 22px;
|
||||
margin: 2px 5px;
|
||||
white-space: nowrap;
|
||||
border-radius: 32px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.label:hover {
|
||||
background-color: #DDEEFF;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Habits */
|
||||
.habits {
|
||||
margin: 0;
|
||||
@@ -242,6 +260,12 @@
|
||||
padding-top: 1px;
|
||||
}
|
||||
|
||||
/* Topics */
|
||||
.topics {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
/* Fade animation */
|
||||
.af {
|
||||
opacity: 0;
|
||||
|
||||
Reference in New Issue
Block a user