Add tweets plugin (#23)

* Add support for tweets plugin
This commit is contained in:
Simon Lecoq
2020-12-17 22:38:51 +01:00
committed by GitHub
parent 6eac410f03
commit 592fd9d7bb
21 changed files with 312 additions and 316 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

View File

@@ -25,7 +25,7 @@ jobs:
analyze: analyze:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: ["test-master","test-latest"] needs: ["test-master"]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2
@@ -281,27 +281,8 @@ jobs:
plugin_projects: yes plugin_projects: yes
plugin_projects_limit: 2 plugin_projects_limit: 2
- name: ${{ matrix.template }} > Plugin > Tweets
test-latest: uses: lowlighter/metrics@master
needs: build
runs-on: ubuntu-latest
strategy:
matrix:
template: ["classic","terminal"]
steps:
- name: ${{ matrix.template }} > Base
uses: lowlighter/metrics@latest
with:
token: ${{ secrets.METRICS_TOKEN }}
dryrun: yes
repositories: 1
template: ${{ matrix.template }}
base: header, activity, community, repositories, metadata
plugins_errors_fatal: yes
- name: ${{ matrix.template }} > Plugin > PageSpeed
uses: lowlighter/metrics@latest
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
dryrun: yes dryrun: yes
@@ -309,218 +290,8 @@ jobs:
template: ${{ matrix.template }} template: ${{ matrix.template }}
base: "" base: ""
plugins_errors_fatal: yes plugins_errors_fatal: yes
plugin_pagespeed: yes plugin_tweets: yes
plugin_pagespeed_token: ${{ secrets.PAGESPEED_TOKEN }} plugin_tweets_limit: 2
plugin_tweets_token: ${{ secrets.TWITTER_TOKEN }}
- name: ${{ matrix.template }} > Plugin > PageSpeed (detailed)
uses: lowlighter/metrics@latest
with:
token: ${{ secrets.METRICS_TOKEN }}
dryrun: yes
repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_pagespeed: yes
plugin_pagespeed_detailed: yes
plugin_pagespeed_token: ${{ secrets.PAGESPEED_TOKEN }}
- name: ${{ matrix.template }} > Plugin > Music (playlist - apple)
uses: lowlighter/metrics@latest
with:
token: ${{ secrets.METRICS_TOKEN }}
dryrun: yes
repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_music: yes
plugin_music_playlist: ${{ secrets.MUSIC_PLAYLIST_APPLE }}
- name: ${{ matrix.template }} > Plugin > Music (playlist - spotify)
uses: lowlighter/metrics@latest
with:
token: ${{ secrets.METRICS_TOKEN }}
dryrun: yes
repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_music: yes
plugin_music_playlist: ${{ secrets.MUSIC_PLAYLIST_SPOTIFY }}
- name: ${{ matrix.template }} > Plugin > Music (recent - spotify)
uses: lowlighter/metrics@latest
with:
token: ${{ secrets.METRICS_TOKEN }}
dryrun: yes
repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_music: yes
plugin_music_provider: spotify
plugin_music_token: ${{ secrets.SPOTIFY_TOKENS }}
- name: ${{ matrix.template }} > Plugin > Posts (dev.to)
uses: lowlighter/metrics@latest
with:
token: ${{ secrets.METRICS_TOKEN }}
dryrun: yes
repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_posts: yes
plugin_posts_source: dev.to
- name: ${{ matrix.template }} > Plugin > Isocalendar
uses: lowlighter/metrics@latest
with:
token: ${{ secrets.METRICS_TOKEN }}
dryrun: yes
repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_isocalendar: yes
- name: ${{ matrix.template }} > Plugin > Isocalendar (full year)
uses: lowlighter/metrics@latest
with:
token: ${{ secrets.METRICS_TOKEN }}
dryrun: yes
repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_isocalendar: yes
plugin_isocalendar_duration: full-year
- name: ${{ matrix.template }} > Plugin > Habits
uses: lowlighter/metrics@latest
with:
token: ${{ secrets.METRICS_TOKEN }}
dryrun: yes
repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_habits: yes
- name: ${{ matrix.template }} > Plugin > Languages
uses: lowlighter/metrics@latest
with:
token: ${{ secrets.METRICS_TOKEN }}
dryrun: yes
repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_languages: yes
- name: ${{ matrix.template }} > Plugin > Follow-up
uses: lowlighter/metrics@latest
with:
token: ${{ secrets.METRICS_TOKEN }}
dryrun: yes
repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_followup: yes
- name: ${{ matrix.template }} > Plugin > Lines
uses: lowlighter/metrics@latest
with:
token: ${{ secrets.METRICS_TOKEN }}
dryrun: yes
repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_lines: yes
- name: ${{ matrix.template }} > Plugin > Traffic
uses: lowlighter/metrics@latest
with:
token: ${{ secrets.METRICS_TOKEN }}
dryrun: yes
repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_traffic: yes
- name: ${{ matrix.template }} > Plugin > Gists
uses: lowlighter/metrics@latest
with:
token: ${{ secrets.METRICS_TOKEN }}
dryrun: yes
repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_gists: yes
- name: ${{ matrix.template }} > Plugin > Topics (stars)
uses: lowlighter/metrics@latest
with:
token: ${{ secrets.METRICS_TOKEN }}
dryrun: yes
repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_topics: yes
plugin_topics_sort: stars
- name: ${{ matrix.template }} > Plugin > Topics (activity)
uses: lowlighter/metrics@latest
with:
token: ${{ secrets.METRICS_TOKEN }}
dryrun: yes
repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_topics: yes
plugin_topics_sort: activity
- name: ${{ matrix.template }} > Plugin > Topics (starred)
uses: lowlighter/metrics@latest
with:
token: ${{ secrets.METRICS_TOKEN }}
dryrun: yes
repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_topics: yes
plugin_topics_sort: starred
- name: ${{ matrix.template }} > Plugin > Topics (random)
uses: lowlighter/metrics@latest
with:
token: ${{ secrets.METRICS_TOKEN }}
dryrun: yes
repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_topics: yes
plugin_topics_sort: random
- name: ${{ matrix.template }} > Plugin > Projects
uses: lowlighter/metrics@latest
with:
token: ${{ secrets.METRICS_TOKEN }}
dryrun: yes
repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_projects: yes
plugin_projects_limit: 2

View File

@@ -100,13 +100,13 @@ But there's more with [plugins](https://github.com/lowlighter/metrics/tree/maste
</td> </td>
</tr> </tr>
<tr> <tr>
<th><a href="https://github.com/lowlighter/metrics#-habits">💡 Coding Habits plugin</a></th> <th><a href="https://github.com/lowlighter/metrics#-tweets">🐤 Tweets plugin</a></th>
<th><a href="https://github.com/lowlighter/metrics#%EF%B8%8F-posts">✒️ Recent posts plugin</a></th> <th><a href="https://github.com/lowlighter/metrics#%EF%B8%8F-posts">✒️ Recent posts plugin</a></th>
</tr> </tr>
<tr> <tr>
<td> <td>
<a href="https://github.com/lowlighter/metrics#-habits"> <a href="https://github.com/lowlighter/metrics#-tweets">
<img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.habits.svg" alt="" width="400"> <img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.tweets.svg" alt="" width="400">
</a> </a>
</td> </td>
<td> <td>
@@ -116,16 +116,20 @@ But there's more with [plugins](https://github.com/lowlighter/metrics/tree/maste
</td> </td>
</tr> </tr>
<tr> <tr>
<th><a href="https://github.com/lowlighter/metrics#-habits">💡 Coding Habits plugin</a></th>
<th><a href="https://github.com/lowlighter/metrics#-gists">🎫 Gists plugin</a></th> <th><a href="https://github.com/lowlighter/metrics#-gists">🎫 Gists plugin</a></th>
<th></th>
</tr> </tr>
<tr> <tr>
<td>
<a href="https://github.com/lowlighter/metrics#-habits">
<img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.habits.svg" alt="" width="400">
</a>
</td>
<td> <td>
<a href="https://github.com/lowlighter/metrics#-gists"> <a href="https://github.com/lowlighter/metrics#-gists">
<img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.gists.svg" alt="" width="400"> <img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.gists.svg" alt="" width="400">
</a> </a>
</td> </td>
<td></td>
</tr> </tr>
<tr> <tr>
<td colspan="2" align="center"> <td colspan="2" align="center">
@@ -847,12 +851,12 @@ Add the following to your workflow :
### 🧮 Traffic ### 🧮 Traffic
⚠️ This plugin requires a personal token with full repo scope.
The repositories *traffic* plugin displays the number of pages views across your repositories. The repositories *traffic* plugin displays the number of pages views across your repositories.
![Traffic plugin](https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.traffic.svg) ![Traffic plugin](https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.traffic.svg)
⚠️ This plugin requires a personal token with full repo scope.
<details> <details>
<summary>💬 About</summary> <summary>💬 About</summary>
@@ -874,6 +878,63 @@ Add the following to your workflow :
</details> </details>
### 🐤 Tweets
🚧 This plugin is available as pre-release on @master
The recent *tweets* plugin displays your latest tweets of the [twitter](https://twitter.com) attached mentioned on your account :
![Tweets plugin](https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.tweets.svg)
<details>
<summary>💬 About</summary>
Add the following to your workflow :
```yaml
- uses: lowlighter/metrics@latest
with:
# ... other options
plugin_tweets: yes
plugin_tweets_token: ${{ secrets.TWITTER_TOKEN }}
```
<details>
<summary>💬 Obtaining a twitter token</summary>
To get a twitter token, you'll need to apply to the [developer program](https://apps.twitter.com).
It's a bit tedious, but it seems that requests are approved quite quickly.
Create an app from your [developer dashboard](https://developer.twitter.com/en/portal/dashboard) and register your bearer token in your repository secrets.
![Twitter token](.github/readme/imgs/plugin_tweets_secrets.png)
</details>
</details>
### ✒️ Posts
The recent *posts* plugin displays recent articles you wrote on an external source, like [dev.to](https://dev.to).
![Posts plugin](https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.posts.svg)
<details>
<summary>💬 About</summary>
Supported sources are :
* [dev.to](https://dev.to)
Add the following to your workflow :
```yaml
- uses: lowlighter/metrics@latest
with:
# ... other options
plugin_posts: yes
plugin_posts_source: ********
```
</details>
### 💡 Habits ### 💡 Habits
The coding *habits* add deduced coding habits based on your recent activity, from up to 100 events. The coding *habits* add deduced coding habits based on your recent activity, from up to 100 events.
@@ -899,29 +960,6 @@ Add the following to your workflow :
</details> </details>
### ✒️ Posts
The recent *posts* plugin displays recent articles you wrote on an external source, like [dev.to](https://dev.to).
![Posts plugin](https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.posts.svg)
<details>
<summary>💬 About</summary>
Supported sources are :
* [dev.to](https://dev.to)
Add the following to your workflow :
```yaml
- uses: lowlighter/metrics@latest
with:
# ... other options
plugin_posts: yes
plugin_posts_source: ********
```
</details>
### 🎫 Gists ### 🎫 Gists
The *gists* plugin displays your [gists](https://gist.github.com) metrics. The *gists* plugin displays your [gists](https://gist.github.com) metrics.

View File

@@ -248,6 +248,24 @@ inputs:
description: Number of active projects to display description: Number of active projects to display
default: 4 default: 4
# Tweets plugin
# Enable it to display recent tweets of the twitter username attached to "user"
plugin_tweets:
description: Display recent tweets
default: no
# Tweets API token (required when tweets plugin is enabled)
# See https://apps.twitter.com for more informations
plugin_tweets_token:
description: Twitter bearer token
default: ""
# Number of tweets to display
# Between 1 and 10
plugin_tweets_limit:
description: Number of tweets to display
default: 2
# Enable debug mode # Enable debug mode
# Ensure you correctly put all sensitive informations in your repository secrets before ! # Ensure you correctly put all sensitive informations in your repository secrets before !
debug: debug:

File diff suppressed because one or more lines are too long

View File

@@ -93,6 +93,7 @@
gists:{enabled:bool(core.getInput("plugin_gists"))}, gists:{enabled:bool(core.getInput("plugin_gists"))},
topics:{enabled:bool(core.getInput("plugin_topics"))}, topics:{enabled:bool(core.getInput("plugin_topics"))},
projects:{enabled:bool(core.getInput("plugin_projects"))}, projects:{enabled:bool(core.getInput("plugin_projects"))},
tweets:{enabled:bool(core.getInput("plugin_tweets"))},
} }
let q = Object.fromEntries(Object.entries(plugins).filter(([key, plugin]) => plugin.enabled).map(([key]) => [key, true])) 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(", ")}`) console.log(`Plugins enabled | ${Object.entries(plugins).filter(([key, plugin]) => plugin.enabled).map(([key]) => key).join(", ")}`)
@@ -147,6 +148,14 @@
q[`projects.${option}`] = core.getInput(`plugin_projects_${option}`) || null q[`projects.${option}`] = core.getInput(`plugin_projects_${option}`) || null
console.log(`Projects limit | ${q["projects.limit"]}`) console.log(`Projects limit | ${q["projects.limit"]}`)
} }
//Tweets
if (plugins.tweets.enabled) {
plugins.tweets.token = core.getInput("plugin_tweets_token") || null
for (const option of ["limit"])
q[`tweets.${option}`] = core.getInput(`plugin_tweets_${option}`) || null
console.log(`Twitter token | ${plugins.tweets.token ? "provided" : "missing"}`)
console.log(`Tweets limit | ${q["tweets.limit"]}`)
}
//Repositories to use //Repositories to use
const repositories = Number(core.getInput("repositories")) || 100 const repositories = Number(core.getInput("repositories")) || 100

70
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{ {
"name": "metrics", "name": "metrics",
"version": "2.8.0", "version": "2.9.0-beta",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@@ -29,9 +29,9 @@
} }
}, },
"@babel/code-frame": { "@babel/code-frame": {
"version": "7.10.4", "version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
"integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/highlight": "^7.10.4" "@babel/highlight": "^7.10.4"
@@ -61,25 +61,25 @@
} }
}, },
"@babel/generator": { "@babel/generator": {
"version": "7.12.10", "version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.10.tgz", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.11.tgz",
"integrity": "sha512-6mCdfhWgmqLdtTkhXjnIz0LcdVCd26wS2JXRtj2XY0u5klDsXBREA/pG5NVOuVnF2LUrBGNFtQkIqqTbblg0ww==", "integrity": "sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/types": "^7.12.10", "@babel/types": "^7.12.11",
"jsesc": "^2.5.1", "jsesc": "^2.5.1",
"source-map": "^0.5.0" "source-map": "^0.5.0"
} }
}, },
"@babel/helper-function-name": { "@babel/helper-function-name": {
"version": "7.10.4", "version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.11.tgz",
"integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", "integrity": "sha512-AtQKjtYNolKNi6nNNVLQ27CP6D9oFR6bq/HPYSizlzbp7uC1M59XJe8L+0uXjbIaZaUJF99ruHqVGiKXU/7ybA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/helper-get-function-arity": "^7.10.4", "@babel/helper-get-function-arity": "^7.12.10",
"@babel/template": "^7.10.4", "@babel/template": "^7.12.7",
"@babel/types": "^7.10.4" "@babel/types": "^7.12.11"
} }
}, },
"@babel/helper-get-function-arity": { "@babel/helper-get-function-arity": {
@@ -136,15 +136,15 @@
} }
}, },
"@babel/helper-replace-supers": { "@babel/helper-replace-supers": {
"version": "7.12.5", "version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.5.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.11.tgz",
"integrity": "sha512-5YILoed0ZyIpF4gKcpZitEnXEJ9UoDRki1Ey6xz46rxOzfNMAhVIJMoune1hmPVxh40LRv1+oafz7UsWX+vyWA==", "integrity": "sha512-q+w1cqmhL7R0FNzth/PLLp2N+scXEK/L2AHbXUyydxp828F4FEa5WcVoqui9vFRiHDQErj9Zof8azP32uGVTRA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/helper-member-expression-to-functions": "^7.12.1", "@babel/helper-member-expression-to-functions": "^7.12.7",
"@babel/helper-optimise-call-expression": "^7.10.4", "@babel/helper-optimise-call-expression": "^7.12.10",
"@babel/traverse": "^7.12.5", "@babel/traverse": "^7.12.10",
"@babel/types": "^7.12.5" "@babel/types": "^7.12.11"
} }
}, },
"@babel/helper-simple-access": { "@babel/helper-simple-access": {
@@ -157,18 +157,18 @@
} }
}, },
"@babel/helper-split-export-declaration": { "@babel/helper-split-export-declaration": {
"version": "7.11.0", "version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.11.tgz",
"integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", "integrity": "sha512-LsIVN8j48gHgwzfocYUSkO/hjYAOJqlpJEc7tGXcIm4cubjVUf8LGW6eWRyxEu7gA25q02p0rQUWoCI33HNS5g==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/types": "^7.11.0" "@babel/types": "^7.12.11"
} }
}, },
"@babel/helper-validator-identifier": { "@babel/helper-validator-identifier": {
"version": "7.10.4", "version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz",
"integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==",
"dev": true "dev": true
}, },
"@babel/helpers": { "@babel/helpers": {
@@ -194,9 +194,9 @@
} }
}, },
"@babel/parser": { "@babel/parser": {
"version": "7.12.10", "version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.10.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.11.tgz",
"integrity": "sha512-PJdRPwyoOqFAWfLytxrWwGrAxghCgh/yTNCYciOz8QgjflA7aZhECPZAa2VUedKg2+QMWkI0L9lynh2SNmNEgA==", "integrity": "sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg==",
"dev": true "dev": true
}, },
"@babel/template": { "@babel/template": {
@@ -228,12 +228,12 @@
} }
}, },
"@babel/types": { "@babel/types": {
"version": "7.12.10", "version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.10.tgz", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.11.tgz",
"integrity": "sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw==", "integrity": "sha512-ukA9SQtKThINm++CX1CwmliMrE54J6nIYB5XTwL5f/CLFW9owfls+YSU8tVW15RQ2w+a3fSbPjC6HdQNtWZkiA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/helper-validator-identifier": "^7.10.4", "@babel/helper-validator-identifier": "^7.12.11",
"lodash": "^4.17.19", "lodash": "^4.17.19",
"to-fast-properties": "^2.0.0" "to-fast-properties": "^2.0.0"
} }

View File

@@ -1,7 +1,7 @@
{ {
"name": "metrics", "name": "metrics",
"version": "2.8.0", "version": "2.9.0-beta",
"description": "Generate an user's GitHub metrics as SVG image format to embed somewhere else", "description": "An image generator with 20+ metrics about your GitHub account such as activity, community, repositories, coding habits, website performances, music played, starred topics, etc. that you can put on your profile or elsewhere !",
"main": "index.mjs", "main": "index.mjs",
"scripts": { "scripts": {
"start": "node index.mjs", "start": "node index.mjs",

View File

@@ -17,7 +17,7 @@
"plugins":{ "//":"Additional plugins (optional)", "plugins":{ "//":"Additional plugins (optional)",
"pagespeed":{ "//":"Pagespeed plugin", "pagespeed":{ "//":"Pagespeed plugin",
"enabled":true, "//":"Enable or disable PageSpeed metrics", "enabled":true, "//":"Enable or disable PageSpeed metrics",
"token":null, "//":"Pagespeed token" "token":null, "//":"Pagespeed token (optional)"
}, },
"traffic":{ "//":"Traffic plugin (GitHub API token must be RW for this to work)", "traffic":{ "//":"Traffic plugin (GitHub API token must be RW for this to work)",
"enabled":false, "//":"Enable or disable repositories total page views is last two weeks" "enabled":false, "//":"Enable or disable repositories total page views is last two weeks"
@@ -53,6 +53,10 @@
}, },
"projects":{ "//":"Projects plugin", "projects":{ "//":"Projects plugin",
"enabled":false, "//":"Enable or disable personal projects display" "enabled":false, "//":"Enable or disable personal projects display"
},
"tweets":{ "//":"Tweets plugin",
"enabled":true, "//":"Enable or disable recent tweets display",
"token":null, "//":"Twitter token (required when enabled)"
} }
} }
} }

View File

@@ -36,6 +36,7 @@
gists:"Gists metrics", gists:"Gists metrics",
topics:"Starred topics", topics:"Starred topics",
projects:"Projects", projects:"Projects",
tweets:"Latest tweets",
"base.header":"Header", "base.header":"Header",
"base.activity":"Account activity", "base.activity":"Account activity",
"base.community":"Community stats", "base.community":"Community stats",
@@ -55,6 +56,7 @@
"projects.limit":4, "projects.limit":4,
"topics.sort":"stars", "topics.sort":"stars",
"topics.limit":12, "topics.limit":12,
"tweets.limit":2,
}, },
}, },
templates:{ templates:{

View File

@@ -51,9 +51,16 @@
</label> </label>
</div> </div>
<i>*Additional plugins may be available when used as GitHub Action</i> <i>*Additional plugins may be available when used as GitHub Action</i>
<template v-if="(plugins.enabled.music)||(plugins.enabled.pagespeed)||(plugins.enabled.languages)||(plugins.enabled.habits)||(plugins.enabled.posts)||(plugins.enabled.isocalendar)||(plugins.enabled.projects)||(plugins.enabled.topics)"> <template v-if="(plugins.enabled.tweets)||(plugins.enabled.music)||(plugins.enabled.pagespeed)||(plugins.enabled.languages)||(plugins.enabled.habits)||(plugins.enabled.posts)||(plugins.enabled.isocalendar)||(plugins.enabled.projects)||(plugins.enabled.topics)">
<h3>2.3 Configure additional plugins</h3> <h3>2.3 Configure additional plugins</h3>
<div class="options"> <div class="options">
<div class="options-group" v-if="plugins.enabled.tweets">
<h4>{{ plugins.descriptions.tweets }}</h4>
<label>
Number of tweets to display
<input type="number" v-model="plugins.options['tweets.limit']" min="1" max="10" @change="load">
</label>
</div>
<div class="options-group" v-if="plugins.enabled.music"> <div class="options-group" v-if="plugins.enabled.music">
<h4>{{ plugins.descriptions.music }}</h4> <h4>{{ plugins.descriptions.music }}</h4>
<label> <label>

View File

@@ -49,7 +49,7 @@
//Compute metrics //Compute metrics
console.debug(`metrics/compute/${login} > compute`) console.debug(`metrics/compute/${login} > compute`)
const computer = Templates[template].default || Templates[template] 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, htmlescape}}) await computer({login, q}, {conf, data, rest, graphql, plugins}, {s, pending, imports:{plugins:Plugins, url, imgb64, axios, puppeteer, format, bytes, shuffle, htmlescape, urlexpand}})
const promised = await Promise.all(pending) const promised = await Promise.all(pending)
//Check plugins errors //Check plugins errors
@@ -115,13 +115,22 @@
} }
/** Escape html */ /** Escape html */
function htmlescape(string) { function htmlescape(string, u = {"&":true, "<":true, ">":true, '"':true, "'":true}) {
return string return string
.replace(/&/g, "&amp;") .replace(/&(?!(?:amp|lt|gt|quot|apos);)/g, u["&"] ? "&amp;" : "&")
.replace(/</g, "&lt;") .replace(/</g, u["<"] ? "&lt;" : "<")
.replace(/>/g, "&gt;") .replace(/>/g, u[">"] ? "&gt;" : ">")
.replace(/"/g, "&quot;") .replace(/"/g, u['"'] ? "&quot;" : '"')
.replace(/'/g, "&#39;") .replace(/'/g, u["'"] ? "&apos;" : "'")
}
/** Expand url */
async function urlexpand(url) {
try {
return (await axios.get(url)).request.res.responseUrl
} catch {
return url
}
} }
/** Placeholder generator */ /** Placeholder generator */
@@ -169,6 +178,7 @@
languages:{favorites:new Array(7).fill(null).map((_, x) => ({x, name:"######", color:"#ebedf0", value:1/(x+1)}))}, languages:{favorites:new Array(7).fill(null).map((_, x) => ({x, name:"######", color:"#ebedf0", value:1/(x+1)}))},
topics:{list:[...new Array("topics.limit" in q ? Math.max(Number(q["topics.limit"])||0, 0) : 12).fill(null).map(() => ({name:"######", description:"", icon:null})), {name:`And ## more...`, description:"", icon:null}]}, topics:{list:[...new Array("topics.limit" in q ? Math.max(Number(q["topics.limit"])||0, 0) : 12).fill(null).map(() => ({name:"######", description:"", icon:null})), {name:`And ## more...`, description:"", icon:null}]},
projects:{list:[...new Array("projects.limit" in q ? Math.max(Number(q["projects.limit"])||0, 0) : 4).fill(null).map(() => ({name:"########", updated:"########", progress:{enabled:true, todo:"##", doing:"##", done:"##", total:"##"}}))]}, projects:{list:[...new Array("projects.limit" in q ? Math.max(Number(q["projects.limit"])||0, 0) : 4).fill(null).map(() => ({name:"########", updated:"########", progress:{enabled:true, todo:"##", doing:"##", done:"##", total:"##"}}))]},
tweets:{profile:{username:"########", verified:false}, list:[...new Array("tweets.limit" in q ? Math.max(Number(q["tweets.limit"])||0, 0) : 2).fill(null).map(() => ({text:"###### ###### ####### ######".repeat(4), created_at:Date.now()}))]},
}[key]??{})] }[key]??{})]
)), )),
}) })

View File

@@ -13,6 +13,7 @@
import projects from "./projects/index.mjs" import projects from "./projects/index.mjs"
import topics from "./topics/index.mjs" import topics from "./topics/index.mjs"
import traffic from "./traffic/index.mjs" import traffic from "./traffic/index.mjs"
import tweets from "./tweets/index.mjs"
//Exports //Exports
export default { export default {
@@ -28,4 +29,5 @@
projects, projects,
topics, topics,
traffic, traffic,
tweets,
} }

View File

@@ -37,6 +37,9 @@
break break
topics.push(...starred) topics.push(...starred)
} }
//Close browser
console.debug(`metrics/compute/${login}/plugins > music > closing browser`)
await browser.close()
//Shuffle topics //Shuffle topics
if (shuffle) if (shuffle)
topics = imports.shuffle(topics) topics = imports.shuffle(topics)

View File

@@ -0,0 +1,56 @@
//Setup
export default async function ({login, imports, data, q}, {enabled = false, token = null} = {}) {
//Plugin execution
try {
//Check if plugin is enabled and requirements are met
if ((!enabled)||(!q.tweets))
return null
//Parameters override
let {"tweets.limit":limit = 2} = q
//Limit
limit = Math.max(1, Math.min(10, Number(limit)))
//Load user profile
const username = data.user.twitterUsername
console.debug(`metrics/compute/${login}/plugins > tweets > loading twitter profile (@${username})`)
const {data:{data:profile = null}} = await imports.axios.get(`https://api.twitter.com/2/users/by/username/${username}?user.fields=profile_image_url,verified`, {headers:{Authorization:`Bearer ${token}`}})
//Load tweets
console.debug(`metrics/compute/${login}/plugins > tweets > loading tweets`)
const {data:{data:tweets = []}} = await imports.axios.get(`https://api.twitter.com/2/tweets/search/recent?query=from:${username}&tweet.fields=created_at&expansions=entities.mentions.username`, {headers:{Authorization:`Bearer ${token}`}})
//Load profile image
if (profile?.profile_image_url) {
console.debug(`metrics/compute/${login}/plugins > tweets > loading profile image`)
profile.profile_image = await imports.imgb64(profile.profile_image_url)
}
//Limit tweets
if (limit > 0) {
console.debug(`metrics/compute/${login}/plugins > tweets > keeping only ${limit} tweets`)
tweets.splice(limit)
}
//Format tweets
await Promise.all(tweets.map(async tweet => {
//Mentions
tweet.mentions = tweet.entities?.mentions.map(({username}) => username) ?? []
//Format text
console.debug(`metrics/compute/${login}/plugins > tweets > formatting tweet ${tweet.id}`)
tweet.text = imports.htmlescape(
//Escape tags
imports.htmlescape(tweet.text, {"<":true, ">":true})
//Mentions
.replace(new RegExp(`@(${tweet.mentions.join("|")})`, "gi"), ` <span class="mention">@$1</span> `)
//Hashtags
.replace(/(?<!&)[#|]([a-z0-9_\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u00ff\u0100-\u024f\u0253-\u0254\u0256-\u0257\u0300-\u036f\u1e00-\u1eff\u0400-\u04ff\u0500-\u0527\u2de0-\u2dff\ua640-\ua69f\u0591-\u05bf\u05c1-\u05c2\u05c4-\u05c5\u05d0-\u05ea\u05f0-\u05f4\ufb12-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb40-\ufb41\ufb43-\ufb44\ufb46-\ufb4f\u0610-\u061a\u0620-\u065f\u066e-\u06d3\u06d5-\u06dc\u06de-\u06e8\u06ea-\u06ef\u06fa-\u06fc\u0750-\u077f\u08a2-\u08ac\u08e4-\u08fe\ufb50-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\u200c-\u200c\u0e01-\u0e3a\u0e40-\u0e4e\u1100-\u11ff\u3130-\u3185\ua960-\ua97f\uac00-\ud7af\ud7b0-\ud7ff\uffa1-\uffdc\u30a1-\u30fa\u30fc-\u30fe\uff66-\uff9f\uff10-\uff19\uff21-\uff3a\uff41-\uff5a\u3041-\u3096\u3099-\u309e\u3400-\u4dbf\u4e00-\u9fff\u20000-\u2a6df\u2a700-\u2b73f\u2b740-\u2b81f\u2f800-\u2fa1f]*[a-z_\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u00ff\u0100-\u024f\u0253-\u0254\u0256-\u0257\u0300-\u036f\u1e00-\u1eff\u0400-\u04ff\u0500-\u0527\u2de0-\u2dff\ua640-\ua69f\u0591-\u05bf\u05c1-\u05c2\u05c4-\u05c5\u05d0-\u05ea\u05f0-\u05f4\ufb12-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb40-\ufb41\ufb43-\ufb44\ufb46-\ufb4f\u0610-\u061a\u0620-\u065f\u066e-\u06d3\u06d5-\u06dc\u06de-\u06e8\u06ea-\u06ef\u06fa-\u06fc\u0750-\u077f\u08a2-\u08ac\u08e4-\u08fe\ufb50-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\u200c-\u200c\u0e01-\u0e3a\u0e40-\u0e4e\u1100-\u11ff\u3130-\u3185\ua960-\ua97f\uac00-\ud7af\ud7b0-\ud7ff\uffa1-\uffdc\u30a1-\u30fa\u30fc-\u30fe\uff66-\uff9f\uff10-\uff19\uff21-\uff3a\uff41-\uff5a\u3041-\u3096\u3099-\u309e\u3400-\u4dbf\u4e00-\u9fff\u20000-\u2a6df\u2a700-\u2b73f\u2b740-\u2b81f\u2f800-\u2fa1f][a-z0-9_\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u00ff\u0100-\u024f\u0253-\u0254\u0256-\u0257\u0300-\u036f\u1e00-\u1eff\u0400-\u04ff\u0500-\u0527\u2de0-\u2dff\ua640-\ua69f\u0591-\u05bf\u05c1-\u05c2\u05c4-\u05c5\u05d0-\u05ea\u05f0-\u05f4\ufb12-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb40-\ufb41\ufb43-\ufb44\ufb46-\ufb4f\u0610-\u061a\u0620-\u065f\u066e-\u06d3\u06d5-\u06dc\u06de-\u06e8\u06ea-\u06ef\u06fa-\u06fc\u0750-\u077f\u08a2-\u08ac\u08e4-\u08fe\ufb50-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\u200c-\u200c\u0e01-\u0e3a\u0e40-\u0e4e\u1100-\u11ff\u3130-\u3185\ua960-\ua97f\uac00-\ud7af\ud7b0-\ud7ff\uffa1-\uffdc\u30a1-\u30fa\u30fc-\u30fe\uff66-\uff9f\uff10-\uff19\uff21-\uff3a\uff41-\uff5a\u3041-\u3096\u3099-\u309e\u3400-\u4dbf\u4e00-\u9fff\u20000-\u2a6df\u2a700-\u2b73f\u2b740-\u2b81f\u2f800-\u2fa1f]*)/gi, ` <span class="hashtag">#$1</span> `)
//Line breaks
.replace(/\n/g, "<br/>")
//Links
.replace(/https?:[/][/](t.co[/]\w+)/g, ` <span class="link">$1</span> `)
, {"&":true})
}))
//Result
return {username, profile, list:tweets}
}
//Handle errors
catch (error) {
console.debug(error)
throw {error:{message:`An error occured`}}
}
}

View File

@@ -14,6 +14,7 @@
+ (!!plugins.gists)*68 + (!!plugins.gists)*68
+ (!!plugins.topics)*160 + (!!plugins.topics)*160
+ (!!plugins.projects)*22 + (plugins.projects?.list?.length ?? 0)*60 + (!!plugins.projects)*22 + (plugins.projects?.list?.length ?? 0)*60
+ (!!plugins.tweets)*64 + (plugins.tweets?.list?.length ?? 0)*90
+ Math.max(0, (((!!base.metadata)+(!!base.header)+((!!base.activity)||(!!base.community))+(!!base.repositories)+((!!plugins.habits))+(!!plugins.pagespeed)+(!!plugins.languages)+(!!plugins.music)+(!!plugins.posts)+(!!plugins.isocalendar)+(!!plugins.gists)+(!!plugins.topics)+(!!plugins.projects))-1))*4 + Math.max(0, (((!!base.metadata)+(!!base.header)+((!!base.activity)||(!!base.community))+(!!base.repositories)+((!!plugins.habits))+(!!plugins.pagespeed)+(!!plugins.languages)+(!!plugins.music)+(!!plugins.posts)+(!!plugins.isocalendar)+(!!plugins.gists)+(!!plugins.topics)+(!!plugins.projects))-1))*4
%>"> %>">
@@ -633,6 +634,52 @@
</section> </section>
<% } %> <% } %>
<% if (plugins.tweets) { %>
<section>
<h2 class="field">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 273.5 222.3" width="16" height="16"><path d="M273.5 26.3a109.77 109.77 0 0 1-32.2 8.8 56.07 56.07 0 0 0 24.7-31 113.39 113.39 0 0 1-35.7 13.6 56.1 56.1 0 0 0-97 38.4 54 54 0 0 0 1.5 12.8A159.68 159.68 0 0 1 19.1 10.3a56.12 56.12 0 0 0 17.4 74.9 56.06 56.06 0 0 1-25.4-7v.7a56.11 56.11 0 0 0 45 55 55.65 55.65 0 0 1-14.8 2 62.39 62.39 0 0 1-10.6-1 56.24 56.24 0 0 0 52.4 39 112.87 112.87 0 0 1-69.7 24 119 119 0 0 1-13.4-.8 158.83 158.83 0 0 0 86 25.2c103.2 0 159.6-85.5 159.6-159.6 0-2.4-.1-4.9-.2-7.3a114.25 114.25 0 0 0 28.1-29.1"></path></svg>
Latest tweets
</h2>
<div class="row fill-width">
<section>
<% if (plugins.tweets.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.tweets.error.message %>
</div>
<% } else { %>
<div class="field <%= !plugins.tweets.profile ? 'error' : '' %>">
<% if (plugins.tweets.profile?.verified) { %>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M9.585.52a2.678 2.678 0 00-3.17 0l-.928.68a1.178 1.178 0 01-.518.215L3.83 1.59a2.678 2.678 0 00-2.24 2.24l-.175 1.14a1.178 1.178 0 01-.215.518l-.68.928a2.678 2.678 0 000 3.17l.68.928c.113.153.186.33.215.518l.175 1.138a2.678 2.678 0 002.24 2.24l1.138.175c.187.029.365.102.518.215l.928.68a2.678 2.678 0 003.17 0l.928-.68a1.17 1.17 0 01.518-.215l1.138-.175a2.678 2.678 0 002.241-2.241l.175-1.138c.029-.187.102-.365.215-.518l.68-.928a2.678 2.678 0 000-3.17l-.68-.928a1.179 1.179 0 01-.215-.518L14.41 3.83a2.678 2.678 0 00-2.24-2.24l-1.138-.175a1.179 1.179 0 01-.518-.215L9.585.52zM7.303 1.728c.415-.305.98-.305 1.394 0l.928.68c.348.256.752.423 1.18.489l1.136.174c.51.078.909.478.987.987l.174 1.137c.066.427.233.831.489 1.18l.68.927c.305.415.305.98 0 1.394l-.68.928a2.678 2.678 0 00-.489 1.18l-.174 1.136a1.178 1.178 0 01-.987.987l-1.137.174a2.678 2.678 0 00-1.18.489l-.927.68c-.415.305-.98.305-1.394 0l-.928-.68a2.678 2.678 0 00-1.18-.489l-1.136-.174a1.178 1.178 0 01-.987-.987l-.174-1.137a2.678 2.678 0 00-.489-1.18l-.68-.927a1.178 1.178 0 010-1.394l.68-.928c.256-.348.423-.752.489-1.18l.174-1.136c.078-.51.478-.909.987-.987l1.137-.174a2.678 2.678 0 001.18-.489l.927-.68zM11.28 6.78a.75.75 0 00-1.06-1.06L7 8.94 5.78 7.72a.75.75 0 00-1.06 1.06l1.75 1.75a.75.75 0 001.06 0l3.75-3.75z"></path></svg>
<% } else { %>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M4.75 2.37a6.5 6.5 0 006.5 11.26.75.75 0 01.75 1.298 8 8 0 113.994-7.273.754.754 0 01.006.095v1.5a2.75 2.75 0 01-5.072 1.475A4 4 0 1112 8v1.25a1.25 1.25 0 002.5 0V7.867a6.5 6.5 0 00-9.75-5.496V2.37zM10.5 8a2.5 2.5 0 10-5 0 2.5 2.5 0 005 0z"></path></svg>
<% } %>
<%= plugins.tweets.username %>
<% if (!plugins.tweets.profile) { %>
: twitter username not found
<% } %>
</div>
<% if (plugins.tweets.profile) { %>
<% if (plugins.tweets.list.length) { %>
<% for (const {text, created_at} of plugins.tweets.list) { %>
<div class="tweet">
<%- text %>
<div class="date"><%= new Date(created_at).toGMTString() %></div>
</div>
<% } %>
<% } else { %>
<div class="field">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1.75 1.5a.25.25 0 00-.25.25v9.5c0 .138.112.25.25.25h2a.75.75 0 01.75.75v2.19l2.72-2.72a.75.75 0 01.53-.22h6.5a.25.25 0 00.25-.25v-9.5a.25.25 0 00-.25-.25H1.75zM0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v9.5A1.75 1.75 0 0114.25 13H8.06l-2.573 2.573A1.457 1.457 0 013 14.543V13H1.75A1.75 1.75 0 010 11.25v-9.5zM9 9a1 1 0 11-2 0 1 1 0 012 0zm-.25-5.25a.75.75 0 00-1.5 0v2.5a.75.75 0 001.5 0v-2.5z"></path></svg>
No recent tweets
</div>
<% } %>
<% } %>
<% } %>
</section>
</div>
</section>
<% } %>
<% if (plugins.isocalendar) { %> <% if (plugins.isocalendar) { %>
<section> <section>
<h2 class="field"> <h2 class="field">

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View File

@@ -7,6 +7,7 @@ query Metrics {
avatarUrl avatarUrl
websiteUrl websiteUrl
isHireable isHireable
twitterUsername
gists { gists {
totalCount totalCount
} }

View File

@@ -284,6 +284,26 @@
flex-wrap: wrap; flex-wrap: wrap;
} }
/* Tweets */
.tweet {
font-size: 13px;
margin-top: 6px;
margin-bottom: 16px;
margin-left: 18px;
border-left: 3px solid #777777B2;
padding-left: 6px;
}
.tweet .mention, .tweet .link, .tweet .hashtag {
color: #0366d6;
}
.tweet .date {
margin: 6px 0;
font-size: 12px;
opacity: .7;
}
/* Fade animation */ /* Fade animation */
.af { .af {
opacity: 0; opacity: 0;

View File

@@ -39,7 +39,7 @@
//Compute licenses stats //Compute licenses stats
computed.licenses.favorite = Object.entries(computed.licenses.used).sort(([an, a], [bn, b]) => b - a).slice(0, 1).map(([name, value]) => name) || "" computed.licenses.favorite = Object.entries(computed.licenses.used).sort(([an, a], [bn, b]) => b - a).slice(0, 1).map(([name, value]) => name) || ""
//Compute total commits and sponsorships //Compute total commits
computed.commits += data.user.contributionsCollection.totalCommitContributions + data.user.contributionsCollection.restrictedContributionsCount computed.commits += data.user.contributionsCollection.totalCommitContributions + data.user.contributionsCollection.restrictedContributionsCount
//Compute registration date //Compute registration date

View File

@@ -64,7 +64,7 @@
{ {
//Build //Build
const code = await ejs.renderFile(path.join(__utils, "workflow.yml"), { const code = await ejs.renderFile(path.join(__utils, "workflow.yml"), {
releases:["master", "latest"], releases:["master"],
templates:(await fs.promises.readdir(__templates)).filter(name => !/.*[.]mjs$/.test(name)).sort(), templates:(await fs.promises.readdir(__templates)).filter(name => !/.*[.]mjs$/.test(name)).sort(),
testcase(context = {}) { testcase(context = {}) {
return [`with:`, ...Object.entries({ return [`with:`, ...Object.entries({

View File

@@ -182,4 +182,12 @@ jobs:
plugin_projects_limit: 2, plugin_projects_limit: 2,
}) %> }) %>
- name: ${{ matrix.template }} > Plugin > Tweets
uses: lowlighter/metrics@<%- release %>
<%- testcase({
plugin_tweets: true,
plugin_tweets_limit: 2,
plugin_tweets_token: "${{ secrets.TWITTER_TOKEN }}",
}) %>
<% } -%> <% } -%>