@@ -568,7 +627,7 @@
<% } %>
- <% if (computed.plugins.isocalendar) { %>
+ <% if (plugins.isocalendar) { %>
@@ -576,28 +635,28 @@
- <% if (computed.plugins.isocalendar.error) { %>
+ <% if (plugins.isocalendar.error) { %>
- <%= computed.plugins.isocalendar.error.message %>
+ <%= plugins.isocalendar.error.message %>
<% } %>
- <% if (!computed.plugins.isocalendar.error) { %>
+ <% if (!plugins.isocalendar.error) { %>
- Current streak <%= computed.plugins.isocalendar.streak.current %> day<%= s(computed.plugins.isocalendar.streak.current) %>
+ Current streak <%= plugins.isocalendar.streak.current %> day<%= s(plugins.isocalendar.streak.current) %>
- ~<%= computed.plugins.isocalendar.average %> commits per day
+ ~<%= plugins.isocalendar.average %> commits per day
<% } %>
- <% if (computed.plugins.isocalendar.svg) { %>
- <%- computed.plugins.isocalendar.svg %>
+ <% if (plugins.isocalendar.svg) { %>
+ <%- plugins.isocalendar.svg %>
<% } %>
<% } %>
diff --git a/src/templates/classic/style.css b/src/templates/classic/style.css
index d35a97b2..f55fdf2b 100644
--- a/src/templates/classic/style.css
+++ b/src/templates/classic/style.css
@@ -207,6 +207,24 @@
stroke-dasharray: 0 329;
}
}
+ .audits {
+ margin-top: 8px;
+ }
+ .audit.text {
+ min-width: 36px;
+ }
+ .audit svg {
+ margin: 0;
+ }
+ .audit.high {
+ fill: #18b663;
+ }
+ .audit.average {
+ fill: #fb8c00;
+ }
+ .audit.low {
+ fill: #e53935;
+ }
/* Music plugin */
.tracklist {
diff --git a/src/templates/common.mjs b/src/templates/common.mjs
index 036afd67..a388fa8e 100644
--- a/src/templates/common.mjs
+++ b/src/templates/common.mjs
@@ -2,20 +2,21 @@
export default async function ({login, q}, {conf, data, rest, graphql, plugins}, {s, pending, imports}) {
//Init
- const computed = data.computed = {commits:0, sponsorships:0, licenses:{favorite:"", used:{}}, token:{}, repositories:{watchers:0, stargazers:0, issues_open:0, issues_closed:0, pr_open:0, pr_merged:0, forks:0, releases:0}, plugins:{}}
+ const computed = data.computed = {commits:0, sponsorships:0, licenses:{favorite:"", used:{}}, token:{}, repositories:{watchers:0, stargazers:0, issues_open:0, issues_closed:0, pr_open:0, pr_merged:0, forks:0, releases:0}}
const avatar = imports.imgb64(data.user.avatarUrl)
+ data.plugins = {}
//Plugins
for (const name of Object.keys(imports.plugins)) {
pending.push((async () => {
try {
- computed.plugins[name] = await imports.plugins[name]({login, q, imports, data, computed, rest, graphql}, plugins[name])
+ data.plugins[name] = await imports.plugins[name]({login, q, imports, data, computed, rest, graphql}, plugins[name])
}
catch (error) {
- computed.plugins[name] = error
+ data.plugins[name] = error
}
finally {
- return {name, result:computed.plugins[name]}
+ return {name, result:data.plugins[name]}
}
})())
}
diff --git a/src/templates/terminal/image.svg b/src/templates/terminal/image.svg
index c73e16ff..3408f02d 100644
--- a/src/templates/terminal/image.svg
+++ b/src/templates/terminal/image.svg
@@ -4,16 +4,16 @@
+ (!!base.activity)*108
+ (!!base.community)*94
+ (!!base.repositories)*142
- + ((!!base.repositories)*(!!computed.plugins.traffic))*18
- + ((!!base.repositories)*(!!computed.plugins.followup))*102
- + ((!!base.repositories)*(!!computed.plugins.lines))*34
- + (!!computed.plugins.pagespeed)*110
- + (!!computed.plugins.languages)*124
- + Math.max(0, (((!!base.metadata)+(!!base.header)+((!!base.activity)||(!!base.community))+(!!base.repositories)+(!!computed.plugins.pagespeed)+(!!computed.plugins.languages))-1))*20
+ + ((!!base.repositories)*(!!plugins.traffic))*18
+ + ((!!base.repositories)*(!!plugins.followup))*102
+ + ((!!base.repositories)*(!!plugins.lines))*34
+ + (!!plugins.pagespeed)*110
+ + (!!plugins.languages)*124
+ + Math.max(0, (((!!base.metadata)+(!!base.header)+((!!base.activity)||(!!base.community))+(!!base.repositories)+(!!plugins.pagespeed)+(!!plugins.languages))-1))*20
%>">
<%
meta.$ = `
${`${user.login}`.toLocaleLowerCase()}@metrics:
~${computed.token.scopes.includes("repo") ? "#" : "$"}`
- meta.animations = !meta.placeholder ? {stdin:.16, stdout:.28, length:(2+Object.keys(base).length+Object.keys(computed.plugins).length)} : {stdin:0, stdout:0, length:0}
+ meta.animations = !meta.placeholder ? {stdin:.16, stdout:.28, length:(2+Object.keys(base).length+Object.keys(plugins).length)} : {stdin:0, stdout:0, length:0}
%>
@@ -98,55 +98,55 @@ Last generated: <%= new Date().toGMTString() %>
<%- meta.$ %> ls -lh github/repositories
<%# -%>
<%# -%>
Total <%= user.repositories.totalCount %> repositor<%= s(user.repositories.totalCount, "y") %> - <%= computed.diskUsage %>
-<% if (computed.plugins.traffic) { if (computed.plugins.traffic.error) { -%>
----- views (<%= computed.plugins.traffic.error.message %>)
+<% if (plugins.traffic) { if (plugins.traffic.error) { -%>
+---- views (<%= plugins.traffic.error.message %>)
<% } else { -%>
--r-- <%= `${computed.plugins.traffic.views.count}`.padStart(5) %> views
+-r-- <%= `${plugins.traffic.views.count}`.padStart(5) %> views
<% }} -%>
-r-- <%= `${computed.repositories.stargazers}`.padStart(5) %> stargazer<%= s(computed.repositories.stargazers) %>
-r-- <%= `${computed.repositories.forks}`.padStart(5) %> fork<%= s(computed.repositories.forks) %>
-r-- <%= `${computed.repositories.watchers}`.padStart(5) %> watcher<%= s(computed.repositories.watchers) %>
dr-x <%= `${user.packages.totalCount}`.padStart(5) %> package<%= s(user.packages.totalCount) %>
dr-x <%= `${user.gists.totalCount}`.padStart(5) %> gist<%= s(user.gists.totalCount) %>
-<% if (computed.plugins.followup) { if (computed.plugins.followup.error) { -%>
-d--- ISSUES (<%= computed.plugins.followup.error.message %>)
-d--- PULL_REQUESTS (<%= computed.plugins.followup.error.message %>)
+<% if (plugins.followup) { if (plugins.followup.error) { -%>
+d--- ISSUES (<%= plugins.followup.error.message %>)
+d--- PULL_REQUESTS (<%= plugins.followup.error.message %>)
<% } else { -%>
-dr-x <%= `${computed.plugins.followup.issues.count}`.padStart(5) %> ISSUES
--r-- <%= `${computed.plugins.followup.issues.open}`.padStart(5) %> ├── open
--r-- <%= `${computed.plugins.followup.issues.closed}`.padStart(5) %> └── closed
-dr-x <%= `${computed.plugins.followup.issues.count}`.padStart(5) %> PULL_REQUESTS
--r-- <%= `${computed.plugins.followup.pr.open}`.padStart(5) %> ├── open
--r-- <%= `${computed.plugins.followup.pr.merged}`.padStart(5) %> └── merged
+dr-x <%= `${plugins.followup.issues.count}`.padStart(5) %> ISSUES
+-r-- <%= `${plugins.followup.issues.open}`.padStart(5) %> ├── open
+-r-- <%= `${plugins.followup.issues.closed}`.padStart(5) %> └── closed
+dr-x <%= `${plugins.followup.issues.count}`.padStart(5) %> PULL_REQUESTS
+-r-- <%= `${plugins.followup.pr.open}`.padStart(5) %> ├── open
+-r-- <%= `${plugins.followup.pr.merged}`.padStart(5) %> └── merged
<% }} -%>
<% if (computed.licenses.favorite.length) { -%>
dr-x LICENSE
-r-- └── <%= computed.licenses.favorite %>
<% } -%>
-<% if (computed.plugins.lines) { if (computed.plugins.lines.error) { %>
-@@ <%= computed.plugins.lines.error.message %> @@<% } else { %>
-@@ -<%= computed.plugins.lines.deleted %> +<%= computed.plugins.lines.added %> @@
+<% if (plugins.lines) { if (plugins.lines.error) { %>
+@@ <%= plugins.lines.error.message %> @@<% } else { %>
+@@ -<%= plugins.lines.deleted %> +<%= plugins.lines.added %> @@
<% }} -%>
<% } -%>
<%# ============================================================= -%>
-<% if (computed.plugins.languages) { %>
+<% if (plugins.languages) { %>
<%- meta.$ %> locale
<%# -%>
<%# -%>
-<% if (computed.plugins.languages.error) { -%>
-<%= computed.plugins.languages.error.message %><%# -%>
-<% } else { for (const {name, value} of computed.plugins.languages.favorites) { -%>
+<% if (plugins.languages.error) { -%>
+<%= plugins.languages.error.message %><%# -%>
+<% } else { for (const {name, value} of plugins.languages.favorites) { -%>
<%= name.toLocaleUpperCase().padEnd(12) %> [<%= "#".repeat(Math.ceil(100*value/5)).padEnd(20) %>] <%= (100*value).toFixed(2).padEnd(5) %>%
<% }} -%>
<% } -%>
<%# ============================================================= -%>
-<% if (computed.plugins.pagespeed) { %>
+<% if (plugins.pagespeed) { %>
<%- meta.$ %> curl -I <%= user.websiteUrl %>
<%# -%>
<%# -%>
-<% if (computed.plugins.pagespeed.error) { -%>
-<%= computed.plugins.pagespeed.error.message %><% } else { -%>
+<% if (plugins.pagespeed.error) { -%>
+<%= plugins.pagespeed.error.message %><% } else { -%>
User-Agent: Google PageSpeed API
Location: <%= user.websiteUrl %>
-<% for (const {score, title} of computed.plugins.pagespeed.scores) { -%>
+<% for (const {score, title} of plugins.pagespeed.scores) { -%>
<%= `X-${title.replace(/ /g, "-")}` %>: <%= !Number.isNaN(score) ? Math.round(score*100) : "-" %>%
<% }} -%>
<% } -%>
diff --git a/utils/build.mjs b/utils/build.mjs
index c34ca018..8f35bb10 100644
--- a/utils/build.mjs
+++ b/utils/build.mjs
@@ -5,10 +5,13 @@
import ncc from "@vercel/ncc"
import minify from "babel-minify"
import colors from "colors"
+ import ejs from "ejs"
//Initialization
const __dirname = path.join(path.dirname(url.fileURLToPath(import.meta.url)), "..")
const __action = path.join(__dirname, "action")
+ const __workflows = path.join(__dirname, ".github/workflows")
+ const __utils = path.join(__dirname, "utils")
const __src = path.join(__dirname, "src")
const __plugins = path.join(__src, "plugins")
const __templates = path.join(__src, "templates")
@@ -57,6 +60,48 @@
}
+ //Workflow
+ {
+ //Build
+ const code = await ejs.renderFile(path.join(__utils, "workflow.yml"), {
+ releases:["master", "latest"],
+ templates:(await fs.promises.readdir(__templates)).filter(name => !/.*[.]mjs$/.test(name)).sort(),
+ testcase(context = {}) {
+ return [`with:`, ...Object.entries({
+ token:"${{ secrets.METRICS_TOKEN }}",
+ dryrun:true,
+ repositories:1,
+ template:"${{ matrix.template }}",
+ base:"",
+ plugins_errors_fatal:true,
+ ...context
+ }).map(([key, value]) => `${" ".repeat(5)}${key}: ${
+ typeof value === "boolean" ? (value ? "yes" : "no") :
+ typeof value === "string" ? (!value ? `""` : value) :
+ value
+ }`)].join("\n")
+ },
+ }, {async:true})
+ console.log(`Generated workflow`.grey)
+
+ //Save build
+ if (actions.includes("build")) {
+ fs.promises.writeFile(path.join(__workflows, "workflow.yml"), code)
+ console.log(`Generated workflow saved to ${path.join(__workflows, "dist/index.js")}`.green)
+ }
+
+ //Check build
+ if (actions.includes("check")) {
+ const status = `${await fs.promises.readFile(path.join(__workflows, "workflow.yml"))}` === code
+ if (status)
+ console.log(`Workflow is up-to-date`.grey)
+ else {
+ console.log(`Workflow is outdated`.red)
+ errors.push(`Workflow is outdated, run "npm run build" to fix it`)
+ }
+ }
+ }
+
//Action
{
//Build
diff --git a/utils/workflow.yml b/utils/workflow.yml
new file mode 100644
index 00000000..6a771a4d
--- /dev/null
+++ b/utils/workflow.yml
@@ -0,0 +1,185 @@
+name: Build
+
+on:
+ push:
+ branches: [ master ]
+ pull_request:
+ branches: [ master ]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+ - name: Setup
+ uses: actions/setup-node@v1
+ with:
+ node-version: 15.x
+ - name: Install
+ run: npm ci
+ - name: Build
+ run: npm run build
+ - name: Test
+ run: npm test
+
+ analyze:
+ runs-on: ubuntu-latest
+ needs: <%- JSON.stringify(releases.map(release => `test@${release}`)) %>
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+ - name: Setup
+ uses: github/codeql-action/init@v1
+ with:
+ languages: javascript
+ config-file: ./.github/config/codeql.yml
+ - name: Analyze
+ uses: github/codeql-action/analyze@v1
+
+ # Tests cases below are auto generated through `npm run build`
+ # Edit utils/workflow.yml instead if you need to update workflow
+ <% for (const release of releases) { %>
+ test@<%- release %>:
+ needs: build
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ template: <%- JSON.stringify(templates) %>
+ steps:
+
+ - name: ${{ matrix.template }} > Base
+ uses: lowlighter/metrics@<%- release %>
+ <%- testcase({
+ base: "header, activity, community, repositories, metadata",
+ }) %>
+
+ - name: ${{ matrix.template }} > Plugin > PageSpeed
+ uses: lowlighter/metrics@<%- release %>
+ <%- testcase({
+ plugin_pagespeed: true,
+ plugin_pagespeed_token: "${{ secrets.PAGESPEED_TOKEN }}",
+ }) %>
+
+ - name: ${{ matrix.template }} > Plugin > PageSpeed (detailed)
+ uses: lowlighter/metrics@<%- release %>
+ <%- testcase({
+ plugin_pagespeed: true,
+ plugin_pagespeed_detailed: true,
+ plugin_pagespeed_token: "${{ secrets.PAGESPEED_TOKEN }}",
+ }) %>
+
+ - name: ${{ matrix.template }} > Plugin > Music (playlist - apple)
+ uses: lowlighter/metrics@<%- release %>
+ <%- testcase({
+ plugin_music: true,
+ plugin_music_playlist: "${{ secrets.MUSIC_PLAYLIST_APPLE }}",
+ }) %>
+
+ - name: ${{ matrix.template }} > Plugin > Music (playlist - spotify)
+ uses: lowlighter/metrics@<%- release %>
+ <%- testcase({
+ plugin_music: true,
+ plugin_music_playlist: "${{ secrets.MUSIC_PLAYLIST_SPOTIFY }}",
+ }) %>
+
+ - name: ${{ matrix.template }} > Plugin > Music (recent - spotify)
+ uses: lowlighter/metrics@<%- release %>
+ <%- testcase({
+ plugin_music: true,
+ plugin_music_provider: "spotify",
+ plugin_music_token: "${{ secrets.SPOTIFY_TOKENS }}",
+ }) %>
+
+ - name: ${{ matrix.template }} > Plugin > Posts (dev.to)
+ uses: lowlighter/metrics@<%- release %>
+ <%- testcase({
+ plugin_posts: true,
+ plugin_posts_source: "dev.to",
+ }) %>
+
+ - name: ${{ matrix.template }} > Plugin > Isocalendar
+ uses: lowlighter/metrics@<%- release %>
+ <%- testcase({
+ plugin_isocalendar: true,
+ }) %>
+
+ - name: ${{ matrix.template }} > Plugin > Isocalendar (full year)
+ uses: lowlighter/metrics@<%- release %>
+ <%- testcase({
+ plugin_isocalendar: true,
+ plugin_isocalendar_duration: "full-year",
+ }) %>
+
+ - name: ${{ matrix.template }} > Plugin > Habits
+ uses: lowlighter/metrics@<%- release %>
+ <%- testcase({
+ plugin_habits: true,
+ }) %>
+
+ - name: ${{ matrix.template }} > Plugin > Languages
+ uses: lowlighter/metrics@<%- release %>
+ <%- testcase({
+ plugin_languages: true,
+ }) %>
+
+ - name: ${{ matrix.template }} > Plugin > Follow-up
+ uses: lowlighter/metrics@<%- release %>
+ <%- testcase({
+ plugin_followup: true,
+ }) %>
+
+ - name: ${{ matrix.template }} > Plugin > Lines
+ uses: lowlighter/metrics@<%- release %>
+ <%- testcase({
+ plugin_lines: true,
+ }) %>
+
+ - name: ${{ matrix.template }} > Plugin > Traffic
+ uses: lowlighter/metrics@<%- release %>
+ <%- testcase({
+ plugin_traffic: true,
+ }) %>
+
+ - name: ${{ matrix.template }} > Plugin > Gists
+ uses: lowlighter/metrics@<%- release %>
+ <%- testcase({
+ plugin_gists: true,
+ }) %>
+
+ - name: ${{ matrix.template }} > Plugin > Topics (stars)
+ uses: lowlighter/metrics@<%- release %>
+ <%- testcase({
+ plugin_topics: true,
+ plugin_topics_sort: "stars",
+ }) %>
+
+ - name: ${{ matrix.template }} > Plugin > Topics (activity)
+ uses: lowlighter/metrics@<%- release %>
+ <%- testcase({
+ plugin_topics: true,
+ plugin_topics_sort: "activity",
+ }) %>
+
+ - name: ${{ matrix.template }} > Plugin > Topics (starred)
+ uses: lowlighter/metrics@<%- release %>
+ <%- testcase({
+ plugin_topics: true,
+ plugin_topics_sort: "starred",
+ }) %>
+
+ - name: ${{ matrix.template }} > Plugin > Topics (random)
+ uses: lowlighter/metrics@<%- release %>
+ <%- testcase({
+ plugin_topics: true,
+ plugin_topics_sort: "random",
+ }) %>
+
+ - name: ${{ matrix.template }} > Plugin > Projects
+ uses: lowlighter/metrics@<%- release %>
+ <%- testcase({
+ plugin_projects: true,
+ plugin_projects_limit: 2,
+ }) %>
+
+ <% } -%>