# Features
-- [GitHub Stats Card](#github-stats-card)
-- [GitHub Extra Pins](#github-extra-pins)
-- [Top Languages Card](#top-languages-card)
-- [Wakatime Week Stats](#wakatime-week-stats)
-- [Themes](#themes)
-- [Customization](#customization)
- - [Common Options](#common-options)
- - [Stats Card Exclusive Options](#stats-card-exclusive-options)
- - [Repo Card Exclusive Options](#repo-card-exclusive-options)
- - [Language Card Exclusive Options](#language-card-exclusive-options)
- - [Wakatime Card Exclusive Option](#wakatime-card-exclusive-options)
-- [Deploy Yourself](#deploy-on-your-own-vercel-instance)
+- [GitHub Stats Card](#github-stats-card)
+- [GitHub Extra Pins](#github-extra-pins)
+- [Top Languages Card](#top-languages-card)
+- [Wakatime Week Stats](#wakatime-week-stats)
+- [Themes](#themes)
+- [Customization](#customization)
+ - [Common Options](#common-options)
+ - [Stats Card Exclusive Options](#stats-card-exclusive-options)
+ - [Repo Card Exclusive Options](#repo-card-exclusive-options)
+ - [Language Card Exclusive Options](#language-card-exclusive-options)
+ - [Wakatime Card Exclusive Option](#wakatime-card-exclusive-options)
+- [Deploy Yourself](#deploy-on-your-own-vercel-instance)
# GitHub Stats Card
@@ -160,16 +159,16 @@ You can customize the appearance of your `Stats Card` or `Repo Card` however you
#### Common Options:
-- `title_color` - Card's title color _(hex color)_. Default: `2f80ed`.
-- `text_color` - Body text color _(hex color)_. Default: `434d58`.
-- `icon_color` - Icons color if available _(hex color)_. Default: `4c71f2`.
-- `border_color` - Card's border color _(hex color)_. Default: `e4e2e2` (Does not apply when `hide_border` is enabled).
-- `bg_color` - Card's background color _(hex color)_ **or** a gradient in the form of _angle,start,end_. Default: `fffefe`
-- `hide_border` - Hides the card's border _(boolean)_. Default: `false`
-- `theme` - name of the theme, choose from [all available themes](./themes/README.md). Default: `default` theme.
-- `cache_seconds` - set the cache header manually _(min: 7200, max: 86400)_. Default: `14400 seconds (4 hours)`.
-- `locale` - set the language in the card _(e.g. cn, de, es, etc.)_. Default: `en`.
-- `border_radius` - Corner rounding on the card. Default: `4.5`.
+- `title_color` - Card's title color _(hex color)_. Default: `2f80ed`.
+- `text_color` - Body text color _(hex color)_. Default: `434d58`.
+- `icon_color` - Icons color if available _(hex color)_. Default: `4c71f2`.
+- `border_color` - Card's border color _(hex color)_. Default: `e4e2e2` (Does not apply when `hide_border` is enabled).
+- `bg_color` - Card's background color _(hex color)_ **or** a gradient in the form of _angle,start,end_. Default: `fffefe`
+- `hide_border` - Hides the card's border _(boolean)_. Default: `false`
+- `theme` - name of the theme, choose from [all available themes](./themes/README.md). Default: `default` theme.
+- `cache_seconds` - set the cache header manually _(min: 7200, max: 86400)_. Default: `14400 seconds (4 hours)`.
+- `locale` - set the language in the card _(e.g. cn, de, es, etc.)_. Default: `en`.
+- `border_radius` - Corner rounding on the card. Default: `4.5`.
> Note: The minimum of cache_seconds is currently 4 hours as a temporary fix for PATs exhaustion.
@@ -177,43 +176,41 @@ You can customize the appearance of your `Stats Card` or `Repo Card` however you
You can provide multiple comma-separated values in the bg_color option to render a gradient, with the following format:
-```
-&bg_color=DEG,COLOR1,COLOR2,COLOR3...COLOR10
-```
+ &bg_color=DEG,COLOR1,COLOR2,COLOR3...COLOR10
> Note on cache: Repo cards have a default cache of 4 hours (14400 seconds) if the fork count & star count is less than 1k, otherwise, it's 2 hours (7200 seconds). Also, note that the cache is clamped to a minimum of 2 hours and a maximum of 24 hours.
#### Stats Card Exclusive Options:
-- `hide` - Hides the [specified items](#hiding-individual-stats) from stats _(Comma-separated values)_. Default: `[] (blank array)`.
-- `hide_title` - _(boolean)_. Default: `false`.
-- `card_width` - Set the card's width manually _(number)_. Default: `500px (approx.)`.
-- `hide_rank` - _(boolean)_ hides the rank and automatically resizes the card width. Default: `false`.
-- `show_icons` - _(boolean)_. Default: `false`.
-- `include_all_commits` - Count total commits instead of just the current year commits _(boolean)_. Default: `false`.
-- `count_private` - Count private commits _(boolean)_. Default: `false`.
-- `line_height` - Sets the line-height between text _(number)_. Default: `25`.
-- `exclude_repo` - Exclude stars from specified repositories _(Comma-separated values)_. Default: `[] (blank array)`.
-- `custom_title` - Sets a custom title for the card. Default: ` Github Stats`.
-- `text_bold` - Use bold text _(boolean)_. Default: `true`.
-- `disable_animations` - Disables all animations in the card _(boolean)_. Default: `false`.
+- `hide` - Hides the [specified items](#hiding-individual-stats) from stats _(Comma-separated values)_. Default: `[] (blank array)`.
+- `hide_title` - _(boolean)_. Default: `false`.
+- `card_width` - Set the card's width manually _(number)_. Default: `500px (approx.)`.
+- `hide_rank` - _(boolean)_ hides the rank and automatically resizes the card width. Default: `false`.
+- `show_icons` - _(boolean)_. Default: `false`.
+- `include_all_commits` - Count total commits instead of just the current year commits _(boolean)_. Default: `false`.
+- `count_private` - Count private commits _(boolean)_. Default: `false`.
+- `line_height` - Sets the line-height between text _(number)_. Default: `25`.
+- `exclude_repo` - Exclude stars from specified repositories _(Comma-separated values)_. Default: `[] (blank array)`.
+- `custom_title` - Sets a custom title for the card. Default: ` Github Stats`.
+- `text_bold` - Use bold text _(boolean)_. Default: `true`.
+- `disable_animations` - Disables all animations in the card _(boolean)_. Default: `false`.
> Note on `hide_rank`:
-When hide_rank=`true`, the minimum card width is 270 px + the title length and padding.
+> When hide_rank=`true`, the minimum card width is 270 px + the title length and padding.
#### Repo Card Exclusive Options:
-- `show_owner` - Show the repo's owner name _(boolean)_
+- `show_owner` - Show the repo's owner name _(boolean)_
#### Language Card Exclusive Options:
-- `hide` - Hide the languages specified from the card _(Comma-separated values)_
-- `hide_title` - _(boolean)_
-- `layout` - Switch between two available layouts `default` & `compact`
-- `card_width` - Set the card's width manually _(number)_
-- `langs_count` - Show more languages on the card, between 1-10, defaults to 5 _(number)_
-- `exclude_repo` - Exclude specified repositories _(Comma-separated values)_
-- `custom_title` - Sets a custom title for the card
+- `hide` - Hide the languages specified from the card _(Comma-separated values)_
+- `hide_title` - _(boolean)_
+- `layout` - Switch between two available layouts `default` & `compact`
+- `card_width` - Set the card's width manually _(number)_
+- `langs_count` - Show more languages on the card, between 1-10, defaults to 5 _(number)_
+- `exclude_repo` - Exclude specified repositories _(Comma-separated values)_
+- `custom_title` - Sets a custom title for the card
> :warning: **Important:**
> Language names should be uri-escaped, as specified in [Percent Encoding](https://en.wikipedia.org/wiki/Percent-encoding)
@@ -222,17 +219,17 @@ When hide_rank=`true`, the minimum card width is 270 px + the title length and p
#### Wakatime Card Exclusive Options:
-- `hide` - Hide the languages specified from the card _(Comma-separated values)_
-- `hide_title` - _(boolean)_
-- `line_height` - Sets the line-height between text _(number)_
-- `hide_progress` - Hides the progress bar and percentage _(boolean)_
-- `custom_title` - Sets a custom title for the card
-- `layout` - Switch between two available layouts `default` & `compact`
-- `langs_count` - Limit the number of languages on the card, defaults to all reported languages
-- `api_domain` - Set a custom API domain for the card, e.g. to use services like [Hakatime](https://github.com/mujx/hakatime) or [Wakapi](https://github.com/muety/wakapi)
-- `range` – Request a range different from your WakaTime default, e.g. `last_7_days`. See [WakaTime API docs](https://wakatime.com/developers#stats) for a list of available options.
+- `hide` - Hide the languages specified from the card _(Comma-separated values)_
+- `hide_title` - _(boolean)_
+- `line_height` - Sets the line-height between text _(number)_
+- `hide_progress` - Hides the progress bar and percentage _(boolean)_
+- `custom_title` - Sets a custom title for the card
+- `layout` - Switch between two available layouts `default` & `compact`
+- `langs_count` - Limit the number of languages on the card, defaults to all reported languages
+- `api_domain` - Set a custom API domain for the card, e.g. to use services like [Hakatime](https://github.com/mujx/hakatime) or [Wakapi](https://github.com/muety/wakapi)
+- `range` – Request a range different from your WakaTime default, e.g. `last_7_days`. See [WakaTime API docs](https://wakatime.com/developers#stats) for a list of available options.
----
+* * *
# GitHub Extra Pins
@@ -310,7 +307,7 @@ You can use the `&layout=compact` option to change the card design.
[![Top Langs](https://github-readme-stats.vercel.app/api/top-langs/?username=anuraghazra)](https://github.com/anuraghazra/github-readme-stats)
-- Compact layout
+- Compact layout
[![Top Langs](https://github-readme-stats.vercel.app/api/top-langs/?username=anuraghazra&layout=compact)](https://github.com/anuraghazra/github-readme-stats)
@@ -330,65 +327,65 @@ Change the `?username=` value to your [Wakatime](https://wakatime.com) username.
[![willianrod's wakatime stats](https://github-readme-stats.vercel.app/api/wakatime?username=willianrod&hide_progress=true)](https://github.com/anuraghazra/github-readme-stats)
-- Compact layout
+- Compact layout
[![willianrod's wakatime stats](https://github-readme-stats.vercel.app/api/wakatime?username=willianrod&layout=compact)](https://github.com/anuraghazra/github-readme-stats)
----
+* * *
### All Demos
-- Default
+- Default
![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra)
-- Hiding specific stats
+- Hiding specific stats
![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&hide=contribs,issues)
-- Showing icons
+- Showing icons
![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&hide=issues&show_icons=true)
-- Customize Border Color
+- Customize Border Color
![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&border_color=2e4058)
-- Include All Commits
+- Include All Commits
![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&include_all_commits=true)
-- Themes
+- Themes
Choose from any of the [default themes](#themes)
![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&theme=radical)
-- Gradient
+- Gradient
![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&bg_color=30,e96443,904e95&title_color=fff&text_color=fff)
-- Customizing stats card
+- Customizing stats card
![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api/?username=anuraghazra&show_icons=true&title_color=fff&icon_color=79ff97&text_color=9f9f9f&bg_color=151515)
-- Setting card locale
+- Setting card locale
![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api/?username=anuraghazra&locale=es)
-- Customizing repo card
+- Customizing repo card
![Customized Card](https://github-readme-stats.vercel.app/api/pin?username=anuraghazra&repo=github-readme-stats&title_color=fff&icon_color=f9f9f9&text_color=9f9f9f&bg_color=151515)
-- Top languages
+- Top languages
[![Top Langs](https://github-readme-stats.vercel.app/api/top-langs/?username=anuraghazra)](https://github.com/anuraghazra/github-readme-stats)
-- Wakatime card
+- Wakatime card
[![willianrod's wakatime stats](https://github-readme-stats.vercel.app/api/wakatime?username=willianrod)](https://github.com/anuraghazra/github-readme-stats)
----
+* * *
### Quick Tip (Align The Repo Cards)
@@ -416,23 +413,23 @@ NOTE: Since [#58](https://github.com/anuraghazra/github-readme-stats/pull/58) we
Guide on setting up Vercel 🔨
-1. Go to [vercel.com](https://vercel.com/)
-1. Click on `Log in`
- ![](https://files.catbox.moe/tct1wg.png)
-1. Sign in with GitHub by pressing `Continue with GitHub`
- ![](https://files.catbox.moe/btd78j.jpeg)
-1. Sign in to GitHub and allow access to all repositories, if prompted
-1. Fork this repo
-1. After forking the repo, open the [`vercel.json`](https://github.com/anuraghazra/github-readme-stats/blob/master/vercel.json#L5) file and change the `maxDuration` field to `10`
-1. Go back to your [Vercel dashboard](https://vercel.com/dashboard)
-1. Select `Import Project`
- ![](https://files.catbox.moe/qckos0.png)
-1. Select `Import Git Repository`. Select root and keep everything as is.
- ![](https://files.catbox.moe/pqub9q.png)
-1. Create a personal access token (PAT) [here](https://github.com/settings/tokens/new) and enable the `repo` permissions (this allows access to see private repo stats)
-1. Add the PAT as an environment variable named `PAT_1` (as shown).
- ![](https://files.catbox.moe/0ez4g7.png)
-1. Click deploy, and you're good to go. See your domains to use the API!
+1. Go to [vercel.com](https://vercel.com/)
+2. Click on `Log in`
+ ![](https://files.catbox.moe/tct1wg.png)
+3. Sign in with GitHub by pressing `Continue with GitHub`
+ ![](https://files.catbox.moe/btd78j.jpeg)
+4. Sign in to GitHub and allow access to all repositories, if prompted
+5. Fork this repo
+6. After forking the repo, open the [`vercel.json`](https://github.com/anuraghazra/github-readme-stats/blob/master/vercel.json#L5) file and change the `maxDuration` field to `10`
+7. Go back to your [Vercel dashboard](https://vercel.com/dashboard)
+8. Select `Import Project`
+ ![](https://files.catbox.moe/qckos0.png)
+9. Select `Import Git Repository`. Select root and keep everything as is.
+ ![](https://files.catbox.moe/pqub9q.png)
+10. Create a personal access token (PAT) [here](https://github.com/settings/tokens/new) and enable the `repo` permissions (this allows access to see private repo stats)
+11. Add the PAT as an environment variable named `PAT_1` (as shown).
+ ![](https://files.catbox.moe/0ez4g7.png)
+12. Click deploy, and you're good to go. See your domains to use the API!
@@ -443,17 +440,16 @@ this takes time. You can use this service for free.
However, if you are using this project and are happy with it or just want to encourage me to continue creating stuff, there are a few ways you can do it:-
-- Giving proper credit when you use github-readme-stats on your readme, linking back to it :D
-- Starring and sharing the project :rocket:
-- [![paypal.me/anuraghazra](https://ionicabizau.github.io/badges/paypal.svg)](https://www.paypal.me/anuraghazra) - You can make one-time donations via PayPal. I'll probably buy a ~~coffee~~ tea. :tea:
+- Giving proper credit when you use github-readme-stats on your readme, linking back to it :D
+- Starring and sharing the project :rocket:
+- [![paypal.me/anuraghazra](https://ionicabizau.github.io/badges/paypal.svg)](https://www.paypal.me/anuraghazra) - You can make one-time donations via PayPal. I'll probably buy a ~~coffee~~ tea. :tea:
Thanks! :heart:
----
+* * *
[![https://vercel.com?utm_source=github_readme_stats_team&utm_campaign=oss](./powered-by-vercel.svg)](https://vercel.com?utm_source=github_readme_stats_team&utm_campaign=oss)
-
-Contributions are welcome! <3
+Contributions are welcome! <3
Made with :heart: and JavaScript.
From c5bea57638b16002da1a93f880ebd43c01980b17 Mon Sep 17 00:00:00 2001
From: rickstaa
Date: Sun, 2 Oct 2022 18:07:43 +0200
Subject: [PATCH 020/157] docs: fix india care logo
---
readme.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/readme.md b/readme.md
index 51c7229b13706..ae8038855de03 100644
--- a/readme.md
+++ b/readme.md
@@ -63,7 +63,7 @@
-
+
Are you considering supporting the project by donating? Please DON'T!!
From aa084f31c4f076c1d1f2fbe6855f8de30afad6aa Mon Sep 17 00:00:00 2001
From: Manan1612
Date: Mon, 3 Oct 2022 02:42:32 -0400
Subject: [PATCH 021/157] Added Contributors Badge (#2096)
---
readme.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/readme.md b/readme.md
index ae8038855de03..b18cdf64d2a83 100644
--- a/readme.md
+++ b/readme.md
@@ -6,6 +6,9 @@
Love the project? Please consider donating to help it improve!
-
-
+
Are you considering supporting the project by donating? Please DON'T!!
@@ -74,8 +73,7 @@ Are you considering supporting the project by donating? Please DON'T!!
Instead, Help India fight the 2nd deadly wave of COVID-19.
Thousands of people are dying in India because of a lack of Oxygen & also COVID-related infrastructure.
-Visit and make a small donation to help us fight COVID and overcome this crisis.
-A small donation goes a long way. :heart:
+Visit and make a small donation to help us fight COVID and overcome this crisis. A small donation goes a long way. :heart:
Gostou do projeto? Por favor considere fazer uma doação para ajudar a melhorá-lo!
@@ -142,7 +144,7 @@ Personalize a aparência do seu `Stats Card` ou `Repo Card` da maneira que desej
- `cache_seconds` - Defina o cabeçalho do cache manualmente _(min: 1800, max: 86400)_
- `locale` - defina o idioma no cartão _(por exemplo. cn, de, es, etc.)_
-> Nota sobre o cache: Cartões de repositório tem um cache padrão de 30 minutos (1800 segundos), se o número a contagem de forks e contagem de estrelas é menor que 1 mil o padrão é 2 horas (7200). Note também que o cache é limitado a um mínimo de 30 minutos e um máximo de 24 horas.
+> Nota sobre o cache: Cartões de repositório tem um cache padrão de 30 minutos (1800 segundos), se o número a contagem de forks e contagem de estrelas é menor que 1 mil o padrão é 2 horas (7200 segundos). Note também que o cache é limitado a um mínimo de 30 minutos e um máximo de 24 horas.
#### Opções exclusivas do cartão de estatísticas:
@@ -167,7 +169,7 @@ Personalize a aparência do seu `Stats Card` ou `Repo Card` da maneira que desej
> :warning: **Importante:**
> Nomes de linguagens devem ser uma sequência escapada de URI, como específicado em [Codificação por cento](https://pt.wikipedia.org/wiki/Codificação_por_cento)
-> (Isso é: `c++` deve se tornar `c%2B%2B`, `jupyter notebook` deve se tornar `jupyter%20notebook`, etc.)
+> (Ou seja: `c++` deve se tornar `c%2B%2B`, `jupyter notebook` deve se tornar `jupyter%20notebook`, etc.)
---
From 9aa39dfe81649eef84e8b750be86993e35c93a2b Mon Sep 17 00:00:00 2001
From: Pranav Joglekar
Date: Sun, 20 Nov 2022 00:48:42 +0530
Subject: [PATCH 076/157] feat: allow users to pass ring_color param (#2075)
* fix: prevent crash if undefined color is passed to func fallbackColor
* feat: allow users to pass ring_color param
Before this commit, the ring color was always equal to the title color.
This commit allows the user to pass a ring_color property to allow him
to style the ring color the way he pleases to. If no ring_color is
passed we default to the title color.
* docs: improves ring color documentation
* fix: improve code style
Co-authored-by: rickstaa
---
api/index.js | 2 ++
readme.md | 1 +
src/cards/stats-card.js | 7 ++--
src/common/utils.js | 12 +++++--
src/getStyles.js | 5 +--
.../renderWakatimeCard.test.js.snap | 4 +--
tests/api.test.js | 35 +++++++++++++++++++
tests/renderStatsCard.test.js | 33 +++++++++++++++++
tests/utils.test.js | 23 ++++++++++++
9 files changed, 114 insertions(+), 8 deletions(-)
diff --git a/api/index.js b/api/index.js
index 34824ba658a1f..88bd3c2e3e7ea 100644
--- a/api/index.js
+++ b/api/index.js
@@ -26,6 +26,7 @@ export default async (req, res) => {
include_all_commits,
line_height,
title_color,
+ ring_color,
icon_color,
text_color,
text_bold,
@@ -76,6 +77,7 @@ export default async (req, res) => {
include_all_commits: parseBoolean(include_all_commits),
line_height,
title_color,
+ ring_color,
icon_color,
text_color,
text_bold: parseBoolean(text_bold),
diff --git a/readme.md b/readme.md
index e18efc80f73b9..bfe042fcc2032 100644
--- a/readme.md
+++ b/readme.md
@@ -286,6 +286,7 @@ You can provide multiple comma-separated values in the bg_color option to render
- `custom_title` - Sets a custom title for the card. Default: ` GitHub Stats`.
- `text_bold` - Use bold text _(boolean)_. Default: `true`.
- `disable_animations` - Disables all animations in the card _(boolean)_. Default: `false`.
+- `ring_color` - Color of the rank circle _(hex color)_. Defaults to the theme ring color if it exists and otherwise the title color.
> **Note**
> When hide_rank=`true`, the minimum card width is 270 px + the title length and padding.
diff --git a/src/cards/stats-card.js b/src/cards/stats-card.js
index 782ff069674bb..b078728ea54c3 100644
--- a/src/cards/stats-card.js
+++ b/src/cards/stats-card.js
@@ -89,6 +89,7 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
include_all_commits = false,
line_height = 25,
title_color,
+ ring_color,
icon_color,
text_color,
text_bold = true,
@@ -104,13 +105,14 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
const lheight = parseInt(String(line_height), 10);
// returns theme based colors with proper overrides and defaults
- const { titleColor, textColor, iconColor, bgColor, borderColor } =
+ const { titleColor, iconColor, textColor, bgColor, borderColor, ringColor } =
getCardColors({
title_color,
- icon_color,
text_color,
+ icon_color,
bg_color,
border_color,
+ ring_color,
theme,
});
@@ -201,6 +203,7 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
const progress = 100 - rank.score;
const cssStyles = getStyles({
titleColor,
+ ringColor,
textColor,
iconColor,
show_icons,
diff --git a/src/common/utils.js b/src/common/utils.js
index 43c7587fc2932..a0fbf3dabade7 100644
--- a/src/common/utils.js
+++ b/src/common/utils.js
@@ -133,9 +133,9 @@ function isValidGradient(colors) {
* @returns {string | string[]} The gradient or color.
*/
function fallbackColor(color, fallbackColor) {
- let colors = color.split(",");
let gradient = null;
+ let colors = color ? color.split(",") : [];
if (colors.length > 1 && isValidGradient(colors)) {
gradient = colors;
}
@@ -207,6 +207,7 @@ function getCardColors({
icon_color,
bg_color,
border_color,
+ ring_color,
theme,
fallbackTheme = "default",
}) {
@@ -221,6 +222,13 @@ function getCardColors({
title_color || selectedTheme.title_color,
"#" + defaultTheme.title_color,
);
+
+ // get the color provided by the user else the theme color
+ // finally if both colors are invalid we use the titleColor
+ const ringColor = fallbackColor(
+ ring_color || selectedTheme.ring_color,
+ titleColor,
+ );
const iconColor = fallbackColor(
icon_color || selectedTheme.icon_color,
"#" + defaultTheme.icon_color,
@@ -239,7 +247,7 @@ function getCardColors({
"#" + defaultBorderColor,
);
- return { titleColor, iconColor, textColor, bgColor, borderColor };
+ return { titleColor, iconColor, textColor, bgColor, borderColor, ringColor };
}
/**
diff --git a/src/getStyles.js b/src/getStyles.js
index 79692e8579035..f7b90f4adc7b4 100644
--- a/src/getStyles.js
+++ b/src/getStyles.js
@@ -77,6 +77,7 @@ const getStyles = ({
titleColor,
textColor,
iconColor,
+ ringColor,
show_icons,
progress,
}) => {
@@ -105,13 +106,13 @@ const getStyles = ({
}
.rank-circle-rim {
- stroke: ${titleColor};
+ stroke: ${ringColor};
fill: none;
stroke-width: 6;
opacity: 0.2;
}
.rank-circle {
- stroke: ${titleColor};
+ stroke: ${ringColor};
stroke-dasharray: 250;
fill: none;
stroke-width: 6;
diff --git a/tests/__snapshots__/renderWakatimeCard.test.js.snap b/tests/__snapshots__/renderWakatimeCard.test.js.snap
index 416ead953e459..cc6129272f51e 100644
--- a/tests/__snapshots__/renderWakatimeCard.test.js.snap
+++ b/tests/__snapshots__/renderWakatimeCard.test.js.snap
@@ -51,13 +51,13 @@ exports[`Test Render Wakatime Card should render correctly with compact layout 1
}
.rank-circle-rim {
- stroke: #2f80ed;
+ stroke: undefined;
fill: none;
stroke-width: 6;
opacity: 0.2;
}
.rank-circle {
- stroke: #2f80ed;
+ stroke: undefined;
stroke-dasharray: 250;
fill: none;
stroke-width: 6;
diff --git a/tests/api.test.js b/tests/api.test.js
index f77a7175b43d7..e1830858be063 100644
--- a/tests/api.test.js
+++ b/tests/api.test.js
@@ -248,4 +248,39 @@ describe("Test /api/", () => {
),
);
});
+
+ it("should allow changing ring_color", async () => {
+ const { req, res } = faker(
+ {
+ username: "anuraghazra",
+ hide: "issues,prs,contribs",
+ show_icons: true,
+ hide_border: true,
+ line_height: 100,
+ title_color: "fff",
+ ring_color: "0000ff",
+ icon_color: "fff",
+ text_color: "fff",
+ bg_color: "fff",
+ },
+ data,
+ );
+
+ await api(req, res);
+
+ expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml");
+ expect(res.send).toBeCalledWith(
+ renderStatsCard(stats, {
+ hide: ["issues", "prs", "contribs"],
+ show_icons: true,
+ hide_border: true,
+ line_height: 100,
+ title_color: "fff",
+ ring_color: "0000ff",
+ icon_color: "fff",
+ text_color: "fff",
+ bg_color: "fff",
+ }),
+ );
+ });
});
diff --git a/tests/renderStatsCard.test.js b/tests/renderStatsCard.test.js
index 69708137b334c..288048670f20b 100644
--- a/tests/renderStatsCard.test.js
+++ b/tests/renderStatsCard.test.js
@@ -239,6 +239,39 @@ describe("Test renderStatsCard", () => {
);
});
+ it("should render custom ring_color properly", () => {
+ const customColors = {
+ title_color: "5a0",
+ ring_color: "0000ff",
+ icon_color: "1b998b",
+ text_color: "9991",
+ bg_color: "252525",
+ };
+
+ document.body.innerHTML = renderStatsCard(stats, { ...customColors });
+
+ const styleTag = document.querySelector("style");
+ const stylesObject = cssToObject(styleTag.innerHTML);
+
+ const headerClassStyles = stylesObject[":host"][".header "];
+ const statClassStyles = stylesObject[":host"][".stat "];
+ const iconClassStyles = stylesObject[":host"][".icon "];
+ const rankCircleStyles = stylesObject[":host"][".rank-circle "];
+ const rankCircleRimStyles = stylesObject[":host"][".rank-circle-rim "];
+
+ expect(headerClassStyles.fill.trim()).toBe(`#${customColors.title_color}`);
+ expect(statClassStyles.fill.trim()).toBe(`#${customColors.text_color}`);
+ expect(iconClassStyles.fill.trim()).toBe(`#${customColors.icon_color}`);
+ expect(rankCircleStyles.stroke.trim()).toBe(`#${customColors.ring_color}`);
+ expect(rankCircleRimStyles.stroke.trim()).toBe(
+ `#${customColors.ring_color}`,
+ );
+ expect(queryByTestId(document.body, "card-bg")).toHaveAttribute(
+ "fill",
+ "#252525",
+ );
+ });
+
it("should render icons correctly", () => {
document.body.innerHTML = renderStatsCard(stats, {
show_icons: true,
diff --git a/tests/utils.test.js b/tests/utils.test.js
index b6e4a3be3f9f9..5f6231cceff2d 100644
--- a/tests/utils.test.js
+++ b/tests/utils.test.js
@@ -48,6 +48,7 @@ describe("Test utils.js", () => {
let colors = getCardColors({
title_color: "f00",
text_color: "0f0",
+ ring_color: "0000ff",
icon_color: "00f",
bg_color: "fff",
border_color: "fff",
@@ -57,6 +58,7 @@ describe("Test utils.js", () => {
titleColor: "#f00",
textColor: "#0f0",
iconColor: "#00f",
+ ringColor: "#0000ff",
bgColor: "#fff",
borderColor: "#fff",
});
@@ -75,6 +77,7 @@ describe("Test utils.js", () => {
titleColor: "#2f80ed",
textColor: "#0f0",
iconColor: "#00f",
+ ringColor: "#2f80ed",
bgColor: "#fff",
borderColor: "#e4e2e2",
});
@@ -87,11 +90,31 @@ describe("Test utils.js", () => {
expect(colors).toStrictEqual({
titleColor: "#fff",
textColor: "#9f9f9f",
+ ringColor: "#fff",
iconColor: "#79ff97",
bgColor: "#151515",
borderColor: "#e4e2e2",
});
});
+
+ it("getCardColors: should return ring color equal to title color if not ring color is defined", () => {
+ let colors = getCardColors({
+ title_color: "f00",
+ text_color: "0f0",
+ icon_color: "00f",
+ bg_color: "fff",
+ border_color: "fff",
+ theme: "dark",
+ });
+ expect(colors).toStrictEqual({
+ titleColor: "#f00",
+ textColor: "#0f0",
+ iconColor: "#00f",
+ ringColor: "#f00",
+ bgColor: "#fff",
+ borderColor: "#fff",
+ });
+ });
});
describe("wrapTextMultiline", () => {
From 0e02523459a527007f196cd1a35297d850d08839 Mon Sep 17 00:00:00 2001
From: Bradley Jester <109996512+jesterb0206@users.noreply.github.com>
Date: Sat, 19 Nov 2022 13:44:42 -0800
Subject: [PATCH 077/157] feat: added Date Night theme to index.js (#2264)
* Added Date Night theme to index.js
* My theme name should be in snake_case now
---
themes/index.js | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/themes/index.js b/themes/index.js
index 4279317b3edc3..a5d3abae8cb6f 100644
--- a/themes/index.js
+++ b/themes/index.js
@@ -367,6 +367,13 @@ export const themes = {
text_color: "e0def4",
bg_color: "191724",
},
+ date_night: {
+ title_color: "DA7885",
+ text_color: "E1B2A2",
+ icon_color: "BB8470",
+ border_color: "170F0C",
+ bg_color: "170F0C",
+ },
};
export default themes;
From b2e34ac8db9dd28f009ac1f7f657da8b7f21800c Mon Sep 17 00:00:00 2001
From: rickstaa
Date: Sun, 20 Nov 2022 08:39:44 +0100
Subject: [PATCH 078/157] test: update snapshots
---
tests/__snapshots__/renderWakatimeCard.test.js.snap | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tests/__snapshots__/renderWakatimeCard.test.js.snap b/tests/__snapshots__/renderWakatimeCard.test.js.snap
index cc6129272f51e..1c0bd701fbbfe 100644
--- a/tests/__snapshots__/renderWakatimeCard.test.js.snap
+++ b/tests/__snapshots__/renderWakatimeCard.test.js.snap
@@ -209,13 +209,13 @@ exports[`Test Render Wakatime Card should render correctly with compact layout w
}
.rank-circle-rim {
- stroke: #2f80ed;
+ stroke: undefined;
fill: none;
stroke-width: 6;
opacity: 0.2;
}
.rank-circle {
- stroke: #2f80ed;
+ stroke: undefined;
stroke-dasharray: 250;
fill: none;
stroke-width: 6;
From 4b656ebabb8cb866d08bd010df29845372027018 Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Mon, 21 Nov 2022 10:07:09 +0100
Subject: [PATCH 079/157] refactor: migrate to using arrow functions (#2033)
---
src/calculateRank.js | 10 ++---
src/common/utils.js | 62 +++++++++++++--------------
src/fetchers/repo-fetcher.js | 4 +-
src/fetchers/stats-fetcher.js | 6 +--
src/fetchers/top-languages-fetcher.js | 4 +-
src/translations.js | 4 +-
6 files changed, 45 insertions(+), 45 deletions(-)
diff --git a/src/calculateRank.js b/src/calculateRank.js
index 23d61dba35ddb..24845bc7d9944 100644
--- a/src/calculateRank.js
+++ b/src/calculateRank.js
@@ -9,7 +9,7 @@
* @param {number} to The value to calculate the probability for.
* @returns {number} Probability.
*/
-function normalcdf(mean, sigma, to) {
+const normalcdf = (mean, sigma, to) => {
var z = (to - mean) / Math.sqrt(2 * sigma * sigma);
var t = 1 / (1 + 0.3275911 * Math.abs(z));
var a1 = 0.254829592;
@@ -24,7 +24,7 @@ function normalcdf(mean, sigma, to) {
sign = -1;
}
return (1 / 2) * (1 + sign * erf);
-}
+};
/**
* Calculates the users rank.
@@ -38,7 +38,7 @@ function normalcdf(mean, sigma, to) {
* @param {number} stargazers The number of stars.
* @returns {{level: string, score: number}}} The users rank.
*/
-function calculateRank({
+const calculateRank = ({
totalRepos,
totalCommits,
contributions,
@@ -46,7 +46,7 @@ function calculateRank({
prs,
issues,
stargazers,
-}) {
+}) => {
const COMMITS_OFFSET = 1.65;
const CONTRIBS_OFFSET = 1.65;
const ISSUES_OFFSET = 1;
@@ -98,7 +98,7 @@ function calculateRank({
})();
return { level, score: normalizedScore };
-}
+};
export { calculateRank };
export default calculateRank;
diff --git a/src/common/utils.js b/src/common/utils.js
index a0fbf3dabade7..688219c8d8e18 100644
--- a/src/common/utils.js
+++ b/src/common/utils.js
@@ -42,13 +42,13 @@ const renderError = (message, secondaryMessage = "") => {
* @param {string} str String to encode.
* @returns {string} Encoded string.
*/
-function encodeHTML(str) {
+const encodeHTML = (str) => {
return str
.replace(/[\u00A0-\u9999<>&](?!#)/gim, (i) => {
return "" + i.charCodeAt(0) + ";";
})
.replace(/\u0008/gim, "");
-}
+};
/**
* Retrieves num with suffix k(thousands) precise to 1 decimal if greater than 999.
@@ -56,11 +56,11 @@ function encodeHTML(str) {
* @param {number} num The number to format.
* @returns {string|number} The formatted number.
*/
-function kFormatter(num) {
+const kFormatter = (num) => {
return Math.abs(num) > 999
? Math.sign(num) * parseFloat((Math.abs(num) / 1000).toFixed(1)) + "k"
: Math.sign(num) * Math.abs(num);
-}
+};
/**
* Checks if a string is a valid hex color.
@@ -68,11 +68,11 @@ function kFormatter(num) {
* @param {string} hexColor String to check.
* @returns {boolean} True if the given string is a valid hex color.
*/
-function isValidHexColor(hexColor) {
+const isValidHexColor = (hexColor) => {
return new RegExp(
/^([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}|[A-Fa-f0-9]{4})$/,
).test(hexColor);
-}
+};
/**
* Returns boolean if value is either "true" or "false" else the value as it is.
@@ -80,7 +80,7 @@ function isValidHexColor(hexColor) {
* @param {string} value The value to parse.
* @returns {boolean | string} The parsed value.
*/
-function parseBoolean(value) {
+const parseBoolean = (value) => {
if (value === "true") {
return true;
} else if (value === "false") {
@@ -88,7 +88,7 @@ function parseBoolean(value) {
} else {
return value;
}
-}
+};
/**
* Parse string to array of strings.
@@ -96,10 +96,10 @@ function parseBoolean(value) {
* @param {string} str The string to parse.
* @returns {string[]} The array of strings.
*/
-function parseArray(str) {
+const parseArray = (str) => {
if (!str) return [];
return str.split(",");
-}
+};
/**
* Clamp the given number between the given range.
@@ -109,11 +109,11 @@ function parseArray(str) {
* @param {number} max The maximum value.
* returns {number} The clamped number.
*/
-function clampValue(number, min, max) {
+const clampValue = (number, min, max) => {
// @ts-ignore
if (Number.isNaN(parseInt(number))) return min;
return Math.max(min, Math.min(number, max));
-}
+};
/**
* Check if the given string is a valid gradient.
@@ -121,9 +121,9 @@ function clampValue(number, min, max) {
* @param {string[]} colors Array of colors.
* @returns {boolean} True if the given string is a valid gradient.
*/
-function isValidGradient(colors) {
+const isValidGradient = (colors) => {
return isValidHexColor(colors[1]) && isValidHexColor(colors[2]);
-}
+};
/**
* Retrieves a gradient if color has more than one valid hex codes else a single color.
@@ -132,7 +132,7 @@ function isValidGradient(colors) {
* @param {string} fallbackColor The fallback color.
* @returns {string | string[]} The gradient or color.
*/
-function fallbackColor(color, fallbackColor) {
+const fallbackColor = (color, fallbackColor) => {
let gradient = null;
let colors = color ? color.split(",") : [];
@@ -144,7 +144,7 @@ function fallbackColor(color, fallbackColor) {
(gradient ? gradient : isValidHexColor(color) && `#${color}`) ||
fallbackColor
);
-}
+};
/**
* Send GraphQL request to GitHub API.
@@ -153,7 +153,7 @@ function fallbackColor(color, fallbackColor) {
* @param {import('axios').AxiosRequestConfig['headers']} headers Request headers.
* @returns {Promise} Request response.
*/
-function request(data, headers) {
+const request = (data, headers) => {
// @ts-ignore
return axios({
url: "https://api.github.com/graphql",
@@ -161,7 +161,7 @@ function request(data, headers) {
headers,
data,
});
-}
+};
/**
* Auto layout utility, allows us to layout things vertically or horizontally with
@@ -174,7 +174,7 @@ function request(data, headers) {
* @param {"column" | "row"?=} props.direction Direction to layout items.
* @returns {string[]} Array of items with proper layout.
*/
-function flexLayout({ items, gap, direction, sizes = [] }) {
+const flexLayout = ({ items, gap, direction, sizes = [] }) => {
let lastSize = 0;
// filter() for filtering out empty strings
return items.filter(Boolean).map((item, i) => {
@@ -186,7 +186,7 @@ function flexLayout({ items, gap, direction, sizes = [] }) {
lastSize += size + gap;
return `${item}`;
});
-}
+};
/**
* Returns theme based colors with proper overrides and defaults.
@@ -201,7 +201,7 @@ function flexLayout({ items, gap, direction, sizes = [] }) {
* @param {string} args.fallbackTheme Fallback theme.
*
*/
-function getCardColors({
+const getCardColors = ({
title_color,
text_color,
icon_color,
@@ -210,7 +210,7 @@ function getCardColors({
ring_color,
theme,
fallbackTheme = "default",
-}) {
+}) => {
const defaultTheme = themes[fallbackTheme];
const selectedTheme = themes[theme] || defaultTheme;
const defaultBorderColor =
@@ -248,7 +248,7 @@ function getCardColors({
);
return { titleColor, iconColor, textColor, bgColor, borderColor, ringColor };
-}
+};
/**
* Split text over multiple lines based on the card width.
@@ -258,7 +258,7 @@ function getCardColors({
* @param {number} maxLines Maximum number of lines.
* @returns {string[]} Array of lines.
*/
-function wrapTextMultiline(text, width = 59, maxLines = 3) {
+const wrapTextMultiline = (text, width = 59, maxLines = 3) => {
const fullWidthComma = ",";
const encoded = encodeHTML(text);
const isChinese = encoded.includes(fullWidthComma);
@@ -283,7 +283,7 @@ function wrapTextMultiline(text, width = 59, maxLines = 3) {
// Remove empty lines if text fits in less than maxLines lines
const multiLineText = lines.filter(Boolean);
return multiLineText;
-}
+};
const noop = () => {};
// return console instance based on the environment
@@ -349,7 +349,7 @@ class MissingParamError extends Error {
* @param {number} fontSize Font size.
* @returns {number} Text length.
*/
-function measureText(str, fontSize = 10) {
+const measureText = (str, fontSize = 10) => {
// prettier-ignore
const widths = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -381,7 +381,7 @@ function measureText(str, fontSize = 10) {
)
.reduce((cur, acc) => acc + cur) * fontSize
);
-}
+};
/** @param {string} name */
const lowercaseTrim = (name) => name.toLowerCase().trim();
@@ -394,7 +394,7 @@ const lowercaseTrim = (name) => name.toLowerCase().trim();
* @param {number} perChunk Number of languages per column.
* @returns {Array} Array of languages split in two columns.
*/
-function chunkArray(arr, perChunk) {
+const chunkArray = (arr, perChunk) => {
return arr.reduce((resultArray, item, index) => {
const chunkIndex = Math.floor(index / perChunk);
@@ -406,7 +406,7 @@ function chunkArray(arr, perChunk) {
return resultArray;
}, []);
-}
+};
/**
* Parse emoji from string.
@@ -414,12 +414,12 @@ function chunkArray(arr, perChunk) {
* @param {string} str String to parse emoji from.
* @returns {string} String with emoji parsed.
*/
-function parseEmojis(str) {
+const parseEmojis = (str) => {
if (!str) throw new Error("[parseEmoji]: str argument not provided");
return str.replace(/:\w+:/gm, (emoji) => {
return toEmoji.get(emoji) || "";
});
-}
+};
export {
ERROR_CARD_LENGTH,
diff --git a/src/fetchers/repo-fetcher.js b/src/fetchers/repo-fetcher.js
index 28dd89a7f3e4a..ff7a2be8164cc 100644
--- a/src/fetchers/repo-fetcher.js
+++ b/src/fetchers/repo-fetcher.js
@@ -60,7 +60,7 @@ const urlExample = "/api/pin?username=USERNAME&repo=REPO_NAME";
* @param {string} reponame GitHub repository name.
* @returns {Promise} Repository data.
*/
-async function fetchRepo(username, reponame) {
+const fetchRepo = async (username, reponame) => {
if (!username && !reponame) {
throw new MissingParamError(["username", "repo"], urlExample);
}
@@ -100,7 +100,7 @@ async function fetchRepo(username, reponame) {
starCount: data.organization.repository.stargazers.totalCount,
};
}
-}
+};
export { fetchRepo };
export default fetchRepo;
diff --git a/src/fetchers/stats-fetcher.js b/src/fetchers/stats-fetcher.js
index c236b5882b42f..9d17d009c0b70 100644
--- a/src/fetchers/stats-fetcher.js
+++ b/src/fetchers/stats-fetcher.js
@@ -188,12 +188,12 @@ const totalStarsFetcher = async (username, repoToHide) => {
* @param {boolean} include_all_commits Include all commits.
* @returns {Promise} Stats data.
*/
-async function fetchStats(
+const fetchStats = async (
username,
count_private = false,
include_all_commits = false,
exclude_repo = [],
-) {
+) => {
if (!username) throw new MissingParamError(["username"]);
const stats = {
@@ -275,7 +275,7 @@ async function fetchStats(
});
return stats;
-}
+};
export { fetchStats };
export default fetchStats;
diff --git a/src/fetchers/top-languages-fetcher.js b/src/fetchers/top-languages-fetcher.js
index 109fa06bd2207..5fa1c8040b170 100644
--- a/src/fetchers/top-languages-fetcher.js
+++ b/src/fetchers/top-languages-fetcher.js
@@ -57,7 +57,7 @@ const fetcher = (variables, token) => {
* @param {string[]} exclude_repo List of repositories to exclude.
* @returns {Promise} Top languages data.
*/
-async function fetchTopLanguages(username, exclude_repo = []) {
+const fetchTopLanguages = async (username, exclude_repo = []) => {
if (!username) throw new MissingParamError(["username"]);
const res = await retryer(fetcher, { login: username });
@@ -136,7 +136,7 @@ async function fetchTopLanguages(username, exclude_repo = []) {
}, {});
return topLangs;
-}
+};
export { fetchTopLanguages };
export default fetchTopLanguages;
diff --git a/src/translations.js b/src/translations.js
index 65fc231f59b4e..45c8295e024de 100644
--- a/src/translations.js
+++ b/src/translations.js
@@ -367,9 +367,9 @@ const availableLocales = Object.keys(repoCardLocales["repocard.archived"]);
* @param {string} locale The locale to check.
* @returns {boolean} Boolean specifying whether the locale is available or not.
*/
-function isLocaleAvailable(locale) {
+const isLocaleAvailable = (locale) => {
return availableLocales.includes(locale.toLowerCase());
-}
+};
export {
isLocaleAvailable,
From 5df25a64721847ae6086fd1fcae0b4724805f5a8 Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Mon, 21 Nov 2022 10:10:46 +0100
Subject: [PATCH 080/157] fix: improve boolean parse behaviour (#2029)
---
src/common/utils.js | 19 +++++++++++--------
tests/utils.test.js | 18 ++++++++++++++++++
2 files changed, 29 insertions(+), 8 deletions(-)
diff --git a/src/common/utils.js b/src/common/utils.js
index 688219c8d8e18..1215fc9ac8cc2 100644
--- a/src/common/utils.js
+++ b/src/common/utils.js
@@ -77,17 +77,20 @@ const isValidHexColor = (hexColor) => {
/**
* Returns boolean if value is either "true" or "false" else the value as it is.
*
- * @param {string} value The value to parse.
- * @returns {boolean | string} The parsed value.
+ * @param {string | boolean} value The value to parse.
+ * @returns {boolean | undefined } The parsed value.
*/
const parseBoolean = (value) => {
- if (value === "true") {
- return true;
- } else if (value === "false") {
- return false;
- } else {
- return value;
+ if (typeof value === "boolean") return value;
+
+ if (typeof value === "string") {
+ if (value.toLowerCase() === "true") {
+ return true;
+ } else if (value.toLowerCase() === "false") {
+ return false;
+ }
}
+ return undefined;
};
/**
diff --git a/tests/utils.test.js b/tests/utils.test.js
index 5f6231cceff2d..c91fe9d54ae5d 100644
--- a/tests/utils.test.js
+++ b/tests/utils.test.js
@@ -4,6 +4,7 @@ import {
encodeHTML,
getCardColors,
kFormatter,
+ parseBoolean,
renderError,
wrapTextMultiline,
} from "../src/common/utils.js";
@@ -19,6 +20,23 @@ describe("Test utils.js", () => {
expect(kFormatter(9900000)).toBe("9900k");
});
+ it("should test parseBoolean", () => {
+ expect(parseBoolean(true)).toBe(true);
+ expect(parseBoolean(false)).toBe(false);
+
+ expect(parseBoolean("true")).toBe(true);
+ expect(parseBoolean("false")).toBe(false);
+ expect(parseBoolean("True")).toBe(true);
+ expect(parseBoolean("False")).toBe(false);
+ expect(parseBoolean("TRUE")).toBe(true);
+ expect(parseBoolean("FALSE")).toBe(false);
+
+ expect(parseBoolean("1")).toBe(undefined);
+ expect(parseBoolean("0")).toBe(undefined);
+ expect(parseBoolean("")).toBe(undefined);
+ expect(parseBoolean(undefined)).toBe(undefined);
+ });
+
it("should test encodeHTML", () => {
expect(encodeHTML(`hello world<,.#4^&^@%!))`)).toBe(
"<html>hello world<,.#4^&^@%!))",
From 42a4b6f60a5d534c9de5434ebaa09f222ac40247 Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Mon, 21 Nov 2022 10:13:14 +0100
Subject: [PATCH 081/157] refactor: remove unused dotenv calls (#2059)
As explained in the Vercel documentation vercel ignores dot files (see
https://github.com/vercel/vercel/discussions/3962#discussioncomment-4277). It
instead loads the env variables defined in the vercel instance. As a
result we can therefore remove dotenv.
---
api/index.js | 3 ---
api/top-langs.js | 3 ---
api/wakatime.js | 3 ---
src/fetchers/stats-fetcher.js | 3 ---
src/fetchers/top-languages-fetcher.js | 3 ---
5 files changed, 15 deletions(-)
diff --git a/api/index.js b/api/index.js
index 88bd3c2e3e7ea..8fbe2bc28e998 100644
--- a/api/index.js
+++ b/api/index.js
@@ -1,4 +1,3 @@
-import * as dotenv from "dotenv";
import { renderStatsCard } from "../src/cards/stats-card.js";
import { blacklist } from "../src/common/blacklist.js";
import {
@@ -11,8 +10,6 @@ import {
import { fetchStats } from "../src/fetchers/stats-fetcher.js";
import { isLocaleAvailable } from "../src/translations.js";
-dotenv.config();
-
export default async (req, res) => {
const {
username,
diff --git a/api/top-langs.js b/api/top-langs.js
index 25f97c8b455b2..1b6b980d77c4b 100644
--- a/api/top-langs.js
+++ b/api/top-langs.js
@@ -1,4 +1,3 @@
-import * as dotenv from "dotenv";
import { renderTopLanguages } from "../src/cards/top-languages-card.js";
import { blacklist } from "../src/common/blacklist.js";
import {
@@ -11,8 +10,6 @@ import {
import { fetchTopLanguages } from "../src/fetchers/top-languages-fetcher.js";
import { isLocaleAvailable } from "../src/translations.js";
-dotenv.config();
-
export default async (req, res) => {
const {
username,
diff --git a/api/wakatime.js b/api/wakatime.js
index fb8caa51c9477..7680b76e602f2 100644
--- a/api/wakatime.js
+++ b/api/wakatime.js
@@ -1,4 +1,3 @@
-import * as dotenv from "dotenv";
import { renderWakatimeCard } from "../src/cards/wakatime-card.js";
import {
clampValue,
@@ -10,8 +9,6 @@ import {
import { fetchWakatimeStats } from "../src/fetchers/wakatime-fetcher.js";
import { isLocaleAvailable } from "../src/translations.js";
-dotenv.config();
-
export default async (req, res) => {
const {
username,
diff --git a/src/fetchers/stats-fetcher.js b/src/fetchers/stats-fetcher.js
index 9d17d009c0b70..7f6cb9e5e95b4 100644
--- a/src/fetchers/stats-fetcher.js
+++ b/src/fetchers/stats-fetcher.js
@@ -1,6 +1,5 @@
// @ts-check
import axios from "axios";
-import * as dotenv from "dotenv";
import githubUsernameRegex from "github-username-regex";
import { calculateRank } from "../calculateRank.js";
import { retryer } from "../common/retryer.js";
@@ -12,8 +11,6 @@ import {
wrapTextMultiline,
} from "../common/utils.js";
-dotenv.config();
-
/**
* Stats fetcher object.
*
diff --git a/src/fetchers/top-languages-fetcher.js b/src/fetchers/top-languages-fetcher.js
index 5fa1c8040b170..86d794435be08 100644
--- a/src/fetchers/top-languages-fetcher.js
+++ b/src/fetchers/top-languages-fetcher.js
@@ -1,5 +1,4 @@
// @ts-check
-import * as dotenv from "dotenv";
import { retryer } from "../common/retryer.js";
import {
CustomError,
@@ -9,8 +8,6 @@ import {
wrapTextMultiline,
} from "../common/utils.js";
-dotenv.config();
-
/**
* Top languages fetcher object.
*
From f07cd133d3166688c5883f64c6491665f38bba78 Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Mon, 21 Nov 2022 10:15:43 +0100
Subject: [PATCH 082/157] fix: fix retry max-out bug (#2121)
* fix: fix retry max-out bug
This commit makes sure that the retry function tests all PATs.
* style: format code
* test: fix retry tests
* style: format code
---
src/common/retryer.js | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/common/retryer.js b/src/common/retryer.js
index 77f69d3cbbbce..e54eedbec6dd5 100644
--- a/src/common/retryer.js
+++ b/src/common/retryer.js
@@ -1,5 +1,11 @@
import { CustomError, logger } from "./utils.js";
+// Script variables.
+const PATs = Object.keys(process.env).filter((key) =>
+ /PAT_\d*$/.exec(key),
+).length;
+const RETRIES = PATs ? PATs : 7;
+
/**
* Try to execute the fetcher function until it succeeds or the max number of retries is reached.
*
@@ -10,7 +16,7 @@ import { CustomError, logger } from "./utils.js";
* @returns Promise
*/
const retryer = async (fetcher, variables, retries = 0) => {
- if (retries > 7) {
+ if (retries > RETRIES) {
throw new CustomError("Maximum retries exceeded", CustomError.MAX_RETRY);
}
try {
From 3cb205c65b709688e48ee61ebeabbb3af1f72518 Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Mon, 21 Nov 2022 10:21:46 +0100
Subject: [PATCH 083/157] feat: improve card loading speed (#2124)
* feat: improve card loading times
This commit adds the `stale-while-revalidate` option to speed up the
card loading times.
* mend
---
api/index.js | 7 ++++++-
api/pin.js | 7 ++++++-
api/top-langs.js | 7 ++++++-
api/wakatime.js | 7 ++++++-
tests/api.test.js | 35 ++++++++++++++++++++++++++++++-----
5 files changed, 54 insertions(+), 9 deletions(-)
diff --git a/api/index.js b/api/index.js
index 8fbe2bc28e998..b449d43b49080 100644
--- a/api/index.js
+++ b/api/index.js
@@ -61,7 +61,12 @@ export default async (req, res) => {
CONSTANTS.ONE_DAY,
);
- res.setHeader("Cache-Control", `public, max-age=${cacheSeconds}`);
+ res.setHeader(
+ "Cache-Control",
+ `max-age=${
+ cacheSeconds / 2
+ }, s-maxage=${cacheSeconds}, stale-while-revalidate=${CONSTANTS.ONE_DAY}`,
+ );
return res.send(
renderStatsCard(stats, {
diff --git a/api/pin.js b/api/pin.js
index ef149948d0ef6..4838b0f02fece 100644
--- a/api/pin.js
+++ b/api/pin.js
@@ -58,7 +58,12 @@ export default async (req, res) => {
cacheSeconds = CONSTANTS.FOUR_HOURS;
}
- res.setHeader("Cache-Control", `public, max-age=${cacheSeconds}`);
+ res.setHeader(
+ "Cache-Control",
+ `max-age=${
+ cacheSeconds / 2
+ }, s-maxage=${cacheSeconds}, stale-while-revalidate=${CONSTANTS.ONE_DAY}`,
+ );
return res.send(
renderRepoCard(repoData, {
diff --git a/api/top-langs.js b/api/top-langs.js
index 1b6b980d77c4b..d183d3b455ca0 100644
--- a/api/top-langs.js
+++ b/api/top-langs.js
@@ -52,7 +52,12 @@ export default async (req, res) => {
CONSTANTS.ONE_DAY,
);
- res.setHeader("Cache-Control", `public, max-age=${cacheSeconds}`);
+ res.setHeader(
+ "Cache-Control",
+ `max-age=${
+ cacheSeconds / 2
+ }, s-maxage=${cacheSeconds}, stale-while-revalidate=${CONSTANTS.ONE_DAY}`,
+ );
return res.send(
renderTopLanguages(topLangs, {
diff --git a/api/wakatime.js b/api/wakatime.js
index 7680b76e602f2..d439c5b7ac8c6 100644
--- a/api/wakatime.js
+++ b/api/wakatime.js
@@ -52,7 +52,12 @@ export default async (req, res) => {
cacheSeconds = CONSTANTS.FOUR_HOURS;
}
- res.setHeader("Cache-Control", `public, max-age=${cacheSeconds}`);
+ res.setHeader(
+ "Cache-Control",
+ `max-age=${
+ cacheSeconds / 2
+ }, s-maxage=${cacheSeconds}, stale-while-revalidate=${CONSTANTS.ONE_DAY}`,
+ );
return res.send(
renderWakatimeCard(stats, {
diff --git a/tests/api.test.js b/tests/api.test.js
index e1830858be063..0037bcdb566b2 100644
--- a/tests/api.test.js
+++ b/tests/api.test.js
@@ -160,7 +160,12 @@ describe("Test /api/", () => {
expect(res.setHeader.mock.calls).toEqual([
["Content-Type", "image/svg+xml"],
- ["Cache-Control", `public, max-age=${CONSTANTS.FOUR_HOURS}`],
+ [
+ "Cache-Control",
+ `max-age=${CONSTANTS.FOUR_HOURS / 2}, s-maxage=${
+ CONSTANTS.FOUR_HOURS
+ }, stale-while-revalidate=${CONSTANTS.ONE_DAY}`,
+ ],
]);
});
@@ -170,7 +175,12 @@ describe("Test /api/", () => {
expect(res.setHeader.mock.calls).toEqual([
["Content-Type", "image/svg+xml"],
- ["Cache-Control", `public, max-age=${15000}`],
+ [
+ "Cache-Control",
+ `max-age=7500, s-maxage=${15000}, stale-while-revalidate=${
+ CONSTANTS.ONE_DAY
+ }`,
+ ],
]);
});
@@ -191,7 +201,12 @@ describe("Test /api/", () => {
expect(res.setHeader.mock.calls).toEqual([
["Content-Type", "image/svg+xml"],
- ["Cache-Control", `public, max-age=${CONSTANTS.ONE_DAY}`],
+ [
+ "Cache-Control",
+ `max-age=${CONSTANTS.ONE_DAY / 2}, s-maxage=${
+ CONSTANTS.ONE_DAY
+ }, stale-while-revalidate=${CONSTANTS.ONE_DAY}`,
+ ],
]);
}
@@ -202,7 +217,12 @@ describe("Test /api/", () => {
expect(res.setHeader.mock.calls).toEqual([
["Content-Type", "image/svg+xml"],
- ["Cache-Control", `public, max-age=${CONSTANTS.FOUR_HOURS}`],
+ [
+ "Cache-Control",
+ `max-age=${CONSTANTS.FOUR_HOURS / 2}, s-maxage=${
+ CONSTANTS.FOUR_HOURS
+ }, stale-while-revalidate=${CONSTANTS.ONE_DAY}`,
+ ],
]);
}
@@ -212,7 +232,12 @@ describe("Test /api/", () => {
expect(res.setHeader.mock.calls).toEqual([
["Content-Type", "image/svg+xml"],
- ["Cache-Control", `public, max-age=${CONSTANTS.FOUR_HOURS}`],
+ [
+ "Cache-Control",
+ `max-age=${CONSTANTS.FOUR_HOURS / 2}, s-maxage=${
+ CONSTANTS.FOUR_HOURS
+ }, stale-while-revalidate=${CONSTANTS.ONE_DAY}`,
+ ],
]);
}
});
From ada9cf4e0eeec24579ec12ee709fa7afd402fcf8 Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Mon, 21 Nov 2022 11:08:05 +0100
Subject: [PATCH 084/157] feat: add INCLUDE_ORGS env variable (#2275)
This commit adds an INCLUDE_ORGS ENV variable that can be used to include results from
organizations into the GRS cards for self-deployed Vercel instances.
**Warning**
This is a hidden feature since we can not officially support this on the Public
Vercel instance due to GraphQL and Vercel rate/timeout limits. You can set this env
variable via Vercel's ENV variable menu (see
https://vercel.com/docs/concepts/projects/environment-variables).
---
src/common/utils.js | 2 +-
src/fetchers/stats-fetcher.js | 25 +++++++++++++++++++------
src/fetchers/top-languages-fetcher.js | 12 +++++++++---
3 files changed, 29 insertions(+), 10 deletions(-)
diff --git a/src/common/utils.js b/src/common/utils.js
index 1215fc9ac8cc2..147f5408f81f3 100644
--- a/src/common/utils.js
+++ b/src/common/utils.js
@@ -77,7 +77,7 @@ const isValidHexColor = (hexColor) => {
/**
* Returns boolean if value is either "true" or "false" else the value as it is.
*
- * @param {string | boolean} value The value to parse.
+ * @param {string | boolean| undefined} value The value to parse.
* @returns {boolean | undefined } The parsed value.
*/
const parseBoolean = (value) => {
diff --git a/src/fetchers/stats-fetcher.js b/src/fetchers/stats-fetcher.js
index 7f6cb9e5e95b4..a8ed082c57102 100644
--- a/src/fetchers/stats-fetcher.js
+++ b/src/fetchers/stats-fetcher.js
@@ -7,6 +7,7 @@ import {
CustomError,
logger,
MissingParamError,
+ parseBoolean,
request,
wrapTextMultiline,
} from "../common/utils.js";
@@ -22,7 +23,7 @@ const fetcher = (variables, token) => {
return request(
{
query: `
- query userInfo($login: String!) {
+ query userInfo($login: String!, $ownerAffiliations: [RepositoryAffiliation]) {
user(login: $login) {
name
login
@@ -45,7 +46,7 @@ const fetcher = (variables, token) => {
followers {
totalCount
}
- repositories(ownerAffiliations: OWNER) {
+ repositories(ownerAffiliations: $ownerAffiliations) {
totalCount
}
}
@@ -70,9 +71,9 @@ const repositoriesFetcher = (variables, token) => {
return request(
{
query: `
- query userInfo($login: String!, $after: String) {
+ query userInfo($login: String!, $after: String, $ownerAffiliations: [RepositoryAffiliation]) {
user(login: $login) {
- repositories(first: 100, ownerAffiliations: OWNER, orderBy: {direction: DESC, field: STARGAZERS}, after: $after) {
+ repositories(first: 100, ownerAffiliations: $ownerAffiliations, orderBy: {direction: DESC, field: STARGAZERS}, after: $after) {
nodes {
name
stargazers {
@@ -149,7 +150,14 @@ const totalStarsFetcher = async (username, repoToHide) => {
let hasNextPage = true;
let endCursor = null;
while (hasNextPage) {
- const variables = { login: username, first: 100, after: endCursor };
+ const variables = {
+ login: username,
+ first: 100,
+ after: endCursor,
+ ownerAffiliations: parseBoolean(process.env.INCLUDE_ORGS)
+ ? ["OWNER", "COLLABORATOR"]
+ : ["OWNER"],
+ };
let res = await retryer(repositoriesFetcher, variables);
if (res.data.errors) {
@@ -203,7 +211,12 @@ const fetchStats = async (
rank: { level: "C", score: 0 },
};
- let res = await retryer(fetcher, { login: username });
+ let res = await retryer(fetcher, {
+ login: username,
+ ownerAffiliations: parseBoolean(process.env.INCLUDE_ORGS)
+ ? ["OWNER", "COLLABORATOR"]
+ : ["OWNER"],
+ });
// Catch GraphQL errors.
if (res.data.errors) {
diff --git a/src/fetchers/top-languages-fetcher.js b/src/fetchers/top-languages-fetcher.js
index 86d794435be08..cf8c3d16610ab 100644
--- a/src/fetchers/top-languages-fetcher.js
+++ b/src/fetchers/top-languages-fetcher.js
@@ -4,6 +4,7 @@ import {
CustomError,
logger,
MissingParamError,
+ parseBoolean,
request,
wrapTextMultiline,
} from "../common/utils.js";
@@ -19,10 +20,10 @@ const fetcher = (variables, token) => {
return request(
{
query: `
- query userInfo($login: String!) {
+ query userInfo($login: String!, $ownerAffiliations: [RepositoryAffiliation]) {
user(login: $login) {
# fetch only owner repos & not forks
- repositories(ownerAffiliations: OWNER, isFork: false, first: 100) {
+ repositories(ownerAffiliations: $ownerAffiliations, isFork: false, first: 100) {
nodes {
name
languages(first: 10, orderBy: {field: SIZE, direction: DESC}) {
@@ -57,7 +58,12 @@ const fetcher = (variables, token) => {
const fetchTopLanguages = async (username, exclude_repo = []) => {
if (!username) throw new MissingParamError(["username"]);
- const res = await retryer(fetcher, { login: username });
+ const res = await retryer(fetcher, {
+ login: username,
+ ownerAffiliations: parseBoolean(process.env.INCLUDE_ORGS)
+ ? ["OWNER", "COLLABORATOR"]
+ : ["OWNER"],
+ });
if (res.data.errors) {
logger.error(res.data.errors);
From 0efb982c2aa0c65eabfb8d774fa546a1685c0f28 Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Mon, 21 Nov 2022 11:15:32 +0100
Subject: [PATCH 085/157] Revert "feat: add INCLUDE_ORGS env variable (#2275)"
(#2276)
This reverts commit ada9cf4e0eeec24579ec12ee709fa7afd402fcf8.
---
src/common/utils.js | 2 +-
src/fetchers/stats-fetcher.js | 25 ++++++-------------------
src/fetchers/top-languages-fetcher.js | 12 +++---------
3 files changed, 10 insertions(+), 29 deletions(-)
diff --git a/src/common/utils.js b/src/common/utils.js
index 147f5408f81f3..1215fc9ac8cc2 100644
--- a/src/common/utils.js
+++ b/src/common/utils.js
@@ -77,7 +77,7 @@ const isValidHexColor = (hexColor) => {
/**
* Returns boolean if value is either "true" or "false" else the value as it is.
*
- * @param {string | boolean| undefined} value The value to parse.
+ * @param {string | boolean} value The value to parse.
* @returns {boolean | undefined } The parsed value.
*/
const parseBoolean = (value) => {
diff --git a/src/fetchers/stats-fetcher.js b/src/fetchers/stats-fetcher.js
index a8ed082c57102..7f6cb9e5e95b4 100644
--- a/src/fetchers/stats-fetcher.js
+++ b/src/fetchers/stats-fetcher.js
@@ -7,7 +7,6 @@ import {
CustomError,
logger,
MissingParamError,
- parseBoolean,
request,
wrapTextMultiline,
} from "../common/utils.js";
@@ -23,7 +22,7 @@ const fetcher = (variables, token) => {
return request(
{
query: `
- query userInfo($login: String!, $ownerAffiliations: [RepositoryAffiliation]) {
+ query userInfo($login: String!) {
user(login: $login) {
name
login
@@ -46,7 +45,7 @@ const fetcher = (variables, token) => {
followers {
totalCount
}
- repositories(ownerAffiliations: $ownerAffiliations) {
+ repositories(ownerAffiliations: OWNER) {
totalCount
}
}
@@ -71,9 +70,9 @@ const repositoriesFetcher = (variables, token) => {
return request(
{
query: `
- query userInfo($login: String!, $after: String, $ownerAffiliations: [RepositoryAffiliation]) {
+ query userInfo($login: String!, $after: String) {
user(login: $login) {
- repositories(first: 100, ownerAffiliations: $ownerAffiliations, orderBy: {direction: DESC, field: STARGAZERS}, after: $after) {
+ repositories(first: 100, ownerAffiliations: OWNER, orderBy: {direction: DESC, field: STARGAZERS}, after: $after) {
nodes {
name
stargazers {
@@ -150,14 +149,7 @@ const totalStarsFetcher = async (username, repoToHide) => {
let hasNextPage = true;
let endCursor = null;
while (hasNextPage) {
- const variables = {
- login: username,
- first: 100,
- after: endCursor,
- ownerAffiliations: parseBoolean(process.env.INCLUDE_ORGS)
- ? ["OWNER", "COLLABORATOR"]
- : ["OWNER"],
- };
+ const variables = { login: username, first: 100, after: endCursor };
let res = await retryer(repositoriesFetcher, variables);
if (res.data.errors) {
@@ -211,12 +203,7 @@ const fetchStats = async (
rank: { level: "C", score: 0 },
};
- let res = await retryer(fetcher, {
- login: username,
- ownerAffiliations: parseBoolean(process.env.INCLUDE_ORGS)
- ? ["OWNER", "COLLABORATOR"]
- : ["OWNER"],
- });
+ let res = await retryer(fetcher, { login: username });
// Catch GraphQL errors.
if (res.data.errors) {
diff --git a/src/fetchers/top-languages-fetcher.js b/src/fetchers/top-languages-fetcher.js
index cf8c3d16610ab..86d794435be08 100644
--- a/src/fetchers/top-languages-fetcher.js
+++ b/src/fetchers/top-languages-fetcher.js
@@ -4,7 +4,6 @@ import {
CustomError,
logger,
MissingParamError,
- parseBoolean,
request,
wrapTextMultiline,
} from "../common/utils.js";
@@ -20,10 +19,10 @@ const fetcher = (variables, token) => {
return request(
{
query: `
- query userInfo($login: String!, $ownerAffiliations: [RepositoryAffiliation]) {
+ query userInfo($login: String!) {
user(login: $login) {
# fetch only owner repos & not forks
- repositories(ownerAffiliations: $ownerAffiliations, isFork: false, first: 100) {
+ repositories(ownerAffiliations: OWNER, isFork: false, first: 100) {
nodes {
name
languages(first: 10, orderBy: {field: SIZE, direction: DESC}) {
@@ -58,12 +57,7 @@ const fetcher = (variables, token) => {
const fetchTopLanguages = async (username, exclude_repo = []) => {
if (!username) throw new MissingParamError(["username"]);
- const res = await retryer(fetcher, {
- login: username,
- ownerAffiliations: parseBoolean(process.env.INCLUDE_ORGS)
- ? ["OWNER", "COLLABORATOR"]
- : ["OWNER"],
- });
+ const res = await retryer(fetcher, { login: username });
if (res.data.errors) {
logger.error(res.data.errors);
From ad3726ee491492ab6d312cba09f738986192fd0e Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Tue, 22 Nov 2022 09:18:22 +0100
Subject: [PATCH 086/157] fix: fix repoContrib confusion (#2269) (#2274)
This commit prevents confusion about the Contributed to stat. Currently,
only the last year's results are shown, but it looks like it is the
all-time contribution count (see #2269). This commit adds a ' (last year)'
suffix to prevent this confusion from happening.
---
src/cards/stats-card.js | 4 ++--
tests/renderStatsCard.test.js | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/cards/stats-card.js b/src/cards/stats-card.js
index b078728ea54c3..a44f17f31f0f4 100644
--- a/src/cards/stats-card.js
+++ b/src/cards/stats-card.js
@@ -154,7 +154,7 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
},
contribs: {
icon: icons.contribs,
- label: i18n.t("statcard.contribs"),
+ label: i18n.t("statcard.contribs") + " (last year)",
value: contributedTo,
id: "contribs",
},
@@ -186,7 +186,7 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
index,
showIcons: show_icons,
shiftValuePos:
- (!include_all_commits ? 50 : 35) + (isLongLocale ? 50 : 0),
+ (!include_all_commits ? 79.01 : 35) + (isLongLocale ? 50 : 0),
bold: text_bold,
}),
);
diff --git a/tests/renderStatsCard.test.js b/tests/renderStatsCard.test.js
index 288048670f20b..e39e45b7870e3 100644
--- a/tests/renderStatsCard.test.js
+++ b/tests/renderStatsCard.test.js
@@ -344,7 +344,7 @@ describe("Test renderStatsCard", () => {
document.querySelector(
'g[transform="translate(0, 100)"]>.stagger>.stat.bold',
).textContent,
- ).toMatchInlineSnapshot(`"参与项目数:"`);
+ ).toMatchInlineSnapshot(`"参与项目数 (last year):"`);
});
it("should render without rounding", () => {
From 9eb0c3cbb40d551b93536c45100994d4c83b8c04 Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Tue, 22 Nov 2022 09:46:41 +0100
Subject: [PATCH 087/157] feat: fix 'include_all_commits' inner card margin
(#2283)
---
src/cards/stats-card.js | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/cards/stats-card.js b/src/cards/stats-card.js
index a44f17f31f0f4..a049ecce1c7e3 100644
--- a/src/cards/stats-card.js
+++ b/src/cards/stats-card.js
@@ -185,8 +185,7 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
...STATS[key],
index,
showIcons: show_icons,
- shiftValuePos:
- (!include_all_commits ? 79.01 : 35) + (isLongLocale ? 50 : 0),
+ shiftValuePos: 79.01 + (isLongLocale ? 50 : 0),
bold: text_bold,
}),
);
From 42fdff624fb7a3b389792f27352be594c2a45e07 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 9 Jan 2023 15:42:45 +0100
Subject: [PATCH 088/157] build(deps): bump json5 from 2.2.1 to 2.2.3 (#2373)
Bumps [json5](https://github.com/json5/json5) from 2.2.1 to 2.2.3.
- [Release notes](https://github.com/json5/json5/releases)
- [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md)
- [Commits](https://github.com/json5/json5/compare/v2.2.1...v2.2.3)
---
updated-dependencies:
- dependency-name: json5
dependency-type: indirect
...
Signed-off-by: dependabot[bot]
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
package-lock.json | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 048c316bfde58..64d79cfbe84d4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -3929,9 +3929,9 @@
"dev": true
},
"node_modules/json5": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
- "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true,
"bin": {
"json5": "lib/cli.js"
@@ -8656,9 +8656,9 @@
"dev": true
},
"json5": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
- "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true
},
"kleur": {
From 227711c6289679325b325ba8418a643354b76aa0 Mon Sep 17 00:00:00 2001
From: rickstaa
Date: Tue, 10 Jan 2023 10:08:33 +0000
Subject: [PATCH 089/157] test: update snapshots
---
tests/renderStatsCard.test.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/renderStatsCard.test.js b/tests/renderStatsCard.test.js
index e39e45b7870e3..5afb1f0218e5d 100644
--- a/tests/renderStatsCard.test.js
+++ b/tests/renderStatsCard.test.js
@@ -329,7 +329,7 @@ describe("Test renderStatsCard", () => {
document.querySelector(
'g[transform="translate(0, 25)"]>.stagger>.stat.bold',
).textContent,
- ).toMatchInlineSnapshot(`"累计提交数(commit) (2022):"`);
+ ).toMatchInlineSnapshot(`"累计提交数(commit) (2023):"`);
expect(
document.querySelector(
'g[transform="translate(0, 50)"]>.stagger>.stat.bold',
From 77dcdab42c306fd49e71e32a2335d6c06a90baf1 Mon Sep 17 00:00:00 2001
From: Huzaifa Khilawala <55500003+RedHeadphone@users.noreply.github.com>
Date: Tue, 10 Jan 2023 17:51:35 +0530
Subject: [PATCH 090/157] Add loading Animation to Most used Language card
(#2197)
* add: text animation
* compact progress done
* cleaned code
* non compact animation done
* tests fixed + prettier
* revert: vercel.json
* remove: unnecessary import
* added parameter in docs
* style: improve syntax
Co-authored-by: rickstaa
---
api/top-langs.js | 2 +
readme.md | 1 +
src/cards/top-languages-card.js | 82 ++++++++++++++++++++++++--------
src/cards/types.d.ts | 1 +
src/common/createProgressNode.js | 19 ++++----
5 files changed, 76 insertions(+), 29 deletions(-)
diff --git a/api/top-langs.js b/api/top-langs.js
index d183d3b455ca0..19cccb894e33a 100644
--- a/api/top-langs.js
+++ b/api/top-langs.js
@@ -29,6 +29,7 @@ export default async (req, res) => {
locale,
border_radius,
border_color,
+ disable_animations,
} = req.query;
res.setHeader("Content-Type", "image/svg+xml");
@@ -75,6 +76,7 @@ export default async (req, res) => {
border_radius,
border_color,
locale: locale ? locale.toLowerCase() : null,
+ disable_animations: parseBoolean(disable_animations),
}),
);
} catch (err) {
diff --git a/readme.md b/readme.md
index bfe042fcc2032..716bda22758c6 100644
--- a/readme.md
+++ b/readme.md
@@ -304,6 +304,7 @@ You can provide multiple comma-separated values in the bg_color option to render
- `langs_count` - Show more languages on the card, between 1-10 _(number)_. Default `5`.
- `exclude_repo` - Exclude specified repositories _(Comma-separated values)_. Default: `[] (blank array)`.
- `custom_title` - Sets a custom title for the card _(string)_. Default `Most Used Languages`.
+- `disable_animations` - Disables all animations in the card _(boolean)_. Default: `false`.
> **Warning**
> Language names should be URI-escaped, as specified in [Percent Encoding](https://en.wikipedia.org/wiki/Percent-encoding)
diff --git a/src/cards/top-languages-card.js b/src/cards/top-languages-card.js
index 602d1b811b5df..9396ff8e73d5e 100644
--- a/src/cards/top-languages-card.js
+++ b/src/cards/top-languages-card.js
@@ -39,46 +39,53 @@ const getLongestLang = (arr) =>
* Creates a node to display usage of a programming language in percentage
* using text and a horizontal progress bar.
*
- * @param {object[]} props Function properties.
+ * @param {object} props Function properties.
* @param {number} props.width The card width
* @param {string} props.name Name of the programming language.
* @param {string} props.color Color of the programming language.
* @param {string} props.progress Usage of the programming language in percentage.
+ * @param {number} props.index Index of the programming language.
* @returns {string} Programming language SVG node.
*/
-const createProgressTextNode = ({ width, color, name, progress }) => {
+const createProgressTextNode = ({ width, color, name, progress, index }) => {
+ const staggerDelay = (index + 3) * 150;
const paddingRight = 95;
const progressTextX = width - paddingRight + 10;
const progressWidth = width - paddingRight;
return `
- ${name}
- ${progress}%
- ${createProgressNode({
- x: 0,
- y: 25,
- color,
- width: progressWidth,
- progress,
- progressBarBackgroundColor: "#ddd",
- })}
+
+ ${name}
+ ${progress}%
+ ${createProgressNode({
+ x: 0,
+ y: 25,
+ color,
+ width: progressWidth,
+ progress,
+ progressBarBackgroundColor: "#ddd",
+ delay: staggerDelay + 300,
+ })}
+
`;
};
/**
* Creates a text only node to display usage of a programming language in percentage.
*
- * @param {object[]} props Function properties.
+ * @param {object} props Function properties.
* @param {Lang} props.lang Programming language object.
* @param {number} props.totalSize Total size of all languages.
+ * @param {number} props.index Index of the programming language.
* @returns {string} Compact layout programming language SVG node.
*/
-const createCompactLangNode = ({ lang, totalSize }) => {
+const createCompactLangNode = ({ lang, totalSize, index }) => {
const percentage = ((lang.size / totalSize) * 100).toFixed(2);
+ const staggerDelay = (index + 3) * 150;
const color = lang.color || "#858585";
return `
-
+
${lang.name} ${percentage}%
@@ -104,7 +111,6 @@ const createLanguageTextNode = ({ langs, totalSize }) => {
createCompactLangNode({
lang,
totalSize,
- // @ts-ignore
index,
}),
);
@@ -134,12 +140,13 @@ const createLanguageTextNode = ({ langs, totalSize }) => {
*/
const renderNormalLayout = (langs, width, totalLanguageSize) => {
return flexLayout({
- items: langs.map((lang) => {
+ items: langs.map((lang, index) => {
return createProgressTextNode({
- width: width,
+ width,
name: lang.name,
color: lang.color || DEFAULT_LANG_COLOR,
progress: ((lang.size / totalLanguageSize) * 100).toFixed(2),
+ index,
});
}),
gap: 40,
@@ -187,7 +194,7 @@ const renderCompactLayout = (langs, width, totalLanguageSize) => {
return `
-
+
${compactProgressBar}
@@ -276,6 +283,7 @@ const renderTopLanguages = (topLangs, options = {}) => {
langs_count = DEFAULT_LANGS_COUNT,
border_radius,
border_color,
+ disable_animations,
} = options;
const i18n = new I18n({
@@ -324,11 +332,43 @@ const renderTopLanguages = (topLangs, options = {}) => {
colors,
});
- card.disableAnimations();
+ if (disable_animations) card.disableAnimations();
+
card.setHideBorder(hide_border);
card.setHideTitle(hide_title);
card.setCSS(
- `.lang-name { font: 400 11px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${colors.textColor} }`,
+ `
+ @keyframes slideInAnimation {
+ from {
+ width: 0;
+ }
+ to {
+ width: calc(100%-100px);
+ }
+ }
+ @keyframes growWidthAnimation {
+ from {
+ width: 0;
+ }
+ to {
+ width: 100%;
+ }
+ }
+ .lang-name {
+ font: 400 11px "Segoe UI", Ubuntu, Sans-Serif;
+ fill: ${colors.textColor};
+ }
+ .stagger {
+ opacity: 0;
+ animation: fadeInAnimation 0.3s ease-in-out forwards;
+ }
+ #rect-mask rect{
+ animation: slideInAnimation 1s ease-in-out forwards;
+ }
+ .lang-progress{
+ animation: growWidthAnimation 0.6s ease-in-out forwards;
+ }
+ `,
);
return card.render(`
diff --git a/src/cards/types.d.ts b/src/cards/types.d.ts
index 502314c41fa92..c5945d48be71e 100644
--- a/src/cards/types.d.ts
+++ b/src/cards/types.d.ts
@@ -37,6 +37,7 @@ export type TopLangOptions = CommonOptions & {
layout: "compact" | "normal";
custom_title: string;
langs_count: number;
+ disable_animations: boolean;
};
type WakaTimeOptions = CommonOptions & {
diff --git a/src/common/createProgressNode.js b/src/common/createProgressNode.js
index c36818b193b2f..2825583c7406a 100644
--- a/src/common/createProgressNode.js
+++ b/src/common/createProgressNode.js
@@ -10,6 +10,7 @@ import { clampValue } from "./utils.js";
* @param {string} createProgressNodeParams.color Progress color.
* @param {string} createProgressNodeParams.progress Progress value.
* @param {string} createProgressNodeParams.progressBarBackgroundColor Progress bar bg color.
+ * @param {number} createProgressNodeParams.delay Delay before animation starts.
* @returns {string} Progress node.
*/
const createProgressNode = ({
@@ -19,20 +20,22 @@ const createProgressNode = ({
color,
progress,
progressBarBackgroundColor,
+ delay,
}) => {
const progressPercentage = clampValue(progress, 2, 100);
return `
-
-
+
+
+
`;
};
From 5ae959b57c0831bc79d43425e07d0fe7c6a58011 Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Tue, 10 Jan 2023 13:25:06 +0100
Subject: [PATCH 091/157] ci: fix theme readme generation action (#2271)
---
scripts/push-theme-readme.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/push-theme-readme.sh b/scripts/push-theme-readme.sh
index 4a035db3041a0..1ab5de474ea5a 100755
--- a/scripts/push-theme-readme.sh
+++ b/scripts/push-theme-readme.sh
@@ -9,6 +9,6 @@ git config --global user.name "GitHub Readme Stats Bot"
git branch -d $BRANCH_NAME || true
git checkout -b $BRANCH_NAME
git add --all
-git commit --message "docs(theme): Auto update theme readme" || exit 0
+git commit --no-verify --message "docs(theme): Auto update theme readme"
git remote add origin-$BRANCH_NAME https://${PERSONAL_TOKEN}@github.com/${GH_REPO}.git
git push --force --quiet --set-upstream origin-$BRANCH_NAME $BRANCH_NAME
From 0850a9763058aa018b8538b34772f98bbf759aa2 Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Thu, 12 Jan 2023 22:44:27 +0100
Subject: [PATCH 092/157] Revert "build(deps): bump json5 from 2.2.1 to 2.2.3
(#2373)" (#2393)
This reverts commit 42fdff624fb7a3b389792f27352be594c2a45e07.
---
package-lock.json | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 64d79cfbe84d4..048c316bfde58 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -3929,9 +3929,9 @@
"dev": true
},
"node_modules/json5": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
- "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
+ "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
"dev": true,
"bin": {
"json5": "lib/cli.js"
@@ -8656,9 +8656,9 @@
"dev": true
},
"json5": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
- "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
+ "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
"dev": true
},
"kleur": {
From 70f0264905d9370efa635b6a611c8719b8958efa Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Thu, 12 Jan 2023 22:48:28 +0100
Subject: [PATCH 093/157] Revert "ci: fix theme readme generation action
(#2271)" (#2394)
This reverts commit 5ae959b57c0831bc79d43425e07d0fe7c6a58011.
---
scripts/push-theme-readme.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/push-theme-readme.sh b/scripts/push-theme-readme.sh
index 1ab5de474ea5a..4a035db3041a0 100755
--- a/scripts/push-theme-readme.sh
+++ b/scripts/push-theme-readme.sh
@@ -9,6 +9,6 @@ git config --global user.name "GitHub Readme Stats Bot"
git branch -d $BRANCH_NAME || true
git checkout -b $BRANCH_NAME
git add --all
-git commit --no-verify --message "docs(theme): Auto update theme readme"
+git commit --message "docs(theme): Auto update theme readme" || exit 0
git remote add origin-$BRANCH_NAME https://${PERSONAL_TOKEN}@github.com/${GH_REPO}.git
git push --force --quiet --set-upstream origin-$BRANCH_NAME $BRANCH_NAME
From 4b8198fa2198da394b71e43fe4c59862a7014287 Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Thu, 12 Jan 2023 22:52:34 +0100
Subject: [PATCH 094/157] Revert "Add loading Animation to Most used Language
card (#2197)" (#2396)
This reverts commit 77dcdab42c306fd49e71e32a2335d6c06a90baf1.
---
api/top-langs.js | 2 -
readme.md | 1 -
src/cards/top-languages-card.js | 82 ++++++++------------------------
src/cards/types.d.ts | 1 -
src/common/createProgressNode.js | 19 ++++----
5 files changed, 29 insertions(+), 76 deletions(-)
diff --git a/api/top-langs.js b/api/top-langs.js
index 19cccb894e33a..d183d3b455ca0 100644
--- a/api/top-langs.js
+++ b/api/top-langs.js
@@ -29,7 +29,6 @@ export default async (req, res) => {
locale,
border_radius,
border_color,
- disable_animations,
} = req.query;
res.setHeader("Content-Type", "image/svg+xml");
@@ -76,7 +75,6 @@ export default async (req, res) => {
border_radius,
border_color,
locale: locale ? locale.toLowerCase() : null,
- disable_animations: parseBoolean(disable_animations),
}),
);
} catch (err) {
diff --git a/readme.md b/readme.md
index 716bda22758c6..bfe042fcc2032 100644
--- a/readme.md
+++ b/readme.md
@@ -304,7 +304,6 @@ You can provide multiple comma-separated values in the bg_color option to render
- `langs_count` - Show more languages on the card, between 1-10 _(number)_. Default `5`.
- `exclude_repo` - Exclude specified repositories _(Comma-separated values)_. Default: `[] (blank array)`.
- `custom_title` - Sets a custom title for the card _(string)_. Default `Most Used Languages`.
-- `disable_animations` - Disables all animations in the card _(boolean)_. Default: `false`.
> **Warning**
> Language names should be URI-escaped, as specified in [Percent Encoding](https://en.wikipedia.org/wiki/Percent-encoding)
diff --git a/src/cards/top-languages-card.js b/src/cards/top-languages-card.js
index 9396ff8e73d5e..602d1b811b5df 100644
--- a/src/cards/top-languages-card.js
+++ b/src/cards/top-languages-card.js
@@ -39,53 +39,46 @@ const getLongestLang = (arr) =>
* Creates a node to display usage of a programming language in percentage
* using text and a horizontal progress bar.
*
- * @param {object} props Function properties.
+ * @param {object[]} props Function properties.
* @param {number} props.width The card width
* @param {string} props.name Name of the programming language.
* @param {string} props.color Color of the programming language.
* @param {string} props.progress Usage of the programming language in percentage.
- * @param {number} props.index Index of the programming language.
* @returns {string} Programming language SVG node.
*/
-const createProgressTextNode = ({ width, color, name, progress, index }) => {
- const staggerDelay = (index + 3) * 150;
+const createProgressTextNode = ({ width, color, name, progress }) => {
const paddingRight = 95;
const progressTextX = width - paddingRight + 10;
const progressWidth = width - paddingRight;
return `
-
- ${name}
- ${progress}%
- ${createProgressNode({
- x: 0,
- y: 25,
- color,
- width: progressWidth,
- progress,
- progressBarBackgroundColor: "#ddd",
- delay: staggerDelay + 300,
- })}
-
+ ${name}
+ ${progress}%
+ ${createProgressNode({
+ x: 0,
+ y: 25,
+ color,
+ width: progressWidth,
+ progress,
+ progressBarBackgroundColor: "#ddd",
+ })}
`;
};
/**
* Creates a text only node to display usage of a programming language in percentage.
*
- * @param {object} props Function properties.
+ * @param {object[]} props Function properties.
* @param {Lang} props.lang Programming language object.
* @param {number} props.totalSize Total size of all languages.
- * @param {number} props.index Index of the programming language.
* @returns {string} Compact layout programming language SVG node.
*/
-const createCompactLangNode = ({ lang, totalSize, index }) => {
+const createCompactLangNode = ({ lang, totalSize }) => {
const percentage = ((lang.size / totalSize) * 100).toFixed(2);
- const staggerDelay = (index + 3) * 150;
const color = lang.color || "#858585";
return `
-
+
${lang.name} ${percentage}%
@@ -111,6 +104,7 @@ const createLanguageTextNode = ({ langs, totalSize }) => {
createCompactLangNode({
lang,
totalSize,
+ // @ts-ignore
index,
}),
);
@@ -140,13 +134,12 @@ const createLanguageTextNode = ({ langs, totalSize }) => {
*/
const renderNormalLayout = (langs, width, totalLanguageSize) => {
return flexLayout({
- items: langs.map((lang, index) => {
+ items: langs.map((lang) => {
return createProgressTextNode({
- width,
+ width: width,
name: lang.name,
color: lang.color || DEFAULT_LANG_COLOR,
progress: ((lang.size / totalLanguageSize) * 100).toFixed(2),
- index,
});
}),
gap: 40,
@@ -194,7 +187,7 @@ const renderCompactLayout = (langs, width, totalLanguageSize) => {
return `
-
+
${compactProgressBar}
@@ -283,7 +276,6 @@ const renderTopLanguages = (topLangs, options = {}) => {
langs_count = DEFAULT_LANGS_COUNT,
border_radius,
border_color,
- disable_animations,
} = options;
const i18n = new I18n({
@@ -332,43 +324,11 @@ const renderTopLanguages = (topLangs, options = {}) => {
colors,
});
- if (disable_animations) card.disableAnimations();
-
+ card.disableAnimations();
card.setHideBorder(hide_border);
card.setHideTitle(hide_title);
card.setCSS(
- `
- @keyframes slideInAnimation {
- from {
- width: 0;
- }
- to {
- width: calc(100%-100px);
- }
- }
- @keyframes growWidthAnimation {
- from {
- width: 0;
- }
- to {
- width: 100%;
- }
- }
- .lang-name {
- font: 400 11px "Segoe UI", Ubuntu, Sans-Serif;
- fill: ${colors.textColor};
- }
- .stagger {
- opacity: 0;
- animation: fadeInAnimation 0.3s ease-in-out forwards;
- }
- #rect-mask rect{
- animation: slideInAnimation 1s ease-in-out forwards;
- }
- .lang-progress{
- animation: growWidthAnimation 0.6s ease-in-out forwards;
- }
- `,
+ `.lang-name { font: 400 11px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${colors.textColor} }`,
);
return card.render(`
diff --git a/src/cards/types.d.ts b/src/cards/types.d.ts
index c5945d48be71e..502314c41fa92 100644
--- a/src/cards/types.d.ts
+++ b/src/cards/types.d.ts
@@ -37,7 +37,6 @@ export type TopLangOptions = CommonOptions & {
layout: "compact" | "normal";
custom_title: string;
langs_count: number;
- disable_animations: boolean;
};
type WakaTimeOptions = CommonOptions & {
diff --git a/src/common/createProgressNode.js b/src/common/createProgressNode.js
index 2825583c7406a..c36818b193b2f 100644
--- a/src/common/createProgressNode.js
+++ b/src/common/createProgressNode.js
@@ -10,7 +10,6 @@ import { clampValue } from "./utils.js";
* @param {string} createProgressNodeParams.color Progress color.
* @param {string} createProgressNodeParams.progress Progress value.
* @param {string} createProgressNodeParams.progressBarBackgroundColor Progress bar bg color.
- * @param {number} createProgressNodeParams.delay Delay before animation starts.
* @returns {string} Progress node.
*/
const createProgressNode = ({
@@ -20,22 +19,20 @@ const createProgressNode = ({
color,
progress,
progressBarBackgroundColor,
- delay,
}) => {
const progressPercentage = clampValue(progress, 2, 100);
return `
-
-
-
+
+
`;
};
From 0ff426d258387ecd0ebbb9206d91b96781e61cf0 Mon Sep 17 00:00:00 2001
From: Anurag Hazra
Date: Fri, 13 Jan 2023 13:16:33 +0530
Subject: [PATCH 095/157] fix: retryer fixed (#2400)
---
src/common/retryer.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/common/retryer.js b/src/common/retryer.js
index e54eedbec6dd5..73833ef85b3a4 100644
--- a/src/common/retryer.js
+++ b/src/common/retryer.js
@@ -45,8 +45,9 @@ const retryer = async (fetcher, variables, retries = 0) => {
// prettier-ignore
// also checking for bad credentials if any tokens gets invalidated
const isBadCredential = err.response.data && err.response.data.message === "Bad credentials";
+ const isAccountSuspended = err.response.data && err.response.data.message === "Sorry. Your account was suspended.";
- if (isBadCredential) {
+ if (isBadCredential || isAccountSuspended) {
logger.log(`PAT_${retries + 1} Failed`);
retries++;
// directly return from the function
From ab9c563ec51a0843ab8ad0877d5f9dd491d23e00 Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Mon, 16 Jan 2023 12:21:13 +0100
Subject: [PATCH 096/157] Revert "Revert "ci: fix theme readme generation
action (#2271)" (#2394)" (#2418)
This reverts commit 70f0264905d9370efa635b6a611c8719b8958efa.
---
scripts/push-theme-readme.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/push-theme-readme.sh b/scripts/push-theme-readme.sh
index 4a035db3041a0..1ab5de474ea5a 100755
--- a/scripts/push-theme-readme.sh
+++ b/scripts/push-theme-readme.sh
@@ -9,6 +9,6 @@ git config --global user.name "GitHub Readme Stats Bot"
git branch -d $BRANCH_NAME || true
git checkout -b $BRANCH_NAME
git add --all
-git commit --message "docs(theme): Auto update theme readme" || exit 0
+git commit --no-verify --message "docs(theme): Auto update theme readme"
git remote add origin-$BRANCH_NAME https://${PERSONAL_TOKEN}@github.com/${GH_REPO}.git
git push --force --quiet --set-upstream origin-$BRANCH_NAME $BRANCH_NAME
From ad9db67b4c551aba6e19cc5af9030d85ac1c4906 Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Mon, 16 Jan 2023 12:28:31 +0100
Subject: [PATCH 097/157] refactor: update code formatting
---
src/common/retryer.js | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/common/retryer.js b/src/common/retryer.js
index 73833ef85b3a4..5351cbe8cf99a 100644
--- a/src/common/retryer.js
+++ b/src/common/retryer.js
@@ -45,7 +45,9 @@ const retryer = async (fetcher, variables, retries = 0) => {
// prettier-ignore
// also checking for bad credentials if any tokens gets invalidated
const isBadCredential = err.response.data && err.response.data.message === "Bad credentials";
- const isAccountSuspended = err.response.data && err.response.data.message === "Sorry. Your account was suspended.";
+ const isAccountSuspended =
+ err.response.data &&
+ err.response.data.message === "Sorry. Your account was suspended.";
if (isBadCredential || isAccountSuspended) {
logger.log(`PAT_${retries + 1} Failed`);
From 06a2a78cfcb1cd29c3b8b46d3899ffac10ab14b8 Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Mon, 16 Jan 2023 12:30:39 +0100
Subject: [PATCH 098/157] Revert "Revert "Add loading Animation to Most used
Language card (#2197)" (#2396)" (#2419)
This reverts commit 4b8198fa2198da394b71e43fe4c59862a7014287.
---
api/top-langs.js | 2 +
readme.md | 1 +
src/cards/top-languages-card.js | 82 ++++++++++++++++++++++++--------
src/cards/types.d.ts | 1 +
src/common/createProgressNode.js | 19 ++++----
5 files changed, 76 insertions(+), 29 deletions(-)
diff --git a/api/top-langs.js b/api/top-langs.js
index d183d3b455ca0..19cccb894e33a 100644
--- a/api/top-langs.js
+++ b/api/top-langs.js
@@ -29,6 +29,7 @@ export default async (req, res) => {
locale,
border_radius,
border_color,
+ disable_animations,
} = req.query;
res.setHeader("Content-Type", "image/svg+xml");
@@ -75,6 +76,7 @@ export default async (req, res) => {
border_radius,
border_color,
locale: locale ? locale.toLowerCase() : null,
+ disable_animations: parseBoolean(disable_animations),
}),
);
} catch (err) {
diff --git a/readme.md b/readme.md
index bfe042fcc2032..716bda22758c6 100644
--- a/readme.md
+++ b/readme.md
@@ -304,6 +304,7 @@ You can provide multiple comma-separated values in the bg_color option to render
- `langs_count` - Show more languages on the card, between 1-10 _(number)_. Default `5`.
- `exclude_repo` - Exclude specified repositories _(Comma-separated values)_. Default: `[] (blank array)`.
- `custom_title` - Sets a custom title for the card _(string)_. Default `Most Used Languages`.
+- `disable_animations` - Disables all animations in the card _(boolean)_. Default: `false`.
> **Warning**
> Language names should be URI-escaped, as specified in [Percent Encoding](https://en.wikipedia.org/wiki/Percent-encoding)
diff --git a/src/cards/top-languages-card.js b/src/cards/top-languages-card.js
index 602d1b811b5df..9396ff8e73d5e 100644
--- a/src/cards/top-languages-card.js
+++ b/src/cards/top-languages-card.js
@@ -39,46 +39,53 @@ const getLongestLang = (arr) =>
* Creates a node to display usage of a programming language in percentage
* using text and a horizontal progress bar.
*
- * @param {object[]} props Function properties.
+ * @param {object} props Function properties.
* @param {number} props.width The card width
* @param {string} props.name Name of the programming language.
* @param {string} props.color Color of the programming language.
* @param {string} props.progress Usage of the programming language in percentage.
+ * @param {number} props.index Index of the programming language.
* @returns {string} Programming language SVG node.
*/
-const createProgressTextNode = ({ width, color, name, progress }) => {
+const createProgressTextNode = ({ width, color, name, progress, index }) => {
+ const staggerDelay = (index + 3) * 150;
const paddingRight = 95;
const progressTextX = width - paddingRight + 10;
const progressWidth = width - paddingRight;
return `
- ${name}
- ${progress}%
- ${createProgressNode({
- x: 0,
- y: 25,
- color,
- width: progressWidth,
- progress,
- progressBarBackgroundColor: "#ddd",
- })}
+
+ ${name}
+ ${progress}%
+ ${createProgressNode({
+ x: 0,
+ y: 25,
+ color,
+ width: progressWidth,
+ progress,
+ progressBarBackgroundColor: "#ddd",
+ delay: staggerDelay + 300,
+ })}
+
`;
};
/**
* Creates a text only node to display usage of a programming language in percentage.
*
- * @param {object[]} props Function properties.
+ * @param {object} props Function properties.
* @param {Lang} props.lang Programming language object.
* @param {number} props.totalSize Total size of all languages.
+ * @param {number} props.index Index of the programming language.
* @returns {string} Compact layout programming language SVG node.
*/
-const createCompactLangNode = ({ lang, totalSize }) => {
+const createCompactLangNode = ({ lang, totalSize, index }) => {
const percentage = ((lang.size / totalSize) * 100).toFixed(2);
+ const staggerDelay = (index + 3) * 150;
const color = lang.color || "#858585";
return `
-
+
${lang.name} ${percentage}%
@@ -104,7 +111,6 @@ const createLanguageTextNode = ({ langs, totalSize }) => {
createCompactLangNode({
lang,
totalSize,
- // @ts-ignore
index,
}),
);
@@ -134,12 +140,13 @@ const createLanguageTextNode = ({ langs, totalSize }) => {
*/
const renderNormalLayout = (langs, width, totalLanguageSize) => {
return flexLayout({
- items: langs.map((lang) => {
+ items: langs.map((lang, index) => {
return createProgressTextNode({
- width: width,
+ width,
name: lang.name,
color: lang.color || DEFAULT_LANG_COLOR,
progress: ((lang.size / totalLanguageSize) * 100).toFixed(2),
+ index,
});
}),
gap: 40,
@@ -187,7 +194,7 @@ const renderCompactLayout = (langs, width, totalLanguageSize) => {
return `
-
+
${compactProgressBar}
@@ -276,6 +283,7 @@ const renderTopLanguages = (topLangs, options = {}) => {
langs_count = DEFAULT_LANGS_COUNT,
border_radius,
border_color,
+ disable_animations,
} = options;
const i18n = new I18n({
@@ -324,11 +332,43 @@ const renderTopLanguages = (topLangs, options = {}) => {
colors,
});
- card.disableAnimations();
+ if (disable_animations) card.disableAnimations();
+
card.setHideBorder(hide_border);
card.setHideTitle(hide_title);
card.setCSS(
- `.lang-name { font: 400 11px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${colors.textColor} }`,
+ `
+ @keyframes slideInAnimation {
+ from {
+ width: 0;
+ }
+ to {
+ width: calc(100%-100px);
+ }
+ }
+ @keyframes growWidthAnimation {
+ from {
+ width: 0;
+ }
+ to {
+ width: 100%;
+ }
+ }
+ .lang-name {
+ font: 400 11px "Segoe UI", Ubuntu, Sans-Serif;
+ fill: ${colors.textColor};
+ }
+ .stagger {
+ opacity: 0;
+ animation: fadeInAnimation 0.3s ease-in-out forwards;
+ }
+ #rect-mask rect{
+ animation: slideInAnimation 1s ease-in-out forwards;
+ }
+ .lang-progress{
+ animation: growWidthAnimation 0.6s ease-in-out forwards;
+ }
+ `,
);
return card.render(`
diff --git a/src/cards/types.d.ts b/src/cards/types.d.ts
index 502314c41fa92..c5945d48be71e 100644
--- a/src/cards/types.d.ts
+++ b/src/cards/types.d.ts
@@ -37,6 +37,7 @@ export type TopLangOptions = CommonOptions & {
layout: "compact" | "normal";
custom_title: string;
langs_count: number;
+ disable_animations: boolean;
};
type WakaTimeOptions = CommonOptions & {
diff --git a/src/common/createProgressNode.js b/src/common/createProgressNode.js
index c36818b193b2f..2825583c7406a 100644
--- a/src/common/createProgressNode.js
+++ b/src/common/createProgressNode.js
@@ -10,6 +10,7 @@ import { clampValue } from "./utils.js";
* @param {string} createProgressNodeParams.color Progress color.
* @param {string} createProgressNodeParams.progress Progress value.
* @param {string} createProgressNodeParams.progressBarBackgroundColor Progress bar bg color.
+ * @param {number} createProgressNodeParams.delay Delay before animation starts.
* @returns {string} Progress node.
*/
const createProgressNode = ({
@@ -19,20 +20,22 @@ const createProgressNode = ({
color,
progress,
progressBarBackgroundColor,
+ delay,
}) => {
const progressPercentage = clampValue(progress, 2, 100);
return `
-
-
+
+
+
`;
};
From 8bc69e761ff7c922f47e6561d7a2f4fd0cc153c7 Mon Sep 17 00:00:00 2001
From: Zohan Subhash
Date: Thu, 19 Jan 2023 14:00:46 +0530
Subject: [PATCH 099/157] Update readme.md (#2442)
---
readme.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/readme.md b/readme.md
index 716bda22758c6..281c4877f9422 100644
--- a/readme.md
+++ b/readme.md
@@ -259,7 +259,7 @@ You can customize the appearance of your `Stats Card` or `Repo Card` however you
- `bg_color` - Card's background color _(hex color)_ **or** a gradient in the form of _angle,start,end_. Default: `fffefe`
- `hide_border` - Hides the card's border _(boolean)_. Default: `false`
- `theme` - name of the theme, choose from [all available themes](./themes/README.md). Default: `default` theme.
-- `cache_seconds` - set the cache header manually _(min: 7200, max: 86400)_. Default: `14400 seconds (4 hours)`.
+- `cache_seconds` - set the cache header manually _(min: 14400, max: 86400)_. Default: `14400 seconds (4 hours)`.
- `locale` - set the language in the card _(e.g. cn, de, es, etc.)_. Default: `en`.
- `border_radius` - Corner rounding on the card. Default: `4.5`.
From d5d1f44e1ccd8f36fc709cae2b42dd0b91f90b07 Mon Sep 17 00:00:00 2001
From: rickstaa
Date: Sat, 21 Jan 2023 11:30:50 +0100
Subject: [PATCH 100/157] test: fix e2e tests
---
tests/e2e/e2e.test.js | 43 +++++++++++++++++++------------------------
1 file changed, 19 insertions(+), 24 deletions(-)
diff --git a/tests/e2e/e2e.test.js b/tests/e2e/e2e.test.js
index 48bf16a0e083a..38b707f8239e9 100644
--- a/tests/e2e/e2e.test.js
+++ b/tests/e2e/e2e.test.js
@@ -11,27 +11,22 @@ import { renderStatsCard } from "../../src/cards/stats-card.js";
import { renderTopLanguages } from "../../src/cards/top-languages-card.js";
import { renderWakatimeCard } from "../../src/cards/wakatime-card.js";
-const REPO = "dummy-cra";
-const USER = "grsdummy";
+const REPO = "cra-test";
+const USER = "catelinemnemosyne";
const STATS_DATA = {
- name: "grsdummy",
- totalPRs: 2,
- totalCommits: 2,
+ name: "Cateline Mnemosyne",
+ totalPRs: 1,
+ totalCommits: 7,
totalIssues: 1,
totalStars: 1,
- contributedTo: 2,
+ contributedTo: 1,
rank: {
level: "A+",
- score: 50.900829325065935,
+ score: 50.893750297869225,
},
};
const LANGS_DATA = {
- TypeScript: {
- color: "#3178c6",
- name: "TypeScript",
- size: 2049,
- },
HTML: {
color: "#e34c26",
name: "HTML",
@@ -42,19 +37,19 @@ const LANGS_DATA = {
name: "CSS",
size: 930,
},
- Python: {
+ JavaScript: {
color: "#3572A5",
- name: "Python",
- size: 671,
+ name: "JavaScript",
+ size: 1912,
},
};
const WAKATIME_DATA = {
human_readable_range: "last week",
is_already_updating: false,
- is_coding_activity_visible: false,
+ is_coding_activity_visible: true,
is_including_today: false,
- is_other_usage_visible: false,
+ is_other_usage_visible: true,
is_stuck: false,
is_up_to_date: false,
is_up_to_date_pending_future: false,
@@ -62,24 +57,24 @@ const WAKATIME_DATA = {
range: "last_7_days",
status: "pending_update",
timeout: 15,
- username: "grsdummy",
+ username: USER,
writes_only: false,
};
const REPOSITORY_DATA = {
- name: "dummy-cra",
- nameWithOwner: "grsdummy/dummy-cra",
+ name: "cra-test",
+ nameWithOwner: `${USER}/cra-test`,
isPrivate: false,
isArchived: false,
isTemplate: false,
stargazers: {
totalCount: 1,
},
- description: "Dummy create react app.",
+ description: "Simple cra test repo.",
primaryLanguage: {
- color: "#3178c6",
- id: "MDg6TGFuZ3VhZ2UyODc=",
- name: "TypeScript",
+ color: "#f1e05a",
+ id: "MDg6TGFuZ3VhZ2UxNDA=",
+ name: "JavaScript",
},
forkCount: 0,
starCount: 1,
From cfa84232e2cec0ddaed4a54699cfb8a7311e528e Mon Sep 17 00:00:00 2001
From: rickstaa
Date: Sat, 21 Jan 2023 11:32:25 +0100
Subject: [PATCH 101/157] test: update snapshots
---
tests/renderStatsCard.test.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/renderStatsCard.test.js b/tests/renderStatsCard.test.js
index e39e45b7870e3..5afb1f0218e5d 100644
--- a/tests/renderStatsCard.test.js
+++ b/tests/renderStatsCard.test.js
@@ -329,7 +329,7 @@ describe("Test renderStatsCard", () => {
document.querySelector(
'g[transform="translate(0, 25)"]>.stagger>.stat.bold',
).textContent,
- ).toMatchInlineSnapshot(`"累计提交数(commit) (2022):"`);
+ ).toMatchInlineSnapshot(`"累计提交数(commit) (2023):"`);
expect(
document.querySelector(
'g[transform="translate(0, 50)"]>.stagger>.stat.bold',
From eab140241718725c5de32aeac5f6e8d14c31fbd0 Mon Sep 17 00:00:00 2001
From: rickstaa
Date: Sat, 21 Jan 2023 11:37:41 +0100
Subject: [PATCH 102/157] test: fix e2e test data
---
tests/e2e/e2e.test.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/e2e/e2e.test.js b/tests/e2e/e2e.test.js
index 38b707f8239e9..999d2c96d6578 100644
--- a/tests/e2e/e2e.test.js
+++ b/tests/e2e/e2e.test.js
@@ -38,7 +38,7 @@ const LANGS_DATA = {
size: 930,
},
JavaScript: {
- color: "#3572A5",
+ color: "#f1e05a",
name: "JavaScript",
size: 1912,
},
From fbb49e3c80f2c4f84fd86834514bcf9638a011a7 Mon Sep 17 00:00:00 2001
From: rickstaa
Date: Sat, 21 Jan 2023 12:15:58 +0100
Subject: [PATCH 103/157] test: update e2e test data
---
tests/e2e/e2e.test.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/e2e/e2e.test.js b/tests/e2e/e2e.test.js
index 999d2c96d6578..4d00646d02f67 100644
--- a/tests/e2e/e2e.test.js
+++ b/tests/e2e/e2e.test.js
@@ -11,7 +11,7 @@ import { renderStatsCard } from "../../src/cards/stats-card.js";
import { renderTopLanguages } from "../../src/cards/top-languages-card.js";
import { renderWakatimeCard } from "../../src/cards/wakatime-card.js";
-const REPO = "cra-test";
+const REPO = "curly-fiesta";
const USER = "catelinemnemosyne";
const STATS_DATA = {
name: "Cateline Mnemosyne",
From 4ff2c2a425dbeccde302e27042d3aa698bc8609c Mon Sep 17 00:00:00 2001
From: rickstaa
Date: Sat, 21 Jan 2023 17:52:51 +0100
Subject: [PATCH 104/157] feat: fix e2e tests
---
tests/e2e/e2e.test.js | 45 +++++++++++++++++++------------------------
1 file changed, 20 insertions(+), 25 deletions(-)
diff --git a/tests/e2e/e2e.test.js b/tests/e2e/e2e.test.js
index 48bf16a0e083a..4d00646d02f67 100644
--- a/tests/e2e/e2e.test.js
+++ b/tests/e2e/e2e.test.js
@@ -11,27 +11,22 @@ import { renderStatsCard } from "../../src/cards/stats-card.js";
import { renderTopLanguages } from "../../src/cards/top-languages-card.js";
import { renderWakatimeCard } from "../../src/cards/wakatime-card.js";
-const REPO = "dummy-cra";
-const USER = "grsdummy";
+const REPO = "curly-fiesta";
+const USER = "catelinemnemosyne";
const STATS_DATA = {
- name: "grsdummy",
- totalPRs: 2,
- totalCommits: 2,
+ name: "Cateline Mnemosyne",
+ totalPRs: 1,
+ totalCommits: 7,
totalIssues: 1,
totalStars: 1,
- contributedTo: 2,
+ contributedTo: 1,
rank: {
level: "A+",
- score: 50.900829325065935,
+ score: 50.893750297869225,
},
};
const LANGS_DATA = {
- TypeScript: {
- color: "#3178c6",
- name: "TypeScript",
- size: 2049,
- },
HTML: {
color: "#e34c26",
name: "HTML",
@@ -42,19 +37,19 @@ const LANGS_DATA = {
name: "CSS",
size: 930,
},
- Python: {
- color: "#3572A5",
- name: "Python",
- size: 671,
+ JavaScript: {
+ color: "#f1e05a",
+ name: "JavaScript",
+ size: 1912,
},
};
const WAKATIME_DATA = {
human_readable_range: "last week",
is_already_updating: false,
- is_coding_activity_visible: false,
+ is_coding_activity_visible: true,
is_including_today: false,
- is_other_usage_visible: false,
+ is_other_usage_visible: true,
is_stuck: false,
is_up_to_date: false,
is_up_to_date_pending_future: false,
@@ -62,24 +57,24 @@ const WAKATIME_DATA = {
range: "last_7_days",
status: "pending_update",
timeout: 15,
- username: "grsdummy",
+ username: USER,
writes_only: false,
};
const REPOSITORY_DATA = {
- name: "dummy-cra",
- nameWithOwner: "grsdummy/dummy-cra",
+ name: "cra-test",
+ nameWithOwner: `${USER}/cra-test`,
isPrivate: false,
isArchived: false,
isTemplate: false,
stargazers: {
totalCount: 1,
},
- description: "Dummy create react app.",
+ description: "Simple cra test repo.",
primaryLanguage: {
- color: "#3178c6",
- id: "MDg6TGFuZ3VhZ2UyODc=",
- name: "TypeScript",
+ color: "#f1e05a",
+ id: "MDg6TGFuZ3VhZ2UxNDA=",
+ name: "JavaScript",
},
forkCount: 0,
starCount: 1,
From c1dc7b850c3ff0a5db4a60564a4eaf8b9fbcdbda Mon Sep 17 00:00:00 2001
From: rickstaa
Date: Sat, 21 Jan 2023 17:58:35 +0100
Subject: [PATCH 105/157] fix: fix e2e test data
---
tests/e2e/e2e.test.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/e2e/e2e.test.js b/tests/e2e/e2e.test.js
index 4d00646d02f67..402e210fcee17 100644
--- a/tests/e2e/e2e.test.js
+++ b/tests/e2e/e2e.test.js
@@ -62,7 +62,7 @@ const WAKATIME_DATA = {
};
const REPOSITORY_DATA = {
- name: "cra-test",
+ name: REPO,
nameWithOwner: `${USER}/cra-test`,
isPrivate: false,
isArchived: false,
From 60fae292a349cd3d92942dc56bf67778c213cb0d Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Sat, 21 Jan 2023 18:32:37 +0100
Subject: [PATCH 106/157] feat: enable multi page star fetching for private
vercel instances (#2159)
* feat: enable multi-page stars' fetching for private vercel instances
This commit enables multi-page stars' support from fetching on private Vercel
instances. This feature can be disabled on the public Vercel instance by adding
the `FETCH_SINGLE_PAGE_STARS=true` as an env variable in the public Vercel
instance. This variable will not be present when people deploy their own Vercel
instance, causing the code to fetch multiple star pages.
* fix: improve stats multi-page fetching behavoir
This commit makes sure that the GraphQL api is only called one time per
100 repositories. The old method added one unnecesairy GraphQL call.
* docs: update documentation
* style: improve code syntax
Co-authored-by: Matteo Pierro
* lol happy new year
* docs: remove rate limit documentation for now
Remove the `FETCH_SINGLE_PAGE_STARS` from documentation for now since it
might confuse people.
* fix: fix error in automatic merge
* feat: make sure env variable is read
Co-authored-by: Matteo Pierro
Co-authored-by: Anurag
---
readme.md | 8 +-
src/fetchers/stats-fetcher.js | 207 +++++++++++++++++-----------------
tests/api.test.js | 35 ++----
tests/fetchStats.test.js | 126 +++++++++++++++------
4 files changed, 210 insertions(+), 166 deletions(-)
diff --git a/readme.md b/readme.md
index 281c4877f9422..678c5c0b14af4 100644
--- a/readme.md
+++ b/readme.md
@@ -93,7 +93,7 @@ Visit and make a small donation to hel
- [Language Card Exclusive Options](#language-card-exclusive-options)
- [Wakatime Card Exclusive Option](#wakatime-card-exclusive-options)
- [Deploy Yourself](#deploy-on-your-own-vercel-instance)
- - [Keep your fork up to date](#keep-your-fork-up-to-date)
+ - [Keep your fork up to date](#keep-your-fork-up-to-date)
# GitHub Stats Card
@@ -264,7 +264,7 @@ You can customize the appearance of your `Stats Card` or `Repo Card` however you
- `border_radius` - Corner rounding on the card. Default: `4.5`.
> **Warning**
-> We use caching to decrease the load on our servers (see https://github.com/anuraghazra/github-readme-stats/issues/1471#issuecomment-1271551425). Our cards have a default cache of 4 hours (14400 seconds). Also, note that the cache is clamped to a minimum of 4 hours and a maximum of 24 hours.
+> We use caching to decrease the load on our servers (see ). Our cards have a default cache of 4 hours (14400 seconds). Also, note that the cache is clamped to a minimum of 4 hours and a maximum of 24 hours.
##### Gradient in bg_color
@@ -354,7 +354,7 @@ Use [show_owner](#customization) variable to include the repo's owner username
The top languages card shows a GitHub user's most frequently used top language.
> **Note**
-> Top Languages does not indicate my skill level or anything like that; it's a GitHub metric to determine which languages have the most code on GitHub. It is a new feature of github-readme-stats._
+> Top Languages does not indicate my skill level or anything like that; it's a GitHub metric to determine which languages have the most code on GitHub. It is a new feature of github-readme-stats.
### Usage
@@ -498,7 +498,7 @@ By default, GitHub does not lay out the cards side by side. To do that, you can
## Deploy on your own Vercel instance
-#### [Check Out Step By Step Video Tutorial By @codeSTACKr](https://youtu.be/n6d4KHSKqGk?t=107)
+#### :film_projector: [Check Out Step By Step Video Tutorial By @codeSTACKr](https://youtu.be/n6d4KHSKqGk?t=107)
> **Warning**
> If you are on the [hobby (i.e. free)](https://vercel.com/pricing) Vercel plan, please make sure you change the `maxDuration` parameter in the [vercel.json](https://github.com/anuraghazra/github-readme-stats/blob/master/vercel.json) file from `30` to `10` (see [#1416](https://github.com/anuraghazra/github-readme-stats/issues/1416#issuecomment-950275476) for more information).
diff --git a/src/fetchers/stats-fetcher.js b/src/fetchers/stats-fetcher.js
index 7f6cb9e5e95b4..a7df1e504db2f 100644
--- a/src/fetchers/stats-fetcher.js
+++ b/src/fetchers/stats-fetcher.js
@@ -1,5 +1,6 @@
// @ts-check
import axios from "axios";
+import * as dotenv from "dotenv";
import githubUsernameRegex from "github-username-regex";
import { calculateRank } from "../calculateRank.js";
import { retryer } from "../common/retryer.js";
@@ -11,46 +12,74 @@ import {
wrapTextMultiline,
} from "../common/utils.js";
+dotenv.config();
+
+// GraphQL queries.
+const GRAPHQL_REPOS_FIELD = `
+ repositories(first: 100, ownerAffiliations: OWNER, orderBy: {direction: DESC, field: STARGAZERS}, after: $after) {
+ totalCount
+ nodes {
+ name
+ stargazers {
+ totalCount
+ }
+ }
+ pageInfo {
+ hasNextPage
+ endCursor
+ }
+ }
+`;
+
+const GRAPHQL_REPOS_QUERY = `
+ query userInfo($login: String!, $after: String) {
+ user(login: $login) {
+ ${GRAPHQL_REPOS_FIELD}
+ }
+ }
+`;
+
+const GRAPHQL_STATS_QUERY = `
+ query userInfo($login: String!, $after: String) {
+ user(login: $login) {
+ name
+ login
+ contributionsCollection {
+ totalCommitContributions
+ restrictedContributionsCount
+ }
+ repositoriesContributedTo(first: 1, contributionTypes: [COMMIT, ISSUE, PULL_REQUEST, REPOSITORY]) {
+ totalCount
+ }
+ pullRequests(first: 1) {
+ totalCount
+ }
+ openIssues: issues(states: OPEN) {
+ totalCount
+ }
+ closedIssues: issues(states: CLOSED) {
+ totalCount
+ }
+ followers {
+ totalCount
+ }
+ ${GRAPHQL_REPOS_FIELD}
+ }
+ }
+`;
+
/**
* Stats fetcher object.
*
* @param {import('axios').AxiosRequestHeaders} variables Fetcher variables.
* @param {string} token GitHub token.
- * @returns {Promise} Stats fetcher response.
+ * @returns {Promise} Stats fetcher response.
*/
const fetcher = (variables, token) => {
+ const query = !variables.after ? GRAPHQL_STATS_QUERY : GRAPHQL_REPOS_QUERY;
return request(
{
- query: `
- query userInfo($login: String!) {
- user(login: $login) {
- name
- login
- contributionsCollection {
- totalCommitContributions
- restrictedContributionsCount
- }
- repositoriesContributedTo(contributionTypes: [COMMIT, ISSUE, PULL_REQUEST, REPOSITORY]) {
- totalCount
- }
- pullRequests {
- totalCount
- }
- openIssues: issues(states: OPEN) {
- totalCount
- }
- closedIssues: issues(states: CLOSED) {
- totalCount
- }
- followers {
- totalCount
- }
- repositories(ownerAffiliations: OWNER) {
- totalCount
- }
- }
- }
- `,
+ query,
variables,
},
{
@@ -60,39 +89,42 @@ const fetcher = (variables, token) => {
};
/**
- * Fetch first 100 repositories for a given username.
+ * Fetch stats information for a given username.
*
- * @param {import('axios').AxiosRequestHeaders} variables Fetcher variables.
- * @param {string} token GitHub token.
- * @returns {Promise} Repositories fetcher response.
+ * @param {string} username Github username.
+ * @returns {Promise} GraphQL Stats object.
+ *
+ * @description This function supports multi-page fetching if the 'FETCH_MULTI_PAGE_STARS' environment variable is set to true.
*/
-const repositoriesFetcher = (variables, token) => {
- return request(
- {
- query: `
- query userInfo($login: String!, $after: String) {
- user(login: $login) {
- repositories(first: 100, ownerAffiliations: OWNER, orderBy: {direction: DESC, field: STARGAZERS}, after: $after) {
- nodes {
- name
- stargazers {
- totalCount
- }
- }
- pageInfo {
- hasNextPage
- endCursor
- }
- }
- }
- }
- `,
- variables,
- },
- {
- Authorization: `bearer ${token}`,
- },
- );
+const statsFetcher = async (username) => {
+ let stats;
+ let hasNextPage = true;
+ let endCursor = null;
+ while (hasNextPage) {
+ const variables = { login: username, first: 100, after: endCursor };
+ let res = await retryer(fetcher, variables);
+ if (res.data.errors) return res;
+
+ // Store stats data.
+ const repoNodes = res.data.data.user.repositories.nodes;
+ if (!stats) {
+ stats = res;
+ } else {
+ stats.data.data.user.repositories.nodes.push(...repoNodes);
+ }
+
+ // Disable multi page fetching on public Vercel instance due to rate limits.
+ const repoNodesWithStars = repoNodes.filter(
+ (node) => node.stargazers.totalCount !== 0,
+ );
+ hasNextPage =
+ process.env.FETCH_MULTI_PAGE_STARS === "true" &&
+ repoNodes.length === repoNodesWithStars.length &&
+ res.data.data.user.repositories.pageInfo.hasNextPage;
+ endCursor = res.data.data.user.repositories.pageInfo.endCursor;
+ }
+
+ return stats;
};
/**
@@ -137,46 +169,6 @@ const totalCommitsFetcher = async (username) => {
return 0;
};
-/**
- * Fetch all the stars for all the repositories of a given username.
- *
- * @param {string} username GitHub username.
- * @param {array} repoToHide Repositories to hide.
- * @returns {Promise} Total stars.
- */
-const totalStarsFetcher = async (username, repoToHide) => {
- let nodes = [];
- let hasNextPage = true;
- let endCursor = null;
- while (hasNextPage) {
- const variables = { login: username, first: 100, after: endCursor };
- let res = await retryer(repositoriesFetcher, variables);
-
- if (res.data.errors) {
- logger.error(res.data.errors);
- throw new CustomError(
- res.data.errors[0].message || "Could not fetch user",
- CustomError.USER_NOT_FOUND,
- );
- }
-
- const allNodes = res.data.data.user.repositories.nodes;
- const nodesWithStars = allNodes.filter(
- (node) => node.stargazers.totalCount !== 0,
- );
- nodes.push(...nodesWithStars);
- // hasNextPage =
- // allNodes.length === nodesWithStars.length &&
- // res.data.data.user.repositories.pageInfo.hasNextPage;
- hasNextPage = false; // NOTE: Temporarily disable fetching of multiple pages. Done because of #2130.
- endCursor = res.data.data.user.repositories.pageInfo.endCursor;
- }
-
- return nodes
- .filter((data) => !repoToHide[data.name])
- .reduce((prev, curr) => prev + curr.stargazers.totalCount, 0);
-};
-
/**
* Fetch stats for a given username.
*
@@ -203,7 +195,7 @@ const fetchStats = async (
rank: { level: "C", score: 0 },
};
- let res = await retryer(fetcher, { login: username });
+ let res = await statsFetcher(username);
// Catch GraphQL errors.
if (res.data.errors) {
@@ -259,8 +251,15 @@ const fetchStats = async (
stats.contributedTo = user.repositoriesContributedTo.totalCount;
// Retrieve stars while filtering out repositories to be hidden
- stats.totalStars = await totalStarsFetcher(username, repoToHide);
+ stats.totalStars = user.repositories.nodes
+ .filter((data) => {
+ return !repoToHide[data.name];
+ })
+ .reduce((prev, curr) => {
+ return prev + curr.stargazers.totalCount;
+ }, 0);
+ // @ts-ignore // TODO: Fix this.
stats.rank = calculateRank({
totalCommits: stats.totalCommits,
totalRepos: user.repositories.totalCount,
diff --git a/tests/api.test.js b/tests/api.test.js
index 0037bcdb566b2..461f3e18abb6d 100644
--- a/tests/api.test.js
+++ b/tests/api.test.js
@@ -25,7 +25,7 @@ stats.rank = calculateRank({
issues: stats.totalIssues,
});
-const data = {
+const data_stats = {
data: {
user: {
name: stats.name,
@@ -40,15 +40,6 @@ const data = {
followers: { totalCount: 0 },
repositories: {
totalCount: 1,
- },
- },
- },
-};
-
-const repositoriesData = {
- data: {
- user: {
- repositories: {
nodes: [{ stargazers: { totalCount: 100 } }],
pageInfo: {
hasNextPage: false,
@@ -83,11 +74,7 @@ const faker = (query, data) => {
setHeader: jest.fn(),
send: jest.fn(),
};
- mock
- .onPost("https://api.github.com/graphql")
- .replyOnce(200, data)
- .onPost("https://api.github.com/graphql")
- .replyOnce(200, repositoriesData);
+ mock.onPost("https://api.github.com/graphql").replyOnce(200, data);
return { req, res };
};
@@ -98,7 +85,7 @@ afterEach(() => {
describe("Test /api/", () => {
it("should test the request", async () => {
- const { req, res } = faker({}, data);
+ const { req, res } = faker({}, data_stats);
await api(req, res);
@@ -133,7 +120,7 @@ describe("Test /api/", () => {
text_color: "fff",
bg_color: "fff",
},
- data,
+ data_stats,
);
await api(req, res);
@@ -154,7 +141,7 @@ describe("Test /api/", () => {
});
it("should have proper cache", async () => {
- const { req, res } = faker({}, data);
+ const { req, res } = faker({}, data_stats);
await api(req, res);
@@ -170,7 +157,7 @@ describe("Test /api/", () => {
});
it("should set proper cache", async () => {
- const { req, res } = faker({ cache_seconds: 15000 }, data);
+ const { req, res } = faker({ cache_seconds: 15000 }, data_stats);
await api(req, res);
expect(res.setHeader.mock.calls).toEqual([
@@ -196,7 +183,7 @@ describe("Test /api/", () => {
it("should set proper cache with clamped values", async () => {
{
- let { req, res } = faker({ cache_seconds: 200000 }, data);
+ let { req, res } = faker({ cache_seconds: 200000 }, data_stats);
await api(req, res);
expect(res.setHeader.mock.calls).toEqual([
@@ -212,7 +199,7 @@ describe("Test /api/", () => {
// note i'm using block scoped vars
{
- let { req, res } = faker({ cache_seconds: 0 }, data);
+ let { req, res } = faker({ cache_seconds: 0 }, data_stats);
await api(req, res);
expect(res.setHeader.mock.calls).toEqual([
@@ -227,7 +214,7 @@ describe("Test /api/", () => {
}
{
- let { req, res } = faker({ cache_seconds: -10000 }, data);
+ let { req, res } = faker({ cache_seconds: -10000 }, data_stats);
await api(req, res);
expect(res.setHeader.mock.calls).toEqual([
@@ -248,7 +235,7 @@ describe("Test /api/", () => {
username: "anuraghazra",
count_private: true,
},
- data,
+ data_stats,
);
await api(req, res);
@@ -288,7 +275,7 @@ describe("Test /api/", () => {
text_color: "fff",
bg_color: "fff",
},
- data,
+ data_stats,
);
await api(req, res);
diff --git a/tests/fetchStats.test.js b/tests/fetchStats.test.js
index 192146ea5fbe0..04e943a75b50a 100644
--- a/tests/fetchStats.test.js
+++ b/tests/fetchStats.test.js
@@ -4,7 +4,8 @@ import MockAdapter from "axios-mock-adapter";
import { calculateRank } from "../src/calculateRank.js";
import { fetchStats } from "../src/fetchers/stats-fetcher.js";
-const data = {
+// Test parameters.
+const data_stats = {
data: {
user: {
name: "Anurag Hazra",
@@ -19,15 +20,6 @@ const data = {
followers: { totalCount: 100 },
repositories: {
totalCount: 5,
- },
- },
- },
-};
-
-const firstRepositoriesData = {
- data: {
- user: {
- repositories: {
nodes: [
{ name: "test-repo-1", stargazers: { totalCount: 100 } },
{ name: "test-repo-2", stargazers: { totalCount: 100 } },
@@ -42,7 +34,7 @@ const firstRepositoriesData = {
},
};
-const secondRepositoriesData = {
+const data_repo = {
data: {
user: {
repositories: {
@@ -59,7 +51,7 @@ const secondRepositoriesData = {
},
};
-const repositoriesWithZeroStarsData = {
+const data_repo_zero_stars = {
data: {
user: {
repositories: {
@@ -93,13 +85,12 @@ const error = {
const mock = new MockAdapter(axios);
beforeEach(() => {
+ process.env.FETCH_MULTI_PAGE_STARS = "false"; // Set to `false` to fetch only one page of stars.
mock
.onPost("https://api.github.com/graphql")
- .replyOnce(200, data)
+ .replyOnce(200, data_stats)
.onPost("https://api.github.com/graphql")
- .replyOnce(200, firstRepositoriesData);
- // .onPost("https://api.github.com/graphql") // NOTE: Temporarily disable fetching of multiple pages. Done because of #2130.
- // .replyOnce(200, secondRepositoriesData); // NOTE: Temporarily disable fetching of multiple pages. Done because of #2130.
+ .replyOnce(200, data_repo);
});
afterEach(() => {
@@ -114,8 +105,7 @@ describe("Test fetchStats", () => {
totalRepos: 5,
followers: 100,
contributions: 61,
- // stargazers: 400, // NOTE: Temporarily disable fetching of multiple pages. Done because of #2130.
- stargazers: 300, // NOTE: Temporarily disable fetching of multiple pages. Done because of #2130.
+ stargazers: 300,
prs: 300,
issues: 200,
});
@@ -126,8 +116,7 @@ describe("Test fetchStats", () => {
totalCommits: 100,
totalIssues: 200,
totalPRs: 300,
- // totalStars: 400, // NOTE: Temporarily disable fetching of multiple pages. Done because of #2130.
- totalStars: 300, // NOTE: Temporarily disable fetching of multiple pages. Done because of #2130.
+ totalStars: 300,
rank,
});
});
@@ -136,9 +125,9 @@ describe("Test fetchStats", () => {
mock.reset();
mock
.onPost("https://api.github.com/graphql")
- .replyOnce(200, data)
+ .replyOnce(200, data_stats)
.onPost("https://api.github.com/graphql")
- .replyOnce(200, repositoriesWithZeroStarsData);
+ .replyOnce(200, data_repo_zero_stars);
let stats = await fetchStats("anuraghazra");
const rank = calculateRank({
@@ -178,8 +167,7 @@ describe("Test fetchStats", () => {
totalRepos: 5,
followers: 100,
contributions: 61,
- // stargazers: 400, // NOTE: Temporarily disable fetching of multiple pages. Done because of #2130.
- stargazers: 300, // NOTE: Temporarily disable fetching of multiple pages. Done because of #2130.
+ stargazers: 300,
prs: 300,
issues: 200,
});
@@ -190,8 +178,7 @@ describe("Test fetchStats", () => {
totalCommits: 150,
totalIssues: 200,
totalPRs: 300,
- // totalStars: 400, // NOTE: Temporarily disable fetching of multiple pages. Done because of #2130.
- totalStars: 300, // NOTE: Temporarily disable fetching of multiple pages. Done because of #2130.
+ totalStars: 300,
rank,
});
});
@@ -207,8 +194,7 @@ describe("Test fetchStats", () => {
totalRepos: 5,
followers: 100,
contributions: 61,
- // stargazers: 400, // NOTE: Temporarily disable fetching of multiple pages. Done because of #2130.
- stargazers: 300, // NOTE: Temporarily disable fetching of multiple pages. Done because of #2130.
+ stargazers: 300,
prs: 300,
issues: 200,
});
@@ -219,8 +205,7 @@ describe("Test fetchStats", () => {
totalCommits: 1050,
totalIssues: 200,
totalPRs: 300,
- // totalStars: 400, // NOTE: Temporarily disable fetching of multiple pages. Done because of #2130.
- totalStars: 300, // NOTE: Temporarily disable fetching of multiple pages. Done because of #2130.
+ totalStars: 300,
rank,
});
});
@@ -236,8 +221,7 @@ describe("Test fetchStats", () => {
totalRepos: 5,
followers: 100,
contributions: 61,
- // stargazers: 300, // NOTE: Temporarily disable fetching of multiple pages. Done because of #2130.
- stargazers: 200, // NOTE: Temporarily disable fetching of multiple pages. Done because of #2130.
+ stargazers: 200,
prs: 300,
issues: 200,
});
@@ -248,8 +232,82 @@ describe("Test fetchStats", () => {
totalCommits: 1050,
totalIssues: 200,
totalPRs: 300,
- // totalStars: 300, // NOTE: Temporarily disable fetching of multiple pages. Done because of #2130.
- totalStars: 200, // NOTE: Temporarily disable fetching of multiple pages. Done because of #2130.
+ totalStars: 200,
+ rank,
+ });
+ });
+
+ it("should fetch two pages of stars if 'FETCH_MULTI_PAGE_STARS' env variable is set to `true`", async () => {
+ process.env.FETCH_MULTI_PAGE_STARS = true;
+
+ let stats = await fetchStats("anuraghazra");
+ const rank = calculateRank({
+ totalCommits: 100,
+ totalRepos: 5,
+ followers: 100,
+ contributions: 61,
+ stargazers: 400,
+ prs: 300,
+ issues: 200,
+ });
+
+ expect(stats).toStrictEqual({
+ contributedTo: 61,
+ name: "Anurag Hazra",
+ totalCommits: 100,
+ totalIssues: 200,
+ totalPRs: 300,
+ totalStars: 400,
+ rank,
+ });
+ });
+
+ it("should fetch one page of stars if 'FETCH_MULTI_PAGE_STARS' env variable is set to `false`", async () => {
+ process.env.FETCH_MULTI_PAGE_STARS = "false";
+
+ let stats = await fetchStats("anuraghazra");
+ const rank = calculateRank({
+ totalCommits: 100,
+ totalRepos: 5,
+ followers: 100,
+ contributions: 61,
+ stargazers: 300,
+ prs: 300,
+ issues: 200,
+ });
+
+ expect(stats).toStrictEqual({
+ contributedTo: 61,
+ name: "Anurag Hazra",
+ totalCommits: 100,
+ totalIssues: 200,
+ totalPRs: 300,
+ totalStars: 300,
+ rank,
+ });
+ });
+
+ it("should fetch one page of stars if 'FETCH_MULTI_PAGE_STARS' env variable is not set", async () => {
+ process.env.FETCH_MULTI_PAGE_STARS = undefined;
+
+ let stats = await fetchStats("anuraghazra");
+ const rank = calculateRank({
+ totalCommits: 100,
+ totalRepos: 5,
+ followers: 100,
+ contributions: 61,
+ stargazers: 300,
+ prs: 300,
+ issues: 200,
+ });
+
+ expect(stats).toStrictEqual({
+ contributedTo: 61,
+ name: "Anurag Hazra",
+ totalCommits: 100,
+ totalIssues: 200,
+ totalPRs: 300,
+ totalStars: 300,
rank,
});
});
From a17fa1cf5de746f54aadbfea0682a0c58beb4941 Mon Sep 17 00:00:00 2001
From: Anurag Hazra
Date: Sun, 22 Jan 2023 00:39:36 +0530
Subject: [PATCH 107/157] chore: resolve conflict (#2453)
* test: fix e2e tests
* test: update snapshots
* test: fix e2e test data
* test: update e2e test data
Co-authored-by: rickstaa
From b2bf4fa4878b585637a7f47d92cb10c62b4d1b06 Mon Sep 17 00:00:00 2001
From: Zohan Subhash
Date: Tue, 24 Jan 2023 20:04:26 +0530
Subject: [PATCH 108/157] fix: change prod deployment branch to vercel branch
to fix maxDuration bug (#2424)
* Create deploy-prep.yml
* Create deploy-prep.py
* Update vercel.json
* Update deploy-prep.yml
* Update vercel.json
* Added coauthor
Co-authored-by: Dou Xiaobo <93511091+douxiaobo@users.noreply.github.com>
* Update deploy-prep.yml
* refactor: format code
* Added if condition to disable deployments on forks
Co-authored-by: Rick Staa
* Update deploy-prep.yml
Co-authored-by: Dou Xiaobo <93511091+douxiaobo@users.noreply.github.com>
Co-authored-by: Anurag Hazra
Co-authored-by: rickstaa
---
.github/workflows/deploy-prep.py | 10 ++++++++++
.github/workflows/deploy-prep.yml | 20 ++++++++++++++++++++
vercel.json | 2 +-
3 files changed, 31 insertions(+), 1 deletion(-)
create mode 100644 .github/workflows/deploy-prep.py
create mode 100644 .github/workflows/deploy-prep.yml
diff --git a/.github/workflows/deploy-prep.py b/.github/workflows/deploy-prep.py
new file mode 100644
index 0000000000000..794c19a296122
--- /dev/null
+++ b/.github/workflows/deploy-prep.py
@@ -0,0 +1,10 @@
+import os
+
+file = open('./vercel.json', 'r')
+str = file.read()
+file = open('./vercel.json', 'w')
+
+str = str.replace('"maxDuration": 10', '"maxDuration": 30')
+
+file.write(str)
+file.close()
diff --git a/.github/workflows/deploy-prep.yml b/.github/workflows/deploy-prep.yml
new file mode 100644
index 0000000000000..0626e13d575a7
--- /dev/null
+++ b/.github/workflows/deploy-prep.yml
@@ -0,0 +1,20 @@
+name: Deployment Prep
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - master
+
+jobs:
+ config:
+ if: github.repository == 'anuraghazra/github-readme-stats'
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - name: Deployment Prep
+ run: python ./.github/workflows/deploy-prep.py
+ - uses: stefanzweifel/git-auto-commit-action@v4
+ with:
+ branch: vercel
+ create_branch: true
+ push_options: "--force"
diff --git a/vercel.json b/vercel.json
index aee61ce054fd0..ddf82eb15666f 100644
--- a/vercel.json
+++ b/vercel.json
@@ -2,7 +2,7 @@
"functions": {
"api/*.js": {
"memory": 128,
- "maxDuration": 30
+ "maxDuration": 10
}
},
"redirects": [
From cd5cbcdb095d766f5dbab2b8b13ed3b38cab7b2a Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Tue, 24 Jan 2023 15:40:11 +0100
Subject: [PATCH 109/157] fix: fixes card overflow problem #2452 (#2460)
This commit makes sure that the card width is formatted correctly.
---
src/cards/stats-card.js | 36 ++++++++++++++++++++++++-----------
tests/renderStatsCard.test.js | 20 +++++++++++--------
2 files changed, 37 insertions(+), 19 deletions(-)
diff --git a/src/cards/stats-card.js b/src/cards/stats-card.js
index a049ecce1c7e3..f39a968f18065 100644
--- a/src/cards/stats-card.js
+++ b/src/cards/stats-card.js
@@ -12,6 +12,11 @@ import {
import { getStyles } from "../getStyles.js";
import { statCardLocales } from "../translations.js";
+const CARD_MIN_WIDTH = 287;
+const CARD_DEFAULT_WIDTH = 287;
+const RANK_CARD_MIN_WIDTH = 420;
+const RANK_CARD_DEFAULT_WIDTH = 450;
+
/**
* Create a stats card text item.
*
@@ -218,11 +223,17 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
When hide_rank=false, the minimum card_width is 340 px + the icon width (if show_icons=true).
Numbers are picked by looking at existing dimensions on production.
*/
- const iconWidth = show_icons ? 16 : 0;
- const minCardWidth = hide_rank
- ? clampValue(50 /* padding */ + calculateTextWidth() * 2, 270, Infinity)
- : 340 + iconWidth;
- const defaultCardWidth = hide_rank ? 270 : 495;
+ const iconWidth = show_icons ? 16 + /* padding */ 1 : 0;
+ const minCardWidth =
+ (hide_rank
+ ? clampValue(
+ 50 /* padding */ + calculateTextWidth() * 2,
+ CARD_MIN_WIDTH,
+ Infinity,
+ )
+ : RANK_CARD_MIN_WIDTH) + iconWidth;
+ const defaultCardWidth =
+ (hide_rank ? CARD_DEFAULT_WIDTH : RANK_CARD_DEFAULT_WIDTH) + iconWidth;
let width = isNaN(card_width) ? defaultCardWidth : card_width;
if (width < minCardWidth) {
width = minCardWidth;
@@ -251,18 +262,21 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
/**
* Calculates the right rank circle translation values such that the rank circle
- * keeps respecting the padding.
+ * keeps respecting the following padding:
*
- * width > 450: The default left padding of 50 px will be used.
- * width < 450: The left and right padding will shrink equally.
+ * width > RANK_CARD_DEFAULT_WIDTH: The default right padding of 70 px will be used.
+ * width < RANK_CARD_DEFAULT_WIDTH: The left and right padding will be enlarged
+ * equally from a certain minimum at RANK_CARD_MIN_WIDTH.
*
* @returns {number} - Rank circle translation value.
*/
const calculateRankXTranslation = () => {
- if (width < 450) {
- return width - 95 + (45 * (450 - 340)) / 110;
+ const minXTranslation = RANK_CARD_MIN_WIDTH + iconWidth - 70;
+ if (width > RANK_CARD_DEFAULT_WIDTH) {
+ const xMaxExpansion = minXTranslation + (450 - minCardWidth) / 2;
+ return xMaxExpansion + width - RANK_CARD_DEFAULT_WIDTH;
} else {
- return width - 95;
+ return minXTranslation + (width - minCardWidth) / 2;
}
};
diff --git a/tests/renderStatsCard.test.js b/tests/renderStatsCard.test.js
index 5afb1f0218e5d..748b7a32cd32b 100644
--- a/tests/renderStatsCard.test.js
+++ b/tests/renderStatsCard.test.js
@@ -78,16 +78,17 @@ describe("Test renderStatsCard", () => {
it("should render with custom width set", () => {
document.body.innerHTML = renderStatsCard(stats);
- expect(document.querySelector("svg")).toHaveAttribute("width", "495");
+ expect(document.querySelector("svg")).toHaveAttribute("width", "450");
- document.body.innerHTML = renderStatsCard(stats, { card_width: 400 });
- expect(document.querySelector("svg")).toHaveAttribute("width", "400");
+ document.body.innerHTML = renderStatsCard(stats, { card_width: 500 });
+ expect(document.querySelector("svg")).toHaveAttribute("width", "500");
});
it("should render with custom width set and limit minimum width", () => {
document.body.innerHTML = renderStatsCard(stats, { card_width: 1 });
- expect(document.querySelector("svg")).toHaveAttribute("width", "340");
+ expect(document.querySelector("svg")).toHaveAttribute("width", "420");
+ // Test default minimum card width without rank circle.
document.body.innerHTML = renderStatsCard(stats, {
card_width: 1,
hide_rank: true,
@@ -97,6 +98,7 @@ describe("Test renderStatsCard", () => {
"305.81250000000006",
);
+ // Test minimum card width with rank and icons.
document.body.innerHTML = renderStatsCard(stats, {
card_width: 1,
hide_rank: true,
@@ -104,22 +106,24 @@ describe("Test renderStatsCard", () => {
});
expect(document.querySelector("svg")).toHaveAttribute(
"width",
- "305.81250000000006",
+ "322.81250000000006",
);
+ // Test minimum card width with icons but without rank.
document.body.innerHTML = renderStatsCard(stats, {
card_width: 1,
hide_rank: false,
show_icons: true,
});
- expect(document.querySelector("svg")).toHaveAttribute("width", "356");
+ expect(document.querySelector("svg")).toHaveAttribute("width", "437");
+ // Test minimum card width without icons or rank.
document.body.innerHTML = renderStatsCard(stats, {
card_width: 1,
hide_rank: false,
show_icons: false,
});
- expect(document.querySelector("svg")).toHaveAttribute("width", "340");
+ expect(document.querySelector("svg")).toHaveAttribute("width", "420");
});
it("should render default colors properly", () => {
@@ -312,7 +316,7 @@ describe("Test renderStatsCard", () => {
expect(
document.body.getElementsByTagName("svg")[0].getAttribute("width"),
- ).toBe("270");
+ ).toBe("287");
});
it("should render translations", () => {
From 99d9d3cde0e4f306704a9680738f79002328319c Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Wed, 25 Jan 2023 09:20:36 +0100
Subject: [PATCH 110/157] ci: prevent certain actions from running on forks
(#2466)
---
.github/workflows/e2e-test.yml | 1 +
.github/workflows/empty-issues-closer.yaml | 1 +
.github/workflows/label-pr.yml | 1 +
.github/workflows/stale-theme-pr-closer.yaml | 1 +
.github/workflows/top-issues-dashboard.yml | 1 +
5 files changed, 5 insertions(+)
diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml
index b9d275f5d5828..d45c76ba08e58 100644
--- a/.github/workflows/e2e-test.yml
+++ b/.github/workflows/e2e-test.yml
@@ -5,6 +5,7 @@ on:
jobs:
e2eTests:
if:
+ github.repository == 'anuraghazra/github-readme-stats' &&
github.event_name == 'deployment_status' &&
github.event.deployment_status.state == 'success'
name: Perform 2e2 tests
diff --git a/.github/workflows/empty-issues-closer.yaml b/.github/workflows/empty-issues-closer.yaml
index b20eef32fefb8..a65ea63b12dd3 100644
--- a/.github/workflows/empty-issues-closer.yaml
+++ b/.github/workflows/empty-issues-closer.yaml
@@ -8,6 +8,7 @@ on:
jobs:
closeEmptyIssuesAndTemplates:
+ if: github.repository == 'anuraghazra/github-readme-stats'
name: Close empty issues
runs-on: ubuntu-latest
steps:
diff --git a/.github/workflows/label-pr.yml b/.github/workflows/label-pr.yml
index c401d32ee4b9c..03715bfab00d6 100644
--- a/.github/workflows/label-pr.yml
+++ b/.github/workflows/label-pr.yml
@@ -4,6 +4,7 @@ on:
jobs:
triage:
+ if: github.repository == 'anuraghazra/github-readme-stats'
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v4
diff --git a/.github/workflows/stale-theme-pr-closer.yaml b/.github/workflows/stale-theme-pr-closer.yaml
index 9a6249825263e..aa104feb528ca 100644
--- a/.github/workflows/stale-theme-pr-closer.yaml
+++ b/.github/workflows/stale-theme-pr-closer.yaml
@@ -5,6 +5,7 @@ on:
jobs:
closeOldThemePrs:
+ if: github.repository == 'anuraghazra/github-readme-stats'
name: Close stale 'invalid' theme PRs
runs-on: ubuntu-latest
strategy:
diff --git a/.github/workflows/top-issues-dashboard.yml b/.github/workflows/top-issues-dashboard.yml
index 2b36e529de454..3a9ec82d35149 100644
--- a/.github/workflows/top-issues-dashboard.yml
+++ b/.github/workflows/top-issues-dashboard.yml
@@ -5,6 +5,7 @@ on:
jobs:
showAndLabelTopIssues:
+ if: github.repository == 'anuraghazra/github-readme-stats'
name: Update top issues Dashboard.
runs-on: ubuntu-latest
steps:
From 077d40561a4eb74ab56a81942155985a7579103a Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Sat, 28 Jan 2023 15:22:02 +0100
Subject: [PATCH 111/157] feat: add PAT monitoring functions (#2178)
* feat: add PAT monitoring functions
This commit adds two monitoring functions that can be used to check
whether the PATs are functioning correctly:
- status/up: Returns whether the PATs are rate limited.
- status/pat-info: Returns information about the PATs.
* feat: add shields.io dynamic badge json response
This commit adds the ability to set the return format of the
`/api/status/up` cloud function. When this format is set to `shields` a
dynamic shields.io badge json is returned.
* feat: add 'json' type to up monitor
* feat: cleanup status functions
* ci: decrease pat-info rate limiting time
* feat: decrease monitoring functions rate limits
* refactor: pat code
* feat: add PAT monitoring functions
This commit adds two monitoring functions that can be used to check
whether the PATs are functioning correctly:
- status/up: Returns whether the PATs are rate limited.
- status/pat-info: Returns information about the PATs.
* feat: add shields.io dynamic badge json response
This commit adds the ability to set the return format of the
`/api/status/up` cloud function. When this format is set to `shields` a
dynamic shields.io badge json is returned.
* feat: add 'json' type to up monitor
* feat: cleanup status functions
* ci: decrease pat-info rate limiting time
* feat: decrease monitoring functions rate limits
* refactor: pat code
* test: fix pat-info tests
* Update api/status/pat-info.js
Co-authored-by: Anurag Hazra
* test: fix broken tests
* chore: fix suspended account
* chore: simplify and refactor
* chore: fix test
* chore: add resetIn field
---------
Co-authored-by: Anurag
---
api/status/pat-info.js | 131 ++++++++++++++++++++++
api/status/up.js | 103 +++++++++++++++++
package-lock.json | 2 +-
package.json | 2 +-
src/common/utils.js | 14 +++
tests/pat-info.test.js | 241 ++++++++++++++++++++++++++++++++++++++++
tests/status.up.test.js | 194 ++++++++++++++++++++++++++++++++
7 files changed, 685 insertions(+), 2 deletions(-)
create mode 100644 api/status/pat-info.js
create mode 100644 api/status/up.js
create mode 100644 tests/pat-info.test.js
create mode 100644 tests/status.up.test.js
diff --git a/api/status/pat-info.js b/api/status/pat-info.js
new file mode 100644
index 0000000000000..720611d424919
--- /dev/null
+++ b/api/status/pat-info.js
@@ -0,0 +1,131 @@
+/**
+ * @file Contains a simple cloud function that can be used to check which PATs are no
+ * longer working. It returns a list of valid PATs, expired PATs and PATs with errors.
+ *
+ * @description This function is currently rate limited to 1 request per 10 minutes.
+ */
+
+import { logger, request, dateDiff } from "../../src/common/utils.js";
+export const RATE_LIMIT_SECONDS = 60 * 10; // 1 request per 10 minutes
+
+/**
+ * Simple uptime check fetcher for the PATs.
+ *
+ * @param {import('axios').AxiosRequestHeaders} variables
+ * @param {string} token
+ */
+const uptimeFetcher = (variables, token) => {
+ return request(
+ {
+ query: `
+ query {
+ rateLimit {
+ remaining
+ resetAt
+ },
+ }`,
+ variables,
+ },
+ {
+ Authorization: `bearer ${token}`,
+ },
+ );
+};
+
+const getAllPATs = () => {
+ return Object.keys(process.env).filter((key) => /PAT_\d*$/.exec(key));
+};
+
+/**
+ * Check whether any of the PATs is expired.
+ */
+const getPATInfo = async (fetcher, variables) => {
+ const details = {};
+ const PATs = getAllPATs();
+
+ for (const pat of PATs) {
+ try {
+ const response = await fetcher(variables, process.env[pat]);
+ const errors = response.data.errors;
+ const hasErrors = Boolean(errors);
+ const errorType = errors?.[0]?.type;
+ const isRateLimited =
+ (hasErrors && errorType === "RATE_LIMITED") ||
+ response.data.data?.rateLimit?.remaining === 0;
+
+ // Store PATs with errors.
+ if (hasErrors && errorType !== "RATE_LIMITED") {
+ details[pat] = {
+ status: "error",
+ error: {
+ type: errors[0].type,
+ message: errors[0].message,
+ },
+ };
+ continue;
+ } else if (isRateLimited) {
+ const date1 = new Date();
+ const date2 = new Date(response.data?.data?.rateLimit?.resetAt);
+ details[pat] = {
+ status: "exhausted",
+ remaining: 0,
+ resetIn: dateDiff(date2, date1) + " minutes",
+ };
+ } else {
+ details[pat] = {
+ status: "valid",
+ remaining: response.data.data.rateLimit.remaining,
+ };
+ }
+ } catch (err) {
+ // Store the PAT if it is expired.
+ const errorMessage = err.response?.data?.message?.toLowerCase();
+ if (errorMessage === "bad credentials") {
+ details[pat] = {
+ status: "expired",
+ };
+ } else if (errorMessage === "sorry. your account was suspended.") {
+ details[pat] = {
+ status: "suspended",
+ };
+ } else {
+ throw err;
+ }
+ }
+ }
+
+ const filterPATsByStatus = (status) => {
+ return Object.keys(details).filter((pat) => details[pat].status === status);
+ };
+
+ return {
+ validPATs: filterPATsByStatus("valid"),
+ expiredPATs: filterPATsByStatus("expired"),
+ exhaustedPATS: filterPATsByStatus("exhausted"),
+ errorPATs: filterPATsByStatus("error"),
+ details,
+ };
+};
+
+/**
+ * Cloud function that returns information about the used PATs.
+ */
+export default async (_, res) => {
+ res.setHeader("Content-Type", "application/json");
+ try {
+ // Add header to prevent abuse.
+ const PATsInfo = await getPATInfo(uptimeFetcher, {});
+ if (PATsInfo) {
+ res.setHeader(
+ "Cache-Control",
+ `max-age=0, s-maxage=${RATE_LIMIT_SECONDS}`,
+ );
+ }
+ res.send(JSON.stringify(PATsInfo, null, 2));
+ } catch (err) {
+ // Throw error if something went wrong.
+ logger.error(err);
+ res.setHeader("Cache-Control", "no-store");
+ res.send("Something went wrong: " + err.message);
+ }
+};
diff --git a/api/status/up.js b/api/status/up.js
new file mode 100644
index 0000000000000..33fe8f900c395
--- /dev/null
+++ b/api/status/up.js
@@ -0,0 +1,103 @@
+/**
+ * @file Contains a simple cloud function that can be used to check if the PATs are still
+ * functional.
+ *
+ * @description This function is currently rate limited to 1 request per 10 minutes.
+ */
+
+import retryer from "../../src/common/retryer.js";
+import { logger, request } from "../../src/common/utils.js";
+
+export const RATE_LIMIT_SECONDS = 60 * 10; // 1 request per 10 minutes
+
+/**
+ * Simple uptime check fetcher for the PATs.
+ *
+ * @param {import('axios').AxiosRequestHeaders} variables
+ * @param {string} token
+ */
+const uptimeFetcher = (variables, token) => {
+ return request(
+ {
+ query: `
+ query {
+ rateLimit {
+ remaining
+ }
+ }
+ `,
+ variables,
+ },
+ {
+ Authorization: `bearer ${token}`,
+ },
+ );
+};
+
+/**
+ * Creates Json response that can be used for shields.io dynamic card generation.
+ *
+ * @param {*} up Whether the PATs are up or not.
+ * @returns Dynamic shields.io JSON response object.
+ *
+ * @see https://shields.io/endpoint.
+ */
+const shieldsUptimeBadge = (up) => {
+ const schemaVersion = 1;
+ const isError = true;
+ const label = "Public Instance";
+ const message = up ? "up" : "down";
+ const color = up ? "brightgreen" : "red";
+ return {
+ schemaVersion,
+ label,
+ message,
+ color,
+ isError,
+ };
+};
+
+/**
+ * Cloud function that returns whether the PATs are still functional.
+ */
+export default async (req, res) => {
+ let { type } = req.query;
+ type = type ? type.toLowerCase() : "boolean";
+
+ res.setHeader("Content-Type", "application/json");
+
+ try {
+ let PATsValid = true;
+ try {
+ await retryer(uptimeFetcher, {});
+ } catch (err) {
+ PATsValid = false;
+ }
+
+ if (PATsValid) {
+ res.setHeader(
+ "Cache-Control",
+ `max-age=0, s-maxage=${RATE_LIMIT_SECONDS}`,
+ );
+ } else {
+ res.setHeader("Cache-Control", "no-store");
+ }
+
+ switch (type) {
+ case "shields":
+ res.send(shieldsUptimeBadge(PATsValid));
+ break;
+ case "json":
+ res.send({ up: PATsValid });
+ break;
+ default:
+ res.send(PATsValid);
+ break;
+ }
+ } catch (err) {
+ // Return fail boolean if something went wrong.
+ logger.error(err);
+ res.setHeader("Cache-Control", "no-store");
+ res.send("Something went wrong: " + err.message);
+ }
+};
diff --git a/package-lock.json b/package-lock.json
index 048c316bfde58..ebc7570a41923 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -22,7 +22,7 @@
"@testing-library/dom": "^8.17.1",
"@testing-library/jest-dom": "^5.16.5",
"@uppercod/css-to-object": "^1.1.1",
- "axios-mock-adapter": "^1.18.1",
+ "axios-mock-adapter": "^1.21.2",
"color-contrast-checker": "^2.1.0",
"hjson": "^3.2.2",
"husky": "^8.0.0",
diff --git a/package.json b/package.json
index 95b1a11dad93f..606d4f5440a24 100644
--- a/package.json
+++ b/package.json
@@ -39,7 +39,7 @@
"@testing-library/dom": "^8.17.1",
"@testing-library/jest-dom": "^5.16.5",
"@uppercod/css-to-object": "^1.1.1",
- "axios-mock-adapter": "^1.18.1",
+ "axios-mock-adapter": "^1.21.2",
"color-contrast-checker": "^2.1.0",
"hjson": "^3.2.2",
"husky": "^8.0.0",
diff --git a/src/common/utils.js b/src/common/utils.js
index 1215fc9ac8cc2..c600c717ae3e5 100644
--- a/src/common/utils.js
+++ b/src/common/utils.js
@@ -424,6 +424,19 @@ const parseEmojis = (str) => {
});
};
+/**
+ * Get diff in minutes
+ * @param {Date} d1
+ * @param {Date} d2
+ * @returns {number}
+ */
+const dateDiff = (d1, d2) => {
+ const date1 = new Date(d1);
+ const date2 = new Date(d2);
+ const diff = date1.getTime() - date2.getTime();
+ return Math.round(diff / (1000 * 60));
+};
+
export {
ERROR_CARD_LENGTH,
renderError,
@@ -447,4 +460,5 @@ export {
lowercaseTrim,
chunkArray,
parseEmojis,
+ dateDiff,
};
diff --git a/tests/pat-info.test.js b/tests/pat-info.test.js
new file mode 100644
index 0000000000000..9635ab24c837c
--- /dev/null
+++ b/tests/pat-info.test.js
@@ -0,0 +1,241 @@
+/**
+ * @file Tests for the status/pat-info cloud function.
+ */
+import dotenv from "dotenv";
+dotenv.config();
+
+import { jest } from "@jest/globals";
+import axios from "axios";
+import MockAdapter from "axios-mock-adapter";
+import patInfo, { RATE_LIMIT_SECONDS } from "../api/status/pat-info.js";
+
+const mock = new MockAdapter(axios);
+
+const successData = {
+ data: {
+ rateLimit: {
+ remaining: 4986,
+ },
+ },
+};
+
+const faker = (query) => {
+ const req = {
+ query: { ...query },
+ };
+ const res = {
+ setHeader: jest.fn(),
+ send: jest.fn(),
+ };
+
+ return { req, res };
+};
+
+const rate_limit_error = {
+ errors: [
+ {
+ type: "RATE_LIMITED",
+ message: "API rate limit exceeded for user ID.",
+ },
+ ],
+ data: {
+ rateLimit: {
+ resetAt: Date.now(),
+ },
+ },
+};
+
+const other_error = {
+ errors: [
+ {
+ type: "SOME_ERROR",
+ message: "This is a error",
+ },
+ ],
+};
+
+const bad_credentials_error = {
+ message: "Bad credentials",
+};
+
+afterEach(() => {
+ mock.reset();
+});
+
+describe("Test /api/status/pat-info", () => {
+ beforeAll(() => {
+ // reset patenv first so that dotenv doesn't populate them with local envs
+ process.env = {};
+ process.env.PAT_1 = "testPAT1";
+ process.env.PAT_2 = "testPAT2";
+ process.env.PAT_3 = "testPAT3";
+ process.env.PAT_4 = "testPAT4";
+ });
+
+ it("should return only 'validPATs' if all PATs are valid", async () => {
+ mock
+ .onPost("https://api.github.com/graphql")
+ .replyOnce(200, rate_limit_error)
+ .onPost("https://api.github.com/graphql")
+ .reply(200, successData);
+
+ const { req, res } = faker({}, {});
+ await patInfo(req, res);
+
+ expect(res.setHeader).toBeCalledWith("Content-Type", "application/json");
+ expect(res.send).toBeCalledWith(
+ JSON.stringify(
+ {
+ validPATs: ["PAT_2", "PAT_3", "PAT_4"],
+ expiredPATs: [],
+ exhaustedPATS: ["PAT_1"],
+ errorPATs: [],
+ details: {
+ PAT_1: {
+ status: "exhausted",
+ remaining: 0,
+ resetIn: "0 minutes",
+ },
+ PAT_2: {
+ status: "valid",
+ remaining: 4986,
+ },
+ PAT_3: {
+ status: "valid",
+ remaining: 4986,
+ },
+ PAT_4: {
+ status: "valid",
+ remaining: 4986,
+ },
+ },
+ },
+ null,
+ 2,
+ ),
+ );
+ });
+
+ it("should return `errorPATs` if a PAT causes an error to be thrown", async () => {
+ mock
+ .onPost("https://api.github.com/graphql")
+ .replyOnce(200, other_error)
+ .onPost("https://api.github.com/graphql")
+ .reply(200, successData);
+
+ const { req, res } = faker({}, {});
+ await patInfo(req, res);
+
+ expect(res.setHeader).toBeCalledWith("Content-Type", "application/json");
+ expect(res.send).toBeCalledWith(
+ JSON.stringify(
+ {
+ validPATs: ["PAT_2", "PAT_3", "PAT_4"],
+ expiredPATs: [],
+ exhaustedPATS: [],
+ errorPATs: ["PAT_1"],
+ details: {
+ PAT_1: {
+ status: "error",
+ error: {
+ type: "SOME_ERROR",
+ message: "This is a error",
+ },
+ },
+ PAT_2: {
+ status: "valid",
+ remaining: 4986,
+ },
+ PAT_3: {
+ status: "valid",
+ remaining: 4986,
+ },
+ PAT_4: {
+ status: "valid",
+ remaining: 4986,
+ },
+ },
+ },
+ null,
+ 2,
+ ),
+ );
+ });
+
+ it("should return `expiredPaths` if a PAT returns a 'Bad credentials' error", async () => {
+ mock
+ .onPost("https://api.github.com/graphql")
+ .replyOnce(404, bad_credentials_error)
+ .onPost("https://api.github.com/graphql")
+ .reply(200, successData);
+
+ const { req, res } = faker({}, {});
+ await patInfo(req, res);
+
+ expect(res.setHeader).toBeCalledWith("Content-Type", "application/json");
+ expect(res.send).toBeCalledWith(
+ JSON.stringify(
+ {
+ validPATs: ["PAT_2", "PAT_3", "PAT_4"],
+ expiredPATs: ["PAT_1"],
+ exhaustedPATS: [],
+ errorPATs: [],
+ details: {
+ PAT_1: {
+ status: "expired",
+ },
+ PAT_2: {
+ status: "valid",
+ remaining: 4986,
+ },
+ PAT_3: {
+ status: "valid",
+ remaining: 4986,
+ },
+ PAT_4: {
+ status: "valid",
+ remaining: 4986,
+ },
+ },
+ },
+ null,
+ 2,
+ ),
+ );
+ });
+
+ it("should throw an error if something goes wrong", async () => {
+ mock.onPost("https://api.github.com/graphql").networkError();
+
+ const { req, res } = faker({}, {});
+ await patInfo(req, res);
+
+ expect(res.setHeader).toBeCalledWith("Content-Type", "application/json");
+ expect(res.send).toBeCalledWith("Something went wrong: Network Error");
+ });
+
+ it("should have proper cache when no error is thrown", async () => {
+ mock.onPost("https://api.github.com/graphql").reply(200, successData);
+
+ const { req, res } = faker({}, {});
+ await patInfo(req, res);
+
+ expect(res.setHeader.mock.calls).toEqual([
+ ["Content-Type", "application/json"],
+ ["Cache-Control", `max-age=0, s-maxage=${RATE_LIMIT_SECONDS}`],
+ ]);
+ });
+
+ it("should have proper cache when error is thrown", async () => {
+ mock.reset();
+ mock.onPost("https://api.github.com/graphql").networkError();
+
+ const { req, res } = faker({}, {});
+ await patInfo(req, res);
+
+ expect(res.setHeader.mock.calls).toEqual([
+ ["Content-Type", "application/json"],
+ ["Cache-Control", "no-store"],
+ ]);
+ });
+});
diff --git a/tests/status.up.test.js b/tests/status.up.test.js
new file mode 100644
index 0000000000000..7cf0144b7112d
--- /dev/null
+++ b/tests/status.up.test.js
@@ -0,0 +1,194 @@
+/**
+ * @file Tests for the status/up cloud function.
+ */
+import { jest } from "@jest/globals";
+import axios from "axios";
+import MockAdapter from "axios-mock-adapter";
+import up, { RATE_LIMIT_SECONDS } from "../api/status/up.js";
+
+const mock = new MockAdapter(axios);
+
+const successData = {
+ rateLimit: {
+ remaining: 4986,
+ },
+};
+
+const faker = (query) => {
+ const req = {
+ query: { ...query },
+ };
+ const res = {
+ setHeader: jest.fn(),
+ send: jest.fn(),
+ };
+
+ return { req, res };
+};
+
+const rate_limit_error = {
+ errors: [
+ {
+ type: "RATE_LIMITED",
+ },
+ ],
+};
+
+const bad_credentials_error = {
+ message: "Bad credentials",
+};
+
+const shields_up = {
+ schemaVersion: 1,
+ label: "Public Instance",
+ isError: true,
+ message: "up",
+ color: "brightgreen",
+};
+const shields_down = {
+ schemaVersion: 1,
+ label: "Public Instance",
+ isError: true,
+ message: "down",
+ color: "red",
+};
+
+afterEach(() => {
+ mock.reset();
+});
+
+describe("Test /api/status/up", () => {
+ it("should return `true` if request was successful", async () => {
+ mock.onPost("https://api.github.com/graphql").replyOnce(200, successData);
+
+ const { req, res } = faker({}, {});
+ await up(req, res);
+
+ expect(res.setHeader).toBeCalledWith("Content-Type", "application/json");
+ expect(res.send).toBeCalledWith(true);
+ });
+
+ it("should return `false` if all PATs are rate limited", async () => {
+ mock.onPost("https://api.github.com/graphql").reply(200, rate_limit_error);
+
+ const { req, res } = faker({}, {});
+ await up(req, res);
+
+ expect(res.setHeader).toBeCalledWith("Content-Type", "application/json");
+ expect(res.send).toBeCalledWith(false);
+ });
+
+ it("should return JSON `true` if request was successful and type='json'", async () => {
+ mock.onPost("https://api.github.com/graphql").replyOnce(200, successData);
+
+ const { req, res } = faker({ type: "json" }, {});
+ await up(req, res);
+
+ expect(res.setHeader).toBeCalledWith("Content-Type", "application/json");
+ expect(res.send).toBeCalledWith({ up: true });
+ });
+
+ it("should return JSON `false` if all PATs are rate limited and type='json'", async () => {
+ mock.onPost("https://api.github.com/graphql").reply(200, rate_limit_error);
+
+ const { req, res } = faker({ type: "json" }, {});
+ await up(req, res);
+
+ expect(res.setHeader).toBeCalledWith("Content-Type", "application/json");
+ expect(res.send).toBeCalledWith({ up: false });
+ });
+
+ it("should return UP shields.io config if request was successful and type='shields'", async () => {
+ mock.onPost("https://api.github.com/graphql").replyOnce(200, successData);
+
+ const { req, res } = faker({ type: "shields" }, {});
+ await up(req, res);
+
+ expect(res.setHeader).toBeCalledWith("Content-Type", "application/json");
+ expect(res.send).toBeCalledWith(shields_up);
+ });
+
+ it("should return DOWN shields.io config if all PATs are rate limited and type='shields'", async () => {
+ mock.onPost("https://api.github.com/graphql").reply(200, rate_limit_error);
+
+ const { req, res } = faker({ type: "shields" }, {});
+ await up(req, res);
+
+ expect(res.setHeader).toBeCalledWith("Content-Type", "application/json");
+ expect(res.send).toBeCalledWith(shields_down);
+ });
+
+ it("should return `true` if the first PAT is rate limited but the second PATs works", async () => {
+ mock
+ .onPost("https://api.github.com/graphql")
+ .replyOnce(200, rate_limit_error)
+ .onPost("https://api.github.com/graphql")
+ .replyOnce(200, successData);
+
+ const { req, res } = faker({}, {});
+ await up(req, res);
+
+ expect(res.setHeader).toBeCalledWith("Content-Type", "application/json");
+ expect(res.send).toBeCalledWith(true);
+ });
+
+ it("should return `true` if the first PAT has 'Bad credentials' but the second PAT works", async () => {
+ mock
+ .onPost("https://api.github.com/graphql")
+ .replyOnce(404, bad_credentials_error)
+ .onPost("https://api.github.com/graphql")
+ .replyOnce(200, successData);
+
+ const { req, res } = faker({}, {});
+ await up(req, res);
+
+ expect(res.setHeader).toBeCalledWith("Content-Type", "application/json");
+ expect(res.send).toBeCalledWith(true);
+ });
+
+ it("should return `false` if all pats have 'Bad credentials'", async () => {
+ mock
+ .onPost("https://api.github.com/graphql")
+ .reply(404, bad_credentials_error);
+
+ const { req, res } = faker({}, {});
+ await up(req, res);
+
+ expect(res.setHeader).toBeCalledWith("Content-Type", "application/json");
+ expect(res.send).toBeCalledWith(false);
+ });
+
+ it("should throw an error if the request fails", async () => {
+ mock.onPost("https://api.github.com/graphql").networkError();
+
+ const { req, res } = faker({}, {});
+ await up(req, res);
+
+ expect(res.setHeader).toBeCalledWith("Content-Type", "application/json");
+ expect(res.send).toBeCalledWith(false);
+ });
+
+ it("should have proper cache when no error is thrown", async () => {
+ mock.onPost("https://api.github.com/graphql").replyOnce(200, successData);
+
+ const { req, res } = faker({}, {});
+ await up(req, res);
+
+ expect(res.setHeader.mock.calls).toEqual([
+ ["Content-Type", "application/json"],
+ ["Cache-Control", `max-age=0, s-maxage=${RATE_LIMIT_SECONDS}`],
+ ]);
+ });
+
+ it("should have proper cache when error is thrown", async () => {
+ mock.onPost("https://api.github.com/graphql").networkError();
+
+ const { req, res } = faker({}, {});
+ await up(req, res);
+
+ expect(res.setHeader.mock.calls).toEqual([
+ ["Content-Type", "application/json"],
+ ["Cache-Control", "no-store"],
+ ]);
+ });
+});
From 7aa502d45377c73f89c6d1096c29cd862188aa2e Mon Sep 17 00:00:00 2001
From: Anurag Hazra
Date: Sat, 28 Jan 2023 20:32:40 +0530
Subject: [PATCH 112/157] chore: minor changes in pat info (#2481)
---
api/status/pat-info.js | 14 +++++++++++---
tests/pat-info.test.js | 9 ++++++---
2 files changed, 17 insertions(+), 6 deletions(-)
diff --git a/api/status/pat-info.js b/api/status/pat-info.js
index 720611d424919..775e06896427c 100644
--- a/api/status/pat-info.js
+++ b/api/status/pat-info.js
@@ -6,7 +6,7 @@
*/
import { logger, request, dateDiff } from "../../src/common/utils.js";
-export const RATE_LIMIT_SECONDS = 60 * 10; // 1 request per 10 minutes
+export const RATE_LIMIT_SECONDS = 60 * 5; // 1 request per 10 minutes
/**
* Simple uptime check fetcher for the PATs.
@@ -98,12 +98,20 @@ const getPATInfo = async (fetcher, variables) => {
return Object.keys(details).filter((pat) => details[pat].status === status);
};
+ const sortedDetails = Object.keys(details)
+ .sort()
+ .reduce((obj, key) => {
+ obj[key] = details[key];
+ return obj;
+ }, {});
+
return {
validPATs: filterPATsByStatus("valid"),
expiredPATs: filterPATsByStatus("expired"),
- exhaustedPATS: filterPATsByStatus("exhausted"),
+ exhaustedPATs: filterPATsByStatus("exhausted"),
+ suspendedPATs: filterPATsByStatus("suspended"),
errorPATs: filterPATsByStatus("error"),
- details,
+ details: sortedDetails,
};
};
diff --git a/tests/pat-info.test.js b/tests/pat-info.test.js
index 9635ab24c837c..23aca8c40e5ca 100644
--- a/tests/pat-info.test.js
+++ b/tests/pat-info.test.js
@@ -88,7 +88,8 @@ describe("Test /api/status/pat-info", () => {
{
validPATs: ["PAT_2", "PAT_3", "PAT_4"],
expiredPATs: [],
- exhaustedPATS: ["PAT_1"],
+ exhaustedPATs: ["PAT_1"],
+ suspendedPATs: [],
errorPATs: [],
details: {
PAT_1: {
@@ -132,7 +133,8 @@ describe("Test /api/status/pat-info", () => {
{
validPATs: ["PAT_2", "PAT_3", "PAT_4"],
expiredPATs: [],
- exhaustedPATS: [],
+ exhaustedPATs: [],
+ suspendedPATs: [],
errorPATs: ["PAT_1"],
details: {
PAT_1: {
@@ -178,7 +180,8 @@ describe("Test /api/status/pat-info", () => {
{
validPATs: ["PAT_2", "PAT_3", "PAT_4"],
expiredPATs: ["PAT_1"],
- exhaustedPATS: [],
+ exhaustedPATs: [],
+ suspendedPATs: [],
errorPATs: [],
details: {
PAT_1: {
From 112000667c01f18fd161f204ae3ee796ec2e3011 Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Sun, 29 Jan 2023 15:19:01 +0100
Subject: [PATCH 113/157] ci: add update languages action (#2484)
* ci: add update languages action
* ci: make sure PR is created when upstream languages are updated
---
.github/workflows/update-langs.yaml | 44 +++++++++++++++++++++++++++++
src/common/languageColors.json | 18 ++++++++++++
2 files changed, 62 insertions(+)
create mode 100644 .github/workflows/update-langs.yaml
diff --git a/.github/workflows/update-langs.yaml b/.github/workflows/update-langs.yaml
new file mode 100644
index 0000000000000..ad6bfb6213b8f
--- /dev/null
+++ b/.github/workflows/update-langs.yaml
@@ -0,0 +1,44 @@
+name: Update supported languages
+on:
+ schedule:
+ - cron: "0 0 */30 * *"
+
+jobs:
+ updateLanguages:
+ if: github.repository == 'anuraghazra/github-readme-stats'
+ name: Update supported languages
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ node-version: [16.x]
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Setup Node
+ uses: actions/setup-node@v3
+ with:
+ node-version: ${{ matrix.node-version }}
+ cache: npm
+
+ - name: Install dependencies
+ run: npm ci
+ env:
+ CI: true
+
+ - name: Run update-languages-json.js script
+ run: npm run generate-langs-json
+
+ - name: Create Pull Request if upstream language file is changed
+ uses: peter-evans/create-pull-request@v4
+ with:
+ commit-message: "refactor: update languages JSON"
+ branch: "update_langs/patch"
+ delete-branch: true
+ title: Update languages JSON
+ body:
+ "The
+ [update-langs](https://github.com/anuraghazra/github-readme-stats/actions/workflows/update-langs.yaml)
+ action found new/updated languages in the [upstream languages JSON
+ file](https://raw.githubusercontent.com/github/linguist/master/lib/linguist/languages.yml)."
+ labels: "ci, lang-card"
diff --git a/src/common/languageColors.json b/src/common/languageColors.json
index 7e8cd551264b8..47bfb1cfa3435 100644
--- a/src/common/languageColors.json
+++ b/src/common/languageColors.json
@@ -102,6 +102,7 @@
"Csound Score": "#1a1a1a",
"Cuda": "#3A4E3A",
"Curry": "#531242",
+ "Cypher": "#34c0eb",
"Cython": "#fedf5b",
"D": "#ba595e",
"DM": "#447265",
@@ -124,6 +125,7 @@
"Earthly": "#2af0ff",
"Easybuild": "#069406",
"Ecere Projects": "#913960",
+ "Ecmarkup": "#eb8131",
"EditorConfig": "#fff1f2",
"Eiffel": "#4d6977",
"Elixir": "#6e4a7e",
@@ -215,6 +217,7 @@
"Idris": "#b30000",
"Ignore List": "#000000",
"ImageJ Macro": "#99AAFF",
+ "Imba": "#16cec6",
"Inno Setup": "#264b99",
"Io": "#a9188d",
"Ioke": "#078193",
@@ -286,6 +289,7 @@
"Mathematica": "#dd1100",
"Max": "#c4a79c",
"Mercury": "#ff2b2b",
+ "Mermaid": "#ff3670",
"Meson": "#007800",
"Metal": "#8f14e9",
"MiniYAML": "#ff1111",
@@ -318,6 +322,10 @@
"Nu": "#c9df40",
"NumPy": "#9C8AF9",
"Nunjucks": "#3d8137",
+ "OASv2-json": "#85ea2d",
+ "OASv2-yaml": "#85ea2d",
+ "OASv3-json": "#85ea2d",
+ "OASv3-yaml": "#85ea2d",
"OCaml": "#3be133",
"ObjectScript": "#424893",
"Objective-C": "#438eff",
@@ -327,14 +335,18 @@
"Omgrofl": "#cabbff",
"Opal": "#f7ede0",
"Open Policy Agent": "#7d9199",
+ "OpenAPI Specification v2": "#85ea2d",
+ "OpenAPI Specification v3": "#85ea2d",
"OpenCL": "#ed2e2d",
"OpenEdge ABL": "#5ce600",
"OpenQASM": "#AA70FF",
"OpenSCAD": "#e5cd45",
+ "Option List": "#476732",
"Org": "#77aa99",
"Oxygene": "#cdd0e3",
"Oz": "#fab738",
"P4": "#7055b5",
+ "PDDL": "#0d00ff",
"PEG.js": "#234d6b",
"PHP": "#4F5D95",
"PLSQL": "#dad8d8",
@@ -351,6 +363,7 @@
"PigLatin": "#fcd7de",
"Pike": "#005390",
"PogoScript": "#d80074",
+ "Polar": "#ae81ff",
"Portugol": "#f8bd00",
"PostCSS": "#dc3a0c",
"PostScript": "#da291c",
@@ -414,6 +427,7 @@
"Sass": "#a53b70",
"Scala": "#c22d40",
"Scaml": "#bd181a",
+ "Scenic": "#fdc700",
"Scheme": "#1e4aec",
"Scilab": "#ca0f21",
"Self": "#0579aa",
@@ -421,6 +435,7 @@
"Shell": "#89e051",
"ShellCheck Config": "#cecfcb",
"Shen": "#120F14",
+ "Simple File Verification": "#C9BFED",
"Singularity": "#64E6AD",
"Slash": "#007eff",
"Slice": "#003fa2",
@@ -428,6 +443,7 @@
"SmPL": "#c94949",
"Smalltalk": "#596706",
"Smarty": "#f0c040",
+ "Smithy": "#c44536",
"Solidity": "#AA6746",
"SourcePawn": "#f69e1d",
"Squirrel": "#800000",
@@ -478,6 +494,7 @@
"Vim Script": "#199f4b",
"Vim Snippet": "#199f4b",
"Visual Basic .NET": "#945db7",
+ "Visual Basic 6.0": "#2c6353",
"Volt": "#1F1F1F",
"Vue": "#41b883",
"Vyper": "#2980b9",
@@ -514,6 +531,7 @@
"fish": "#4aae47",
"hoon": "#00b171",
"jq": "#c7254e",
+ "just": "#384d54",
"kvlang": "#1da6e0",
"mIRC Script": "#3d57c3",
"mcfunction": "#E22837",
From 888663a47728a4e82a78dcc6fd95ce53bdaffc70 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EA=B0=95=EB=AF=BC=EC=A7=80?=
<68285922+Meezzi@users.noreply.github.com>
Date: Tue, 14 Feb 2023 09:50:12 +0900
Subject: [PATCH 114/157] Add `rose` theme (#2480)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: 강민지 <68285922+Kminzzi@users.noreply.github.com>
---
themes/index.js | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/themes/index.js b/themes/index.js
index a5d3abae8cb6f..60825d132a119 100644
--- a/themes/index.js
+++ b/themes/index.js
@@ -374,6 +374,13 @@ export const themes = {
border_color: "170F0C",
bg_color: "170F0C",
},
+ rose: {
+ title_color: "8d192b",
+ text_color: "862931",
+ icon_color: "B71F36",
+ border_color: "e9d8d4",
+ bg_color: "e9d8d4",
+ },
};
export default themes;
From ba7c2f8b55eac8452e479c8bd38b044d204d0424 Mon Sep 17 00:00:00 2001
From: Amir
Date: Thu, 16 Feb 2023 04:53:11 +0330
Subject: [PATCH 115/157] Support hide_progress for top-langs feature (#2514)
* Add support for hide_progress in top languages feature
* Fix mistake
* Add documents for all languages
* Remove unnecessary value check
* Update top-languages-card.js
* Revert document for all languages except English
* Update documentation
* Update documentation
---------
Co-authored-by: Zohan Subhash
---
api/top-langs.js | 2 ++
readme.md | 13 +++++++++++
src/cards/top-languages-card.js | 39 +++++++++++++++++++++++----------
src/cards/types.d.ts | 1 +
4 files changed, 44 insertions(+), 11 deletions(-)
diff --git a/api/top-langs.js b/api/top-langs.js
index 19cccb894e33a..e67d953323441 100644
--- a/api/top-langs.js
+++ b/api/top-langs.js
@@ -30,6 +30,7 @@ export default async (req, res) => {
border_radius,
border_color,
disable_animations,
+ hide_progress,
} = req.query;
res.setHeader("Content-Type", "image/svg+xml");
@@ -77,6 +78,7 @@ export default async (req, res) => {
border_color,
locale: locale ? locale.toLowerCase() : null,
disable_animations: parseBoolean(disable_animations),
+ hide_progress: parseBoolean(hide_progress),
}),
);
} catch (err) {
diff --git a/readme.md b/readme.md
index 678c5c0b14af4..29852bf9c6515 100644
--- a/readme.md
+++ b/readme.md
@@ -305,6 +305,7 @@ You can provide multiple comma-separated values in the bg_color option to render
- `exclude_repo` - Exclude specified repositories _(Comma-separated values)_. Default: `[] (blank array)`.
- `custom_title` - Sets a custom title for the card _(string)_. Default `Most Used Languages`.
- `disable_animations` - Disables all animations in the card _(boolean)_. Default: `false`.
+- `hide_progress` - It uses the compact layout option, hides percentages, and removes the bars. Default: `false`.
> **Warning**
> Language names should be URI-escaped, as specified in [Percent Encoding](https://en.wikipedia.org/wiki/Percent-encoding)
@@ -398,6 +399,14 @@ You can use the `&layout=compact` option to change the card design.
[![Top Langs](https://github-readme-stats.vercel.app/api/top-langs/?username=anuraghazra&layout=compact)](https://github.com/anuraghazra/github-readme-stats)
```
+### Hide Progress Bars
+
+You can use the `&hide_progress=true` option to hide the percentages and the progress bars (layout will be automatically set to `compact`).
+
+```md
+[![Top Langs](https://github-readme-stats.vercel.app/api/top-langs/?username=anuraghazra&hide_progress=true)](https://github.com/anuraghazra/github-readme-stats)
+```
+
### Demo
[![Top Langs](https://github-readme-stats.vercel.app/api/top-langs/?username=anuraghazra)](https://github.com/anuraghazra/github-readme-stats)
@@ -406,6 +415,10 @@ You can use the `&layout=compact` option to change the card design.
[![Top Langs](https://github-readme-stats.vercel.app/api/top-langs/?username=anuraghazra&layout=compact)](https://github.com/anuraghazra/github-readme-stats)
+- Hidden progress bars
+
+[![Top Langs](https://github-readme-stats.vercel.app/api/top-langs/?username=anuraghazra&hide_progress=true)](https://github.com/anuraghazra/github-readme-stats)
+
# Wakatime Week Stats
Change the `?username=` value to your [Wakatime](https://wakatime.com) username.
diff --git a/src/cards/top-languages-card.js b/src/cards/top-languages-card.js
index 9396ff8e73d5e..be1328c0c8fe3 100644
--- a/src/cards/top-languages-card.js
+++ b/src/cards/top-languages-card.js
@@ -76,10 +76,11 @@ const createProgressTextNode = ({ width, color, name, progress, index }) => {
* @param {object} props Function properties.
* @param {Lang} props.lang Programming language object.
* @param {number} props.totalSize Total size of all languages.
+ * @param {boolean} props.hideProgress Whether to hide percentage.
* @param {number} props.index Index of the programming language.
* @returns {string} Compact layout programming language SVG node.
*/
-const createCompactLangNode = ({ lang, totalSize, index }) => {
+const createCompactLangNode = ({ lang, totalSize, hideProgress, index }) => {
const percentage = ((lang.size / totalSize) * 100).toFixed(2);
const staggerDelay = (index + 3) * 150;
const color = lang.color || "#858585";
@@ -88,7 +89,7 @@ const createCompactLangNode = ({ lang, totalSize, index }) => {
- ${lang.name} ${percentage}%
+ ${lang.name} ${hideProgress ? "" : percentage + "%"}
`;
@@ -100,9 +101,10 @@ const createCompactLangNode = ({ lang, totalSize, index }) => {
* @param {object[]} props Function properties.
* @param {Lang[]} props.langs Array of programming languages.
* @param {number} props.totalSize Total size of all languages.
+ * @param {boolean} props.hideProgress Whether to hide percentage.
* @returns {string} Programming languages SVG node.
*/
-const createLanguageTextNode = ({ langs, totalSize }) => {
+const createLanguageTextNode = ({ langs, totalSize, hideProgress }) => {
const longestLang = getLongestLang(langs);
const chunked = chunkArray(langs, langs.length / 2);
const layouts = chunked.map((array) => {
@@ -111,6 +113,7 @@ const createLanguageTextNode = ({ langs, totalSize }) => {
createCompactLangNode({
lang,
totalSize,
+ hideProgress,
index,
}),
);
@@ -160,9 +163,10 @@ const renderNormalLayout = (langs, width, totalLanguageSize) => {
* @param {Lang[]} langs Array of programming languages.
* @param {number} width Card width.
* @param {number} totalLanguageSize Total size of all languages.
+ * @param {boolean} hideProgress Whether to hide progress bar.
* @returns {string} Compact layout card SVG object.
*/
-const renderCompactLayout = (langs, width, totalLanguageSize) => {
+const renderCompactLayout = (langs, width, totalLanguageSize, hideProgress) => {
const paddingRight = 50;
const offsetWidth = width - paddingRight;
// progressOffset holds the previous language's width and used to offset the next language
@@ -193,15 +197,21 @@ const renderCompactLayout = (langs, width, totalLanguageSize) => {
.join("");
return `
-
+ ${
+ !hideProgress
+ ? `
+
${compactProgressBar}
-
-
+ `
+ : ""
+ }
+
${createLanguageTextNode({
langs,
totalSize: totalLanguageSize,
+ hideProgress: hideProgress,
})}
`;
@@ -276,6 +286,7 @@ const renderTopLanguages = (topLangs, options = {}) => {
text_color,
bg_color,
hide,
+ hide_progress,
theme,
layout,
custom_title,
@@ -305,11 +316,17 @@ const renderTopLanguages = (topLangs, options = {}) => {
let height = calculateNormalLayoutHeight(langs.length);
let finalLayout = "";
- if (layout === "compact") {
+ if (layout === "compact" || hide_progress == true) {
width = width + 50; // padding
- height = calculateCompactLayoutHeight(langs.length);
-
- finalLayout = renderCompactLayout(langs, width, totalLanguageSize);
+ height =
+ calculateCompactLayoutHeight(langs.length) + (hide_progress ? -25 : 0);
+
+ finalLayout = renderCompactLayout(
+ langs,
+ width,
+ totalLanguageSize,
+ hide_progress,
+ );
} else {
finalLayout = renderNormalLayout(langs, width, totalLanguageSize);
}
diff --git a/src/cards/types.d.ts b/src/cards/types.d.ts
index c5945d48be71e..52ee0edb6a459 100644
--- a/src/cards/types.d.ts
+++ b/src/cards/types.d.ts
@@ -38,6 +38,7 @@ export type TopLangOptions = CommonOptions & {
custom_title: string;
langs_count: number;
disable_animations: boolean;
+ hide_progress: boolean;
};
type WakaTimeOptions = CommonOptions & {
From 5f20e6c97a35d77c4b2839b340bfc188ed23a056 Mon Sep 17 00:00:00 2001
From: Mohamed Hassan
Date: Sat, 25 Feb 2023 08:49:30 +0200
Subject: [PATCH 116/157] add holi_theme (#2539)
* add holi_theme
* add holi_theme
---
themes/index.js | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/themes/index.js b/themes/index.js
index 60825d132a119..5ed0f782fd90a 100644
--- a/themes/index.js
+++ b/themes/index.js
@@ -381,6 +381,13 @@ export const themes = {
border_color: "e9d8d4",
bg_color: "e9d8d4",
},
+ holi_theme: {
+ title_color: "5FABEE",
+ text_color: "D6E7FF",
+ icon_color: "5FABEE",
+ border_color: "85A4C0",
+ bg_color: "030314",
+ },
};
export default themes;
From a6ff0fa521f87f112f124bc7a9d0b435d4d166b4 Mon Sep 17 00:00:00 2001
From: Oleksandr Perlov
Date: Sat, 25 Feb 2023 08:50:00 +0200
Subject: [PATCH 117/157] Add one_dark_pro (#2507)
This colors were taken from One Dark Pro theme in VSCode extention. Please add it and I will use it in my profile
Co-authored-by: Zohan Subhash
---
themes/index.js | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/themes/index.js b/themes/index.js
index 5ed0f782fd90a..e55c12f89bdce 100644
--- a/themes/index.js
+++ b/themes/index.js
@@ -374,6 +374,12 @@ export const themes = {
border_color: "170F0C",
bg_color: "170F0C",
},
+ one_dark_pro: {
+ title_color: "61AFEF",
+ text_color: "E5C06E",
+ icon_color: "C678DD",
+ border_color: "3B4048",
+ bg_color: "23272E",
rose: {
title_color: "8d192b",
text_color: "862931",
From f3f7a4837d48cb82abd61e8b16631f0f161fca9f Mon Sep 17 00:00:00 2001
From: Cateline Mnemosyne
<123184375+catelinemnemosyne@users.noreply.github.com>
Date: Sat, 25 Feb 2023 09:55:12 +0100
Subject: [PATCH 118/157] fix: fix JSON themes bug. (#2544)
This fixes a JSON bug that was introduced in https://github.com/anuraghazra/github-readme-stats/pull/2507.
---
themes/index.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/themes/index.js b/themes/index.js
index e55c12f89bdce..01c9a8eee79d6 100644
--- a/themes/index.js
+++ b/themes/index.js
@@ -380,6 +380,7 @@ export const themes = {
icon_color: "C678DD",
border_color: "3B4048",
bg_color: "23272E",
+ },
rose: {
title_color: "8d192b",
text_color: "862931",
From 55a303b4a621b9f1ac1ce0c6fe298139df7d2ac1 Mon Sep 17 00:00:00 2001
From: Zohan Subhash
Date: Sat, 25 Feb 2023 17:20:14 +0530
Subject: [PATCH 119/157] Add auto-labelling for documentation updates (#2526)
---
.github/labeler.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.github/labeler.yml b/.github/labeler.yml
index be97765f07e42..fad3eeeb8d101 100644
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -1,3 +1,4 @@
themes: themes/index.js
doc-translation: docs/*
card-i18n: src/translations.js
+documentation: readme.md
From 91345ed55fab44acac016a25d7083fc74b0b1592 Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Sat, 25 Feb 2023 12:51:54 +0100
Subject: [PATCH 120/157] ci: fix unsafe directory bug (#2518)
This commit fixes a bug that was introduced due to a upstream change in
the git package. See https://stackoverflow.com/questions/71849415/i-cannot-add-the-parent-directory-to-safe-directory-in-git/71904131#71904131
for more information.
---
.github/workflows/generate-theme-doc.yml | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/.github/workflows/generate-theme-doc.yml b/.github/workflows/generate-theme-doc.yml
index d5fac06381943..75f6511f09015 100644
--- a/.github/workflows/generate-theme-doc.yml
+++ b/.github/workflows/generate-theme-doc.yml
@@ -23,6 +23,10 @@ jobs:
node-version: ${{ matrix.node-version }}
cache: npm
+ # Fix the unsafe repo error which was introduced by the CVE-2022-24765 git patches.
+ - name: Fix unsafe repo error
+ run: git config --global --add safe.directory ${{ github.workspace }}
+
- name: npm install, generate readme
run: |
npm ci
From 8898d013b67481844213e065407cbe64ef6f3292 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Raphael=20Gon=C3=A7alves?=
<89359384+raphaelricardo10@users.noreply.github.com>
Date: Sat, 25 Feb 2023 09:02:42 -0300
Subject: [PATCH 121/157] Update readme.md (#2414)
fix: missing "&" in show_icons=true in Showing icons section
---
readme.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/readme.md b/readme.md
index 29852bf9c6515..83f573eddef12 100644
--- a/readme.md
+++ b/readme.md
@@ -133,7 +133,7 @@ You can add the count of all your private contributions to the total commits cou
### Showing icons
-To enable icons, you can pass `show_icons=true` in the query param, like so:
+To enable icons, you can pass `&show_icons=true` in the query param, like so:
```md
![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true)
From a3c6f874af5c7140c67d3db4e15f85fb92171fd8 Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Sat, 25 Feb 2023 13:32:08 +0100
Subject: [PATCH 122/157] test: update snapshots (#2519)
---
src/cards/wakatime-card.js | 26 ++++++++++-
.../renderWakatimeCard.test.js.snap | 44 +++++++++++++++++++
2 files changed, 69 insertions(+), 1 deletion(-)
diff --git a/src/cards/wakatime-card.js b/src/cards/wakatime-card.js
index e7af1df710f9c..2c329558b8a35 100644
--- a/src/cards/wakatime-card.js
+++ b/src/cards/wakatime-card.js
@@ -118,6 +118,7 @@ const createTextNode = ({
// @ts-ignore
name: label,
progressBarBackgroundColor,
+ delay: staggerDelay + 300,
});
return `
@@ -276,11 +277,12 @@ const renderWakatimeCard = (stats = {}, options = { hide: [] }) => {
} else {
finalLayout = flexLayout({
items: filteredLanguages.length
- ? filteredLanguages.map((language) => {
+ ? filteredLanguages.map((language, index) => {
return createTextNode({
id: language.name,
label: language.name,
value: language.text,
+ index: index,
percent: language.percent,
// @ts-ignore
progressBarColor: titleColor,
@@ -321,7 +323,29 @@ const renderWakatimeCard = (stats = {}, options = { hide: [] }) => {
card.setCSS(
`
${cssStyles}
+ @keyframes slideInAnimation {
+ from {
+ width: 0;
+ }
+ to {
+ width: calc(100%-100px);
+ }
+ }
+ @keyframes growWidthAnimation {
+ from {
+ width: 0;
+ }
+ to {
+ width: 100%;
+ }
+ }
.lang-name { font: 400 11px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${textColor} }
+ #rect-mask rect{
+ animation: slideInAnimation 1s ease-in-out forwards;
+ }
+ .lang-progress{
+ animation: growWidthAnimation 0.6s ease-in-out forwards;
+ }
`,
);
diff --git a/tests/__snapshots__/renderWakatimeCard.test.js.snap b/tests/__snapshots__/renderWakatimeCard.test.js.snap
index 1c0bd701fbbfe..6dfaf98e9742a 100644
--- a/tests/__snapshots__/renderWakatimeCard.test.js.snap
+++ b/tests/__snapshots__/renderWakatimeCard.test.js.snap
@@ -69,7 +69,29 @@ exports[`Test Render Wakatime Card should render correctly with compact layout 1
}
+ @keyframes slideInAnimation {
+ from {
+ width: 0;
+ }
+ to {
+ width: calc(100%-100px);
+ }
+ }
+ @keyframes growWidthAnimation {
+ from {
+ width: 0;
+ }
+ to {
+ width: 100%;
+ }
+ }
.lang-name { font: 400 11px 'Segoe UI', Ubuntu, Sans-Serif; fill: #434d58 }
+ #rect-mask rect{
+ animation: slideInAnimation 1s ease-in-out forwards;
+ }
+ .lang-progress{
+ animation: growWidthAnimation 0.6s ease-in-out forwards;
+ }
@@ -227,7 +249,29 @@ exports[`Test Render Wakatime Card should render correctly with compact layout w
}
+ @keyframes slideInAnimation {
+ from {
+ width: 0;
+ }
+ to {
+ width: calc(100%-100px);
+ }
+ }
+ @keyframes growWidthAnimation {
+ from {
+ width: 0;
+ }
+ to {
+ width: 100%;
+ }
+ }
.lang-name { font: 400 11px 'Segoe UI', Ubuntu, Sans-Serif; fill: #434d58 }
+ #rect-mask rect{
+ animation: slideInAnimation 1s ease-in-out forwards;
+ }
+ .lang-progress{
+ animation: growWidthAnimation 0.6s ease-in-out forwards;
+ }
From 2ab8b85ae39e7b3307c27328916b97e96f1da00f Mon Sep 17 00:00:00 2001
From: Rehman
Date: Sat, 25 Feb 2023 19:01:49 +0530
Subject: [PATCH 123/157] fix: for issue #2534 (#2536)
---
src/cards/top-languages-card.js | 3 +--
tests/renderTopLanguages.test.js | 6 +++---
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/src/cards/top-languages-card.js b/src/cards/top-languages-card.js
index be1328c0c8fe3..ce8e12a839c77 100644
--- a/src/cards/top-languages-card.js
+++ b/src/cards/top-languages-card.js
@@ -13,7 +13,7 @@ import {
import { langCardLocales } from "../translations.js";
const DEFAULT_CARD_WIDTH = 300;
-const MIN_CARD_WIDTH = 230;
+const MIN_CARD_WIDTH = 280;
const DEFAULT_LANGS_COUNT = 5;
const DEFAULT_LANG_COLOR = "#858585";
const CARD_PADDING = 25;
@@ -317,7 +317,6 @@ const renderTopLanguages = (topLangs, options = {}) => {
let finalLayout = "";
if (layout === "compact" || hide_progress == true) {
- width = width + 50; // padding
height =
calculateCompactLayoutHeight(langs.length) + (hide_progress ? -25 : 0);
diff --git a/tests/renderTopLanguages.test.js b/tests/renderTopLanguages.test.js
index 8ae4bbd0c16e6..de9e21f129bdf 100644
--- a/tests/renderTopLanguages.test.js
+++ b/tests/renderTopLanguages.test.js
@@ -216,7 +216,7 @@ describe("Test renderTopLanguages", () => {
);
expect(queryAllByTestId(document.body, "lang-progress")[0]).toHaveAttribute(
"width",
- "120",
+ "100",
);
expect(queryAllByTestId(document.body, "lang-name")[1]).toHaveTextContent(
@@ -224,7 +224,7 @@ describe("Test renderTopLanguages", () => {
);
expect(queryAllByTestId(document.body, "lang-progress")[1]).toHaveAttribute(
"width",
- "120",
+ "100",
);
expect(queryAllByTestId(document.body, "lang-name")[2]).toHaveTextContent(
@@ -232,7 +232,7 @@ describe("Test renderTopLanguages", () => {
);
expect(queryAllByTestId(document.body, "lang-progress")[2]).toHaveAttribute(
"width",
- "60",
+ "50",
);
});
From 1d528da1dcfe301861810e7e559e70da262c4d4f Mon Sep 17 00:00:00 2001
From: Zohan Subhash
Date: Sat, 25 Feb 2023 19:34:00 +0530
Subject: [PATCH 124/157] Add option to deploy using other services (#2525)
* Create express.js
* Update readme.md
* Update readme.md
---
express.js | 15 +++++++++++++++
readme.md | 25 +++++++++++++++++++++++--
2 files changed, 38 insertions(+), 2 deletions(-)
create mode 100644 express.js
diff --git a/express.js b/express.js
new file mode 100644
index 0000000000000..0a139625e06bb
--- /dev/null
+++ b/express.js
@@ -0,0 +1,15 @@
+import statsCard from './api/index.js'
+import repoCard from './api/pin.js'
+import langCard from './api/top-langs.js'
+import wakatimeCard from './api/wakatime.js'
+import express from 'express'
+import dotenv from 'dotenv'
+
+dotenv.config()
+const app = express()
+app.listen(process.env.port || 9000)
+
+app.get('/', statsCard)
+app.get('/pin', repoCard)
+app.get('/top-langs', langCard)
+app.get('/wakatime', wakatimeCard)
diff --git a/readme.md b/readme.md
index 83f573eddef12..7a60228460126 100644
--- a/readme.md
+++ b/readme.md
@@ -92,7 +92,9 @@ Visit and make a small donation to hel
- [Repo Card Exclusive Options](#repo-card-exclusive-options)
- [Language Card Exclusive Options](#language-card-exclusive-options)
- [Wakatime Card Exclusive Option](#wakatime-card-exclusive-options)
-- [Deploy Yourself](#deploy-on-your-own-vercel-instance)
+- [Deploy Yourself](#deploy-on-your-own)
+ - [On Vercel](#on-vercel)
+ - [On other platforms](#on-other-platforms)
- [Keep your fork up to date](#keep-your-fork-up-to-date)
# GitHub Stats Card
@@ -509,7 +511,9 @@ By default, GitHub does not lay out the cards side by side. To do that, you can
```
-## Deploy on your own Vercel instance
+## Deploy on your own
+
+### On Vercel
#### :film_projector: [Check Out Step By Step Video Tutorial By @codeSTACKr](https://youtu.be/n6d4KHSKqGk?t=107)
@@ -546,6 +550,23 @@ Since the GitHub API only allows 5k requests per hour, my `https://github-readme
+### On other platforms
+
+> **Warning**
+> This way of using GRS is not officially supported and was added to cater to some particular use cases where Vercel could not be used (e.g. #2341). The support for this method, therefore, is limited.
+
+
+:hammer_and_wrench: Step-by-step guide for deploying on other platforms
+
+1. Fork or clone this repo as per your needs
+2. Add `express` to the dependencies section of `package.json`
+https://github.com/anuraghazra/github-readme-stats/blob/ba7c2f8b55eac8452e479c8bd38b044d204d0424/package.json#L54-L61
+3. Run `npm i` if needed (initial setup)
+4. Run `node express.js` to start the server, or set the entry point to `express.js` in `package.json` if you're deploying on a managed service
+https://github.com/anuraghazra/github-readme-stats/blob/ba7c2f8b55eac8452e479c8bd38b044d204d0424/package.json#L11
+5. You're done 🎉
+
+
### Keep your fork up to date
You can keep your fork, and thus your private Vercel instance up to date with the upstream using GitHubs' [Sync Fork button](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork). You can also use the [pull](https://github.com/wei/pull) package created by [@wei](https://github.com/wei) to automate this process.
From 82224fa68a453c82b7d5458c5431d3efb01f1853 Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Sat, 25 Feb 2023 15:12:11 +0100
Subject: [PATCH 125/157] ci: update e2e tests (#2548)
---
.gitignore | 2 ++
tests/e2e/e2e.test.js | 6 +++---
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/.gitignore b/.gitignore
index 2cdfa3d334808..25017502d486a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,5 @@ vercel_token
# IDE
.vscode
*.code-workspace
+
+.vercel
diff --git a/tests/e2e/e2e.test.js b/tests/e2e/e2e.test.js
index 402e210fcee17..f34859d4c8be0 100644
--- a/tests/e2e/e2e.test.js
+++ b/tests/e2e/e2e.test.js
@@ -15,14 +15,14 @@ const REPO = "curly-fiesta";
const USER = "catelinemnemosyne";
const STATS_DATA = {
name: "Cateline Mnemosyne",
- totalPRs: 1,
- totalCommits: 7,
+ totalPRs: 2,
+ totalCommits: 8,
totalIssues: 1,
totalStars: 1,
contributedTo: 1,
rank: {
level: "A+",
- score: 50.893750297869225,
+ score: 50.88831151384285,
},
};
From d5fbfb4345a89c264b8b07b16dedf933fa60691a Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Sat, 25 Feb 2023 15:14:47 +0100
Subject: [PATCH 126/157] ci: fix a bug in the theme preview action (#2549)
---
scripts/preview-theme.js | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/scripts/preview-theme.js b/scripts/preview-theme.js
index 38faf873ce3d5..aae892c602fdb 100644
--- a/scripts/preview-theme.js
+++ b/scripts/preview-theme.js
@@ -298,12 +298,13 @@ const themeNameAlreadyExists = (name) => {
return themes[name] !== undefined;
};
+const DRY_RUN = process.env.DRY_RUN === "true" || false;
+
/**
* Main function.
*/
export const run = async (prNumber) => {
try {
- const dryRun = process.env.DRY_RUN === "true" || false;
debug("Retrieve action information from context...");
debug(`Context: ${inspect(github.context)}`);
let commentBody = `
@@ -513,7 +514,7 @@ export const run = async (prNumber) => {
// Create or update theme-preview comment.
debug("Create or update theme-preview comment...");
let comment_url;
- if (!dryRun) {
+ if (!DRY_RUN) {
comment_url = await upsertComment(octokit, {
comment_id: comment?.id,
issue_number: pullRequestId,
@@ -535,7 +536,7 @@ export const run = async (prNumber) => {
const reviewReason = themesValid
? undefined
: INVALID_REVIEW_COMMENT(comment_url);
- if (!dryRun) {
+ if (!DRY_RUN) {
await addReview(
octokit,
pullRequestId,
@@ -558,7 +559,7 @@ export const run = async (prNumber) => {
}
} catch (error) {
debug("Set review state to `REQUEST_CHANGES` and add `invalid` label...");
- if (!dryRun) {
+ if (!DRY_RUN) {
await addReview(
octokit,
pullRequestId,
From 252c2b419d8adbba76e02463b198409f7d1d5977 Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Sun, 26 Feb 2023 03:44:42 +0100
Subject: [PATCH 127/157] refactor: format code (#2550)
---
express.js | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/express.js b/express.js
index 0a139625e06bb..6ce92ff035181 100644
--- a/express.js
+++ b/express.js
@@ -1,15 +1,15 @@
-import statsCard from './api/index.js'
-import repoCard from './api/pin.js'
-import langCard from './api/top-langs.js'
-import wakatimeCard from './api/wakatime.js'
-import express from 'express'
-import dotenv from 'dotenv'
+import statsCard from "./api/index.js";
+import repoCard from "./api/pin.js";
+import langCard from "./api/top-langs.js";
+import wakatimeCard from "./api/wakatime.js";
+import express from "express";
+import dotenv from "dotenv";
-dotenv.config()
-const app = express()
-app.listen(process.env.port || 9000)
+dotenv.config();
+const app = express();
+app.listen(process.env.port || 9000);
-app.get('/', statsCard)
-app.get('/pin', repoCard)
-app.get('/top-langs', langCard)
-app.get('/wakatime', wakatimeCard)
+app.get("/", statsCard);
+app.get("/pin", repoCard);
+app.get("/top-langs", langCard);
+app.get("/wakatime", wakatimeCard);
From d60d53cdb43c27d48ba2fc2973ae8143579b6dd9 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 1 Mar 2023 06:47:56 +0530
Subject: [PATCH 128/157] refactor: update languages JSON (#2554)
Co-authored-by: rickstaa
---
src/common/languageColors.json | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/src/common/languageColors.json b/src/common/languageColors.json
index 47bfb1cfa3435..b50cba6f30b08 100644
--- a/src/common/languageColors.json
+++ b/src/common/languageColors.json
@@ -79,6 +79,7 @@
"Ceylon": "#dfa535",
"Chapel": "#8dc63f",
"ChucK": "#3f8000",
+ "Circom": "#707575",
"Cirru": "#ccccff",
"Clarion": "#db901e",
"Clarity": "#5546ff",
@@ -116,6 +117,7 @@
"DirectX 3D File": "#aace60",
"Dockerfile": "#384d54",
"Dogescript": "#cca760",
+ "Dotenv": "#e5d559",
"Dylan": "#6c616e",
"E": "#ccce35",
"ECL": "#8a1267",
@@ -149,7 +151,7 @@
"Forth": "#341708",
"Fortran": "#4d41b1",
"Fortran Free Form": "#4d41b1",
- "FreeBasic": "#867db1",
+ "FreeBasic": "#141AC9",
"FreeMarker": "#0050b2",
"Frege": "#00cafe",
"Futhark": "#5f021f",
@@ -182,6 +184,7 @@
"Go": "#00ADD8",
"Go Checksums": "#00ADD8",
"Go Module": "#00ADD8",
+ "Godot Resource": "#355570",
"Golo": "#88562A",
"Gosu": "#82937f",
"Grace": "#615f8b",
@@ -192,6 +195,7 @@
"Groovy": "#4298b8",
"Groovy Server Pages": "#4298b8",
"HAProxy": "#106da9",
+ "HCL": "#844FBA",
"HLSL": "#aace60",
"HOCON": "#9ff8ee",
"HTML": "#e34c26",
@@ -225,6 +229,7 @@
"Isabelle ROOT": "#FEFE00",
"J": "#9EEDFF",
"JAR Manifest": "#b07219",
+ "JCL": "#d90e09",
"JFlex": "#DBCA00",
"JSON": "#292929",
"JSON with Comments": "#292929",
@@ -247,9 +252,11 @@
"Jsonnet": "#0064bd",
"Julia": "#a270ba",
"Jupyter Notebook": "#DA5B0B",
+ "Just": "#384d54",
"KRL": "#28430A",
"Kaitai Struct": "#773b37",
"KakouneScript": "#6f8042",
+ "KerboScript": "#41adf0",
"KiCad Layout": "#2f4aab",
"KiCad Legacy Layout": "#2f4aab",
"KiCad Schematic": "#2f4aab",
@@ -362,6 +369,7 @@
"PicoLisp": "#6067af",
"PigLatin": "#fcd7de",
"Pike": "#005390",
+ "PlantUML": "#fbbd16",
"PogoScript": "#d80074",
"Polar": "#ae81ff",
"Portugol": "#f8bd00",
@@ -379,6 +387,7 @@
"Puppet": "#302B6D",
"PureBasic": "#5a6986",
"PureScript": "#1D222D",
+ "Pyret": "#ee1e10",
"Python": "#3572A5",
"Python console": "#3572A5",
"Python traceback": "#3572A5",
@@ -531,7 +540,6 @@
"fish": "#4aae47",
"hoon": "#00b171",
"jq": "#c7254e",
- "just": "#384d54",
"kvlang": "#1da6e0",
"mIRC Script": "#3d57c3",
"mcfunction": "#E22837",
From 8849b5f5fc708ea2f64d5c7176580252e17bc81a Mon Sep 17 00:00:00 2001
From: Zohan Subhash
Date: Wed, 1 Mar 2023 15:03:49 +0530
Subject: [PATCH 129/157] Preview theme workflow fix (#2557)
* Fix octokit error
* ci: make octokit instance global
---------
Co-authored-by: rickstaa
---
scripts/preview-theme.js | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/scripts/preview-theme.js b/scripts/preview-theme.js
index aae892c602fdb..d94d084aa85e7 100644
--- a/scripts/preview-theme.js
+++ b/scripts/preview-theme.js
@@ -44,6 +44,9 @@ const REQUIRED_COLOR_PROPS = ACCEPTED_COLOR_PROPS.slice(0, 4);
const INVALID_REVIEW_COMMENT = (commentUrl) =>
`Some themes are invalid. See the [Automated Theme Preview](${commentUrl}) comment above for more information.`;
+// Retrieve octokit instance.
+const OCTOKIT = github.getOctokit(getGithubToken());
+
/**
* Retrieve PR number from the event payload.
*
@@ -312,7 +315,6 @@ export const run = async (prNumber) => {
\r${THEME_CONTRIB_GUIDELINESS}
`;
const ccc = new ColorContrastChecker();
- const octokit = github.getOctokit(getGithubToken());
const pullRequestId = prNumber ? prNumber : getPrNumber();
const commenter = getCommenter();
const { owner, repo } = getRepoInfo(github.context);
@@ -322,7 +324,7 @@ export const run = async (prNumber) => {
// Retrieve the PR diff and preview-theme comment.
debug("Retrieve PR diff...");
- const res = await octokit.pulls.get({
+ const res = await OCTOKIT.pulls.get({
owner,
repo,
pull_number: pullRequestId,
@@ -332,7 +334,7 @@ export const run = async (prNumber) => {
});
debug("Retrieve preview-theme comment...");
const comment = await findComment(
- octokit,
+ OCTOKIT,
pullRequestId,
owner,
repo,
@@ -515,7 +517,7 @@ export const run = async (prNumber) => {
debug("Create or update theme-preview comment...");
let comment_url;
if (!DRY_RUN) {
- comment_url = await upsertComment(octokit, {
+ comment_url = await upsertComment(OCTOKIT, {
comment_id: comment?.id,
issue_number: pullRequestId,
owner,
@@ -538,7 +540,7 @@ export const run = async (prNumber) => {
: INVALID_REVIEW_COMMENT(comment_url);
if (!DRY_RUN) {
await addReview(
- octokit,
+ OCTOKIT,
pullRequestId,
owner,
repo,
@@ -546,7 +548,7 @@ export const run = async (prNumber) => {
reviewReason,
);
await addRemoveLabel(
- octokit,
+ OCTOKIT,
pullRequestId,
owner,
repo,
@@ -561,7 +563,7 @@ export const run = async (prNumber) => {
debug("Set review state to `REQUEST_CHANGES` and add `invalid` label...");
if (!DRY_RUN) {
await addReview(
- octokit,
+ OCTOKIT,
pullRequestId,
owner,
repo,
@@ -569,7 +571,7 @@ export const run = async (prNumber) => {
error.message,
);
await addRemoveLabel(
- octokit,
+ OCTOKIT,
pullRequestId,
owner,
repo,
From a1c3c6accc1e8a0be00dd0db5a32d63d86055daa Mon Sep 17 00:00:00 2001
From: Zohan Subhash
Date: Wed, 1 Mar 2023 21:21:25 +0530
Subject: [PATCH 130/157] ci: preview theme workflow fix (#2559)
* Fix octokit error
* ci: make octokit instance global
* Fix preview theme (move declarations to global)
* refactor: make constants uppercase
---------
Co-authored-by: rickstaa
---
scripts/preview-theme.js | 50 ++++++++++++++++++++--------------------
1 file changed, 25 insertions(+), 25 deletions(-)
diff --git a/scripts/preview-theme.js b/scripts/preview-theme.js
index d94d084aa85e7..f5a24a80a326d 100644
--- a/scripts/preview-theme.js
+++ b/scripts/preview-theme.js
@@ -46,6 +46,8 @@ const INVALID_REVIEW_COMMENT = (commentUrl) =>
// Retrieve octokit instance.
const OCTOKIT = github.getOctokit(getGithubToken());
+const PULL_REQUEST_ID = prNumber ? prNumber : getPrNumber();
+const { OWNER, REPO } = getRepoInfo(github.context);
/**
* Retrieve PR number from the event payload.
@@ -315,19 +317,17 @@ export const run = async (prNumber) => {
\r${THEME_CONTRIB_GUIDELINESS}
`;
const ccc = new ColorContrastChecker();
- const pullRequestId = prNumber ? prNumber : getPrNumber();
const commenter = getCommenter();
- const { owner, repo } = getRepoInfo(github.context);
- debug(`Owner: ${owner}`);
- debug(`Repo: ${repo}`);
+ debug(`Owner: ${OWNER}`);
+ debug(`Repo: ${REPO}`);
debug(`Commenter: ${commenter}`);
// Retrieve the PR diff and preview-theme comment.
debug("Retrieve PR diff...");
const res = await OCTOKIT.pulls.get({
- owner,
- repo,
- pull_number: pullRequestId,
+ OWNER,
+ REPO,
+ pull_number: PULL_REQUEST_ID,
mediaType: {
format: "diff",
},
@@ -335,9 +335,9 @@ export const run = async (prNumber) => {
debug("Retrieve preview-theme comment...");
const comment = await findComment(
OCTOKIT,
- pullRequestId,
- owner,
- repo,
+ PULL_REQUEST_ID,
+ OWNER,
+ REPO,
commenter,
);
@@ -519,9 +519,9 @@ export const run = async (prNumber) => {
if (!DRY_RUN) {
comment_url = await upsertComment(OCTOKIT, {
comment_id: comment?.id,
- issue_number: pullRequestId,
- owner,
- repo,
+ issue_number: PULL_REQUEST_ID,
+ OWNER,
+ REPO,
body: commentBody,
});
} else {
@@ -541,17 +541,17 @@ export const run = async (prNumber) => {
if (!DRY_RUN) {
await addReview(
OCTOKIT,
- pullRequestId,
- owner,
- repo,
+ PULL_REQUEST_ID,
+ OWNER,
+ REPO,
reviewState,
reviewReason,
);
await addRemoveLabel(
OCTOKIT,
- pullRequestId,
- owner,
- repo,
+ PULL_REQUEST_ID,
+ OWNER,
+ REPO,
"invalid",
!themesValid,
);
@@ -564,17 +564,17 @@ export const run = async (prNumber) => {
if (!DRY_RUN) {
await addReview(
OCTOKIT,
- pullRequestId,
- owner,
- repo,
+ PULL_REQUEST_ID,
+ OWNER,
+ REPO,
"REQUEST_CHANGES",
error.message,
);
await addRemoveLabel(
OCTOKIT,
- pullRequestId,
- owner,
- repo,
+ PULL_REQUEST_ID,
+ OWNER,
+ REPO,
"invalid",
true,
);
From 9ec2c8367a38e008a1c4ea740d2408bdc3c20842 Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Thu, 2 Mar 2023 03:14:43 +0100
Subject: [PATCH 131/157] refactor: fix code comments and change 'up' rate
limit (#2560)
---
api/status/pat-info.js | 4 ++--
api/status/up.js | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/api/status/pat-info.js b/api/status/pat-info.js
index 775e06896427c..69d869ea2553e 100644
--- a/api/status/pat-info.js
+++ b/api/status/pat-info.js
@@ -2,11 +2,11 @@
* @file Contains a simple cloud function that can be used to check which PATs are no
* longer working. It returns a list of valid PATs, expired PATs and PATs with errors.
*
- * @description This function is currently rate limited to 1 request per 10 minutes.
+ * @description This function is currently rate limited to 1 request per 5 minutes.
*/
import { logger, request, dateDiff } from "../../src/common/utils.js";
-export const RATE_LIMIT_SECONDS = 60 * 5; // 1 request per 10 minutes
+export const RATE_LIMIT_SECONDS = 60 * 5; // 1 request per 5 minutes
/**
* Simple uptime check fetcher for the PATs.
diff --git a/api/status/up.js b/api/status/up.js
index 33fe8f900c395..678a20b0b5c14 100644
--- a/api/status/up.js
+++ b/api/status/up.js
@@ -2,13 +2,13 @@
* @file Contains a simple cloud function that can be used to check if the PATs are still
* functional.
*
- * @description This function is currently rate limited to 1 request per 10 minutes.
+ * @description This function is currently rate limited to 1 request per 5 minutes.
*/
import retryer from "../../src/common/retryer.js";
import { logger, request } from "../../src/common/utils.js";
-export const RATE_LIMIT_SECONDS = 60 * 10; // 1 request per 10 minutes
+export const RATE_LIMIT_SECONDS = 60 * 5; // 1 request per 5 minutes
/**
* Simple uptime check fetcher for the PATs.
From 7bc8f19a7fd7787287c02e42761602746e55c1d2 Mon Sep 17 00:00:00 2001
From: Zohan Subhash
Date: Thu, 2 Mar 2023 22:51:39 +0530
Subject: [PATCH 132/157] Preview action fix (#2561)
* Fix error
* refactor: remove unused code
---------
Co-authored-by: Rick Staa
---
scripts/preview-theme.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/scripts/preview-theme.js b/scripts/preview-theme.js
index f5a24a80a326d..baccaa61a3a78 100644
--- a/scripts/preview-theme.js
+++ b/scripts/preview-theme.js
@@ -46,7 +46,7 @@ const INVALID_REVIEW_COMMENT = (commentUrl) =>
// Retrieve octokit instance.
const OCTOKIT = github.getOctokit(getGithubToken());
-const PULL_REQUEST_ID = prNumber ? prNumber : getPrNumber();
+const PULL_REQUEST_ID = getPrNumber();
const { OWNER, REPO } = getRepoInfo(github.context);
/**
@@ -308,7 +308,7 @@ const DRY_RUN = process.env.DRY_RUN === "true" || false;
/**
* Main function.
*/
-export const run = async (prNumber) => {
+export const run = async () => {
try {
debug("Retrieve action information from context...");
debug(`Context: ${inspect(github.context)}`);
From 976771080facb86c3e4b455fef18278021f7f984 Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Fri, 3 Mar 2023 09:07:02 +0100
Subject: [PATCH 133/157] ci: fix theme preview action (#2563)
---
scripts/preview-theme.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/scripts/preview-theme.js b/scripts/preview-theme.js
index baccaa61a3a78..2cfe0f25cad3a 100644
--- a/scripts/preview-theme.js
+++ b/scripts/preview-theme.js
@@ -46,8 +46,8 @@ const INVALID_REVIEW_COMMENT = (commentUrl) =>
// Retrieve octokit instance.
const OCTOKIT = github.getOctokit(getGithubToken());
-const PULL_REQUEST_ID = getPrNumber();
const { OWNER, REPO } = getRepoInfo(github.context);
+var PULL_REQUEST_ID;
/**
* Retrieve PR number from the event payload.
@@ -318,6 +318,7 @@ export const run = async () => {
`;
const ccc = new ColorContrastChecker();
const commenter = getCommenter();
+ PULL_REQUEST_ID = getPrNumber();
debug(`Owner: ${OWNER}`);
debug(`Repo: ${REPO}`);
debug(`Commenter: ${commenter}`);
From 1e61f9f3fe955fa25ab27dd1e06ddbfd788f4fda Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Fri, 3 Mar 2023 15:57:11 +0100
Subject: [PATCH 134/157] fix theme preview (#2564)
* ci: fix theme preview action
* fix: fix some bugs in the 'theme-preveiw' action
---
scripts/preview-theme.js | 41 +++++++++++++++++++++++++++++++---------
1 file changed, 32 insertions(+), 9 deletions(-)
diff --git a/scripts/preview-theme.js b/scripts/preview-theme.js
index 2cfe0f25cad3a..c0bb9eb5522d8 100644
--- a/scripts/preview-theme.js
+++ b/scripts/preview-theme.js
@@ -43,12 +43,24 @@ const ACCEPTED_COLOR_PROPS = Object.keys(COLOR_PROPS);
const REQUIRED_COLOR_PROPS = ACCEPTED_COLOR_PROPS.slice(0, 4);
const INVALID_REVIEW_COMMENT = (commentUrl) =>
`Some themes are invalid. See the [Automated Theme Preview](${commentUrl}) comment above for more information.`;
-
-// Retrieve octokit instance.
-const OCTOKIT = github.getOctokit(getGithubToken());
-const { OWNER, REPO } = getRepoInfo(github.context);
+var OCTOKIT;
+var OWNER;
+var REPO;
var PULL_REQUEST_ID;
+/**
+ * Incorrect JSON format error.
+ * @extends Error
+ * @param {string} message Error message.
+ * @returns {Error} IncorrectJsonFormatError.
+ */
+class IncorrectJsonFormatError extends Error {
+ constructor(message) {
+ super(message);
+ this.name = "IncorrectJsonFormatError";
+ }
+}
+
/**
* Retrieve PR number from the event payload.
*
@@ -274,7 +286,9 @@ const parseJSON = (json) => {
if (typeof parsedJson === "object") {
return parsedJson;
} else {
- throw new Error("PR diff is not a valid theme JSON object.");
+ throw new IncorrectJsonFormatError(
+ "PR diff is not a valid theme JSON object.",
+ );
}
} catch (error) {
let parsedJson = json
@@ -289,7 +303,9 @@ const parseJSON = (json) => {
}
return Hjson.parse(parsedJson.join(""));
} else {
- throw error;
+ throw new IncorrectJsonFormatError(
+ `Theme JSON file could not be parsed: ${error.message}`,
+ );
}
}
};
@@ -317,6 +333,11 @@ export const run = async () => {
\r${THEME_CONTRIB_GUIDELINESS}
`;
const ccc = new ColorContrastChecker();
+ OCTOKIT = github.getOctokit(getGithubToken());
+ PULL_REQUEST_ID = getPrNumber();
+ const { owner, repo } = getRepoInfo(github.context);
+ OWNER = owner;
+ REPO = repo;
const commenter = getCommenter();
PULL_REQUEST_ID = getPrNumber();
debug(`Owner: ${OWNER}`);
@@ -326,8 +347,8 @@ export const run = async () => {
// Retrieve the PR diff and preview-theme comment.
debug("Retrieve PR diff...");
const res = await OCTOKIT.pulls.get({
- OWNER,
- REPO,
+ owner: OWNER,
+ repo: REPO,
pull_number: PULL_REQUEST_ID,
mediaType: {
format: "diff",
@@ -569,7 +590,9 @@ export const run = async () => {
OWNER,
REPO,
"REQUEST_CHANGES",
- error.message,
+ "**Something went wrong in the theme preview action:** `" +
+ error.message +
+ "`",
);
await addRemoveLabel(
OCTOKIT,
From ed18914fa4c131b076cbc6cff29db3ffbdc48787 Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Sun, 5 Mar 2023 11:22:08 +0100
Subject: [PATCH 135/157] ci: fixes theme preview action (#2566)
---
scripts/preview-theme.js | 44 ++++++++++++++++++++++++++++++----------
1 file changed, 33 insertions(+), 11 deletions(-)
diff --git a/scripts/preview-theme.js b/scripts/preview-theme.js
index c0bb9eb5522d8..3179780d8438c 100644
--- a/scripts/preview-theme.js
+++ b/scripts/preview-theme.js
@@ -143,15 +143,36 @@ const findComment = async (octokit, issueNumber, owner, repo, commenter) => {
* Create or update the preview comment.
*
* @param {Object} octokit Octokit instance.
- * @param {Object} props Comment properties.
+ * @param {number} issueNumber Issue number.
+ * @param {Object} repo Repository name.
+ * @param {Object} owner Owner of the repository.
+ * @param {number} commentId Comment ID.
+ * @param {string} body Comment body.
* @return {string} The comment URL.
*/
-const upsertComment = async (octokit, props) => {
+const upsertComment = async (
+ octokit,
+ issueNumber,
+ repo,
+ owner,
+ commentId,
+ body,
+) => {
let resp;
- if (props.comment_id !== undefined) {
- resp = await octokit.issues.updateComment(props);
+ if (commentId !== undefined) {
+ resp = await octokit.issues.updateComment({
+ owner,
+ repo,
+ comment_id: commentId,
+ body,
+ });
} else {
- resp = await octokit.issues.createComment(props);
+ resp = await octokit.issues.createComment({
+ owner,
+ repo,
+ issue_number: issueNumber,
+ body,
+ });
}
return resp.data.html_url;
};
@@ -539,13 +560,14 @@ export const run = async () => {
debug("Create or update theme-preview comment...");
let comment_url;
if (!DRY_RUN) {
- comment_url = await upsertComment(OCTOKIT, {
- comment_id: comment?.id,
- issue_number: PULL_REQUEST_ID,
- OWNER,
+ comment_url = await upsertComment(
+ OCTOKIT,
+ PULL_REQUEST_ID,
REPO,
- body: commentBody,
- });
+ OWNER,
+ comment?.id,
+ commentBody,
+ );
} else {
info(`DRY_RUN: Comment body: ${commentBody}`);
comment_url = "";
From b93aee34d0101aed1de0b5d7cc68c3bb19614d52 Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Mon, 6 Mar 2023 05:03:06 +0100
Subject: [PATCH 136/157] ci: improve theme preview action (#2572)
---
scripts/preview-theme.js | 41 +++++++++++++++++++++++++++++-----------
1 file changed, 30 insertions(+), 11 deletions(-)
diff --git a/scripts/preview-theme.js b/scripts/preview-theme.js
index 3179780d8438c..e18c01b8615af 100644
--- a/scripts/preview-theme.js
+++ b/scripts/preview-theme.js
@@ -312,18 +312,30 @@ const parseJSON = (json) => {
);
}
} catch (error) {
- let parsedJson = json
+ // Remove trailing commas (if any).
+ let parsedJson = json.replace(/(,\s*})/g, "}");
+
+ // Remove JS comments (if any).
+ parsedJson = parsedJson.replace(/\/\/[A-z\s]*\s/g, "");
+
+ // Fix incorrect open bracket (if any).
+ const splitJson = parsedJson
.split(/([\s\r\s]*}[\s\r\s]*,[\s\r\s]*)(?=[\w"-]+:)/)
- .filter((x) => typeof x !== "string" || !!x.trim());
- if (parsedJson[0].replace(/\s+/g, "") === "},") {
- parsedJson[0] = "},";
- if (!/\s*}\s*,?\s*$/.test(parsedJson[1])) {
- parsedJson.push(parsedJson.shift());
+ .filter((x) => typeof x !== "string" || !!x.trim()); // Split json into array of strings and objects.
+ if (splitJson[0].replace(/\s+/g, "") === "},") {
+ splitJson[0] = "},";
+ if (!/\s*}\s*,?\s*$/.test(splitJson[1])) {
+ splitJson.push(splitJson.shift());
} else {
- parsedJson.shift();
+ splitJson.shift();
}
- return Hjson.parse(parsedJson.join(""));
- } else {
+ parsedJson = splitJson.join("");
+ }
+
+ // Try to parse the fixed json.
+ try {
+ return Hjson.parse(parsedJson);
+ } catch (error) {
throw new IncorrectJsonFormatError(
`Theme JSON file could not be parsed: ${error.message}`,
);
@@ -387,10 +399,17 @@ export const run = async () => {
// Retrieve theme changes from the PR diff.
debug("Retrieve themes...");
const diff = parse(res.data);
+
+ // Retrieve all theme changes from the PR diff and convert to JSON.
+ debug("Retrieve theme changes...");
const content = diff
.find((file) => file.to === "themes/index.js")
- .chunks[0].changes.filter((c) => c.type === "add")
- .map((c) => c.content.replace("+", ""))
+ .chunks.map((chunk) =>
+ chunk.changes
+ .filter((c) => c.type === "add")
+ .map((c) => c.content.replace("+", ""))
+ .join(""),
+ )
.join("");
const themeObject = parseJSON(content);
if (
From c5063b92b6e260dcc405a0a4cd27552dc103f8f5 Mon Sep 17 00:00:00 2001
From: Etanarvazac Revorix
Date: Tue, 7 Mar 2023 20:06:04 -0500
Subject: [PATCH 137/157] Added "Shadow" set (Red, Green, Blue, transparent BG)
(#2529)
* Added "Shadow" set (Red, Green, Blue, transparent BG)
3 additional themes sticking primarily to flat colors, which the exception of icons and border being slightly darker. All 3 themes also have transparent backgrounds that will show differently per-user via GiHub's own light and dark themes. Transparency should also still provide easy readability for both.
* Test
Just want to see if we can make the themes have a transparent background.
* Shadows moved under Transparent
---------
Co-authored-by: Zohan Subhash
---
themes/index.js | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/themes/index.js b/themes/index.js
index 01c9a8eee79d6..d348a2ba1a769 100644
--- a/themes/index.js
+++ b/themes/index.js
@@ -18,6 +18,27 @@ export const themes = {
text_color: "417E87",
bg_color: "ffffff00",
},
+ shadow_red: {
+ title_color: "9A0000",
+ text_color: "444",
+ icon_color: "4F0000",
+ border_color: "4F0000",
+ bg_color: "ffffff00",
+ },
+ shadow_green: {
+ title_color: "007A00",
+ text_color: "444",
+ icon_color: "003D00",
+ border_color: "003D00",
+ bg_color: "ffffff00",
+ },
+ shadow_blue: {
+ title_color: "00779A",
+ text_color: "444",
+ icon_color: "004450",
+ border_color: "004490",
+ bg_color: "ffffff00",
+ },
dark: {
title_color: "fff",
icon_color: "79ff97",
From 2bd9d457ac7f10bd5f1303c6a14f3ec22c2ee9c6 Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Thu, 9 Mar 2023 09:45:50 +0000
Subject: [PATCH 138/157] ci: fix theme docs generate bug (#2573)
---
scripts/push-theme-readme.sh | 1 +
1 file changed, 1 insertion(+)
diff --git a/scripts/push-theme-readme.sh b/scripts/push-theme-readme.sh
index 1ab5de474ea5a..132a4b508e8e4 100755
--- a/scripts/push-theme-readme.sh
+++ b/scripts/push-theme-readme.sh
@@ -6,6 +6,7 @@ export BRANCH_NAME=updated-theme-readme
git --version
git config --global user.email "no-reply@githubreadmestats.com"
git config --global user.name "GitHub Readme Stats Bot"
+git config --global --add safe.directory ${GITHUB_WORKSPACE}
git branch -d $BRANCH_NAME || true
git checkout -b $BRANCH_NAME
git add --all
From 32998295b7ef9742ea0168213807d7e8ec5c72a6 Mon Sep 17 00:00:00 2001
From: Eduardo Zaniboni <67515606+eduardozaniboni@users.noreply.github.com>
Date: Tue, 14 Mar 2023 06:12:29 -0300
Subject: [PATCH 139/157] update my theme (#2576)
---
themes/index.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/themes/index.js b/themes/index.js
index d348a2ba1a769..0121cf0bc14d1 100644
--- a/themes/index.js
+++ b/themes/index.js
@@ -409,7 +409,7 @@ export const themes = {
border_color: "e9d8d4",
bg_color: "e9d8d4",
},
- holi_theme: {
+ holi: {
title_color: "5FABEE",
text_color: "D6E7FF",
icon_color: "5FABEE",
From b928f51442ff224507f519ceaca67d09afffa2b1 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Fri, 31 Mar 2023 06:40:22 +0530
Subject: [PATCH 140/157] refactor: update languages JSON (#2596)
Co-authored-by: rickstaa
---
src/common/languageColors.json | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/common/languageColors.json b/src/common/languageColors.json
index b50cba6f30b08..3937eec5a2bf5 100644
--- a/src/common/languageColors.json
+++ b/src/common/languageColors.json
@@ -133,6 +133,7 @@
"Elixir": "#6e4a7e",
"Elm": "#60B5CC",
"Elvish": "#55BB55",
+ "Elvish Transcript": "#55BB55",
"Emacs Lisp": "#c065db",
"EmberScript": "#FFF4F3",
"Erlang": "#B83998",
@@ -453,6 +454,7 @@
"Smalltalk": "#596706",
"Smarty": "#f0c040",
"Smithy": "#c44536",
+ "Snakemake": "#419179",
"Solidity": "#AA6746",
"SourcePawn": "#f69e1d",
"Squirrel": "#800000",
@@ -466,6 +468,7 @@
"SugarSS": "#2fcc9f",
"SuperCollider": "#46390b",
"Svelte": "#ff3e00",
+ "Sway": "#dea584",
"Swift": "#F05138",
"SystemVerilog": "#DAE1C2",
"TI Program": "#A0AA87",
From d8244a7fe5eaffaf7264e592290b9b1f9aaf849d Mon Sep 17 00:00:00 2001
From: Caeden Perelli-Harris
Date: Sat, 1 Apr 2023 05:47:56 +0100
Subject: [PATCH 141/157] Add format stats option (#2155)
* feat: added `format_stats` option (#2128)
* refactor: change `format_stats` to `short_values` (#2128)
* test: create shorten values test (#2128)
* Update readme.md
Co-authored-by: Rick Staa
* refactor: rename ``short_values`` to ``number_format``
* Update readme.md
Co-authored-by: Rick Staa
* Update src/cards/stats-card.js
Co-authored-by: Rick Staa
* refactor: format codebase
---------
Co-authored-by: Rick Staa
---
api/index.js | 2 ++
readme.md | 1 +
src/cards/stats-card.js | 6 +++++-
src/cards/types.d.ts | 1 +
tests/renderStatsCard.test.js | 9 +++++++++
5 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/api/index.js b/api/index.js
index b449d43b49080..e89c74688d116 100644
--- a/api/index.js
+++ b/api/index.js
@@ -35,6 +35,7 @@ export default async (req, res) => {
locale,
disable_animations,
border_radius,
+ number_format,
border_color,
} = req.query;
res.setHeader("Content-Type", "image/svg+xml");
@@ -88,6 +89,7 @@ export default async (req, res) => {
custom_title,
border_radius,
border_color,
+ number_format,
locale: locale ? locale.toLowerCase() : null,
disable_animations: parseBoolean(disable_animations),
}),
diff --git a/readme.md b/readme.md
index 7a60228460126..91a1cfa9f8870 100644
--- a/readme.md
+++ b/readme.md
@@ -289,6 +289,7 @@ You can provide multiple comma-separated values in the bg_color option to render
- `text_bold` - Use bold text _(boolean)_. Default: `true`.
- `disable_animations` - Disables all animations in the card _(boolean)_. Default: `false`.
- `ring_color` - Color of the rank circle _(hex color)_. Defaults to the theme ring color if it exists and otherwise the title color.
+- `number_format` - Switch between two available formats for displaying the card values `short` (i.e. `6.6k`) and `long` (i.e. `6626`). Default: `short`.
> **Note**
> When hide_rank=`true`, the minimum card width is 270 px + the title length and padding.
diff --git a/src/cards/stats-card.js b/src/cards/stats-card.js
index f39a968f18065..c60ea51d5119c 100644
--- a/src/cards/stats-card.js
+++ b/src/cards/stats-card.js
@@ -39,8 +39,10 @@ const createTextNode = ({
showIcons,
shiftValuePos,
bold,
+ number_format,
}) => {
- const kValue = kFormatter(value);
+ const kValue =
+ number_format.toLowerCase() === "long" ? value : kFormatter(value);
const staggerDelay = (index + 3) * 150;
const labelOffset = showIcons ? `x="25"` : "";
@@ -103,6 +105,7 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
custom_title,
border_radius,
border_color,
+ number_format = "short",
locale,
disable_animations = false,
} = options;
@@ -192,6 +195,7 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
showIcons: show_icons,
shiftValuePos: 79.01 + (isLongLocale ? 50 : 0),
bold: text_bold,
+ number_format,
}),
);
diff --git a/src/cards/types.d.ts b/src/cards/types.d.ts
index 52ee0edb6a459..a3abc23e98a36 100644
--- a/src/cards/types.d.ts
+++ b/src/cards/types.d.ts
@@ -22,6 +22,7 @@ export type StatCardOptions = CommonOptions & {
line_height: number | string;
custom_title: string;
disable_animations: boolean;
+ number_format: string;
};
export type RepoCardOptions = CommonOptions & {
diff --git a/tests/renderStatsCard.test.js b/tests/renderStatsCard.test.js
index 748b7a32cd32b..110121ac9e4b6 100644
--- a/tests/renderStatsCard.test.js
+++ b/tests/renderStatsCard.test.js
@@ -357,4 +357,13 @@ describe("Test renderStatsCard", () => {
document.body.innerHTML = renderStatsCard(stats, {});
expect(document.querySelector("rect")).toHaveAttribute("rx", "4.5");
});
+
+ it("should shorten values", () => {
+ stats["totalCommits"] = 1999;
+
+ document.body.innerHTML = renderStatsCard(stats);
+ expect(getByTestId(document.body, "commits").textContent).toBe("2k");
+ document.body.innerHTML = renderStatsCard(stats, { number_format: "long" });
+ expect(getByTestId(document.body, "commits").textContent).toBe("1999");
+ });
});
From 4d1d83d5e5691a5aaa8a65d230924d6072bbc16d Mon Sep 17 00:00:00 2001
From: Fabiano Couto
Date: Sat, 1 Apr 2023 08:22:00 -0300
Subject: [PATCH 142/157] add github_dark_dimmed theme (#2594)
* feat(theme): add github_dark_dimmed theme
* feat(theme): change github_dark_dimmed icon color
* contrast ratio adjustment
contrast ratio adjustment on github_dark_dimmed theme
* feat(theme): readme preview
* feat(theme): github themes next to each other
* github themes next to each other
---
themes/README.md | 14 ++++++++------
themes/index.js | 7 +++++++
2 files changed, 15 insertions(+), 6 deletions(-)
diff --git a/themes/README.md b/themes/README.md
index b8649d43b9564..5993b6a07a9b8 100644
--- a/themes/README.md
+++ b/themes/README.md
@@ -32,10 +32,11 @@ Use `?theme=THEME_NAME` parameter like so :-
| `jolly` ![jolly][jolly] | `maroongold` ![maroongold][maroongold] | `yeblu` ![yeblu][yeblu] |
| `blueberry` ![blueberry][blueberry] | `slateorange` ![slateorange][slateorange] | `kacho_ga` ![kacho_ga][kacho_ga] |
| `outrun` ![outrun][outrun] | `ocean_dark` ![ocean_dark][ocean_dark] | `city_lights` ![city_lights][city_lights] |
-| `github_dark` ![github_dark][github_dark] | `discord_old_blurple` ![discord_old_blurple][discord_old_blurple] | `aura_dark` ![aura_dark][aura_dark] |
+| `github_dark` ![github_dark][github_dark] | `github_dark_dimmed` ![github_dark_dimmed][github_dark_dimmed] | `discord_old_blurple` ![discord_old_blurple][discord_old_blurple] |
| `panda` ![panda][panda] | `noctis_minimus` ![noctis_minimus][noctis_minimus] | `cobalt2` ![cobalt2][cobalt2] |
| `swift` ![swift][swift] | `aura` ![aura][aura] | `apprentice` ![apprentice][apprentice] |
| `moltack` ![moltack][moltack] | `codeSTACKr` ![codeSTACKr][codeSTACKr] | `rose_pine` ![rose_pine][rose_pine] |
+| `aura_dark` ![aura_dark][aura_dark] | | |
| [Add your theme][add-theme] | | |
## Repo Card
@@ -60,10 +61,11 @@ Use `?theme=THEME_NAME` parameter like so :-
| `jolly` ![jolly][jolly_repo] | `maroongold` ![maroongold][maroongold_repo] | `yeblu` ![yeblu][yeblu_repo] |
| `blueberry` ![blueberry][blueberry_repo] | `slateorange` ![slateorange][slateorange_repo] | `kacho_ga` ![kacho_ga][kacho_ga_repo] |
| `outrun` ![outrun][outrun_repo] | `ocean_dark` ![ocean_dark][ocean_dark_repo] | `city_lights` ![city_lights][city_lights_repo] |
-| `github_dark` ![github_dark][github_dark_repo] | `discord_old_blurple` ![discord_old_blurple][discord_old_blurple_repo] | `aura_dark` ![aura_dark][aura_dark_repo] |
+| `github_dark` ![github_dark][github_dark_repo] | `github_dark_dimmed` ![github_dark_dimmed][github_dark_dimmed_repo] | `discord_old_blurple` ![discord_old_blurple][discord_old_blurple_repo] |
| `panda` ![panda][panda_repo] | `noctis_minimus` ![noctis_minimus][noctis_minimus_repo] | `cobalt2` ![cobalt2][cobalt2_repo] |
| `swift` ![swift][swift_repo] | `aura` ![aura][aura_repo] | `apprentice` ![apprentice][apprentice_repo] |
| `moltack` ![moltack][moltack_repo] | `codeSTACKr` ![codeSTACKr][codeSTACKr_repo] | `rose_pine` ![rose_pine][rose_pine_repo] |
+| `aura_dark` ![aura_dark][aura_dark_repo] | | |
| [Add your theme][add-theme] | | |
@@ -117,8 +119,8 @@ Use `?theme=THEME_NAME` parameter like so :-
[ocean_dark]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=ocean_dark
[city_lights]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=city_lights
[github_dark]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=github_dark
+[github_dark_dimmed]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=github_dark_dimmed
[discord_old_blurple]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=discord_old_blurple
-[aura_dark]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=aura_dark
[panda]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=panda
[noctis_minimus]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=noctis_minimus
[cobalt2]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=cobalt2
@@ -128,7 +130,7 @@ Use `?theme=THEME_NAME` parameter like so :-
[moltack]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=moltack
[codeSTACKr]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=codeSTACKr
[rose_pine]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=rose_pine
-
+[aura_dark]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=aura_dark
[default_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=default
[default_repocard_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=default_repocard
@@ -180,8 +182,8 @@ Use `?theme=THEME_NAME` parameter like so :-
[ocean_dark_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=ocean_dark
[city_lights_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=city_lights
[github_dark_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=github_dark
+[github_dark_dimmed_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=github_dark_dimmed
[discord_old_blurple_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=discord_old_blurple
-[aura_dark_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=aura_dark
[panda_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=panda
[noctis_minimus_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=noctis_minimus
[cobalt2_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=cobalt2
@@ -191,7 +193,7 @@ Use `?theme=THEME_NAME` parameter like so :-
[moltack_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=moltack
[codeSTACKr_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=codeSTACKr
[rose_pine_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=rose_pine
-
+[aura_dark_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=aura_dark
[add-theme]: https://github.com/anuraghazra/github-readme-stats/edit/master/themes/index.js
diff --git a/themes/index.js b/themes/index.js
index 0121cf0bc14d1..ab8eab6a0d0e9 100644
--- a/themes/index.js
+++ b/themes/index.js
@@ -321,6 +321,13 @@ export const themes = {
text_color: "C3D1D9",
bg_color: "0D1117",
},
+ github_dark_dimmed: {
+ title_color: "539bf5",
+ icon_color: "539bf5",
+ text_color: "ADBAC7",
+ bg_color: "24292F",
+ border_color: "373E47",
+ },
discord_old_blurple: {
title_color: "7289DA",
icon_color: "7289DA",
From 879937c11d08154f9afa0de7dab7b4945e452276 Mon Sep 17 00:00:00 2001
From: Fabiano Couto
Date: Mon, 24 Apr 2023 10:56:14 -0300
Subject: [PATCH 143/157] feat(RankIcon): add rank_icon option (#2628)
* feat(theme): add github_dark_dimmed theme
* feat(theme): change github_dark_dimmed icon color
* contrast ratio adjustment
contrast ratio adjustment on github_dark_dimmed theme
* feat(theme): readme preview
* feat(theme): github themes next to each other
* github themes next to each other
* feat(RankIcon): add rank icon option
* feat(RankIcon): extract rankIcon to icons file
* feat(RankIcon): update readme
* feat(RankIcon): test coverage
* Update readme.md
Co-authored-by: Rick Staa
---------
Co-authored-by: Rick Staa
---
api/index.js | 2 ++
readme.md | 13 +++++++++----
src/cards/stats-card.js | 13 +++----------
src/cards/types.d.ts | 4 ++++
src/common/icons.js | 25 ++++++++++++++++++++++++-
tests/renderStatsCard.test.js | 17 +++++++++++++++++
6 files changed, 59 insertions(+), 15 deletions(-)
diff --git a/api/index.js b/api/index.js
index e89c74688d116..29ff87f9af863 100644
--- a/api/index.js
+++ b/api/index.js
@@ -37,6 +37,7 @@ export default async (req, res) => {
border_radius,
number_format,
border_color,
+ rank_icon,
} = req.query;
res.setHeader("Content-Type", "image/svg+xml");
@@ -92,6 +93,7 @@ export default async (req, res) => {
number_format,
locale: locale ? locale.toLowerCase() : null,
disable_animations: parseBoolean(disable_animations),
+ rank_icon,
}),
);
} catch (err) {
diff --git a/readme.md b/readme.md
index 91a1cfa9f8870..fe04a88e81bba 100644
--- a/readme.md
+++ b/readme.md
@@ -216,10 +216,10 @@ You can use [GitHub's theme context](https://github.blog/changelog/2021-11-24-sp
##### Use GitHub's new media feature
You can use [GitHub's new media feature](https://github.blog/changelog/2022-05-19-specify-theme-context-for-images-in-markdown-beta/) in HTML to specify whether to display images for light or dark themes. This is done using the HTML `` element in combination with the `prefers-color-scheme` media feature.
-
+
```html
-
@@ -235,7 +235,7 @@ You can use [GitHub's new media feature](https://github.blog/changelog/2022-05-1
:eyes: Show example
-
@@ -260,7 +260,7 @@ You can customize the appearance of your `Stats Card` or `Repo Card` however you
- `border_color` - Card's border color _(hex color)_. Default: `e4e2e2` (Does not apply when `hide_border` is enabled).
- `bg_color` - Card's background color _(hex color)_ **or** a gradient in the form of _angle,start,end_. Default: `fffefe`
- `hide_border` - Hides the card's border _(boolean)_. Default: `false`
-- `theme` - name of the theme, choose from [all available themes](./themes/README.md). Default: `default` theme.
+- `theme` - name of the theme, choose from [all available themes](./themes/README.md). Default: `default` theme.
- `cache_seconds` - set the cache header manually _(min: 14400, max: 86400)_. Default: `14400 seconds (4 hours)`.
- `locale` - set the language in the card _(e.g. cn, de, es, etc.)_. Default: `en`.
- `border_radius` - Corner rounding on the card. Default: `4.5`.
@@ -280,6 +280,7 @@ You can provide multiple comma-separated values in the bg_color option to render
- `hide_title` - _(boolean)_. Default: `false`.
- `card_width` - Set the card's width manually _(number)_. Default: `500px (approx.)`.
- `hide_rank` - _(boolean)_ hides the rank and automatically resizes the card width. Default: `false`.
+- `rank_icon` - Shows alternative rank icon (i.e. `github` or `default`). Default: `default`.
- `show_icons` - _(boolean)_. Default: `false`.
- `include_all_commits` - Count total commits instead of just the current year commits _(boolean)_. Default: `false`.
- `count_private` - Count private commits _(boolean)_. Default: `false`.
@@ -459,6 +460,10 @@ Change the `?username=` value to your [Wakatime](https://wakatime.com) username.
![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&hide=issues&show_icons=true)
+- Shows Github logo instead rank level
+
+![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&rank_icon=github)
+
- Customize Border Color
![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&border_color=2e4058)
diff --git a/src/cards/stats-card.js b/src/cards/stats-card.js
index c60ea51d5119c..cdb468d301f78 100644
--- a/src/cards/stats-card.js
+++ b/src/cards/stats-card.js
@@ -1,7 +1,7 @@
// @ts-check
import { Card } from "../common/Card.js";
import { I18n } from "../common/I18n.js";
-import { icons } from "../common/icons.js";
+import { icons, rankIcon } from "../common/icons.js";
import {
clampValue,
flexLayout,
@@ -108,6 +108,7 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
number_format = "short",
locale,
disable_animations = false,
+ rank_icon = "default",
} = options;
const lheight = parseInt(String(line_height), 10);
@@ -294,15 +295,7 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
-
- ${rank.level}
-
+ ${rankIcon(rank_icon, rank?.level)}
`;
diff --git a/src/cards/types.d.ts b/src/cards/types.d.ts
index a3abc23e98a36..02a41b5769387 100644
--- a/src/cards/types.d.ts
+++ b/src/cards/types.d.ts
@@ -1,4 +1,5 @@
type ThemeNames = keyof typeof import("../../themes/index.js");
+type RankIcon = "default" | "github";
export type CommonOptions = {
title_color: string;
@@ -23,6 +24,9 @@ export type StatCardOptions = CommonOptions & {
custom_title: string;
disable_animations: boolean;
number_format: string;
+ ring_color: string;
+ text_bold: boolean;
+ rank_icon: RankIcon;
};
export type RepoCardOptions = CommonOptions & {
diff --git a/src/common/icons.js b/src/common/icons.js
index 5282a93ec8725..948ca0bc427d1 100644
--- a/src/common/icons.js
+++ b/src/common/icons.js
@@ -8,5 +8,28 @@ const icons = {
fork: ``,
};
-export { icons };
+/**
+ * Get rank icon
+ *
+ * @returns {string} - The SVG code of the rank icon
+ */
+const rankIcon = (rankIcon, rankLevel) => {
+ switch (rankIcon) {
+ case "github":
+ return `
+
+
+
+ `;
+ case "default":
+ default:
+ return `
+
+ ${rankLevel}
+
+ `;
+ }
+};
+
+export { icons, rankIcon };
export default icons;
diff --git a/tests/renderStatsCard.test.js b/tests/renderStatsCard.test.js
index 110121ac9e4b6..25c5feb604864 100644
--- a/tests/renderStatsCard.test.js
+++ b/tests/renderStatsCard.test.js
@@ -366,4 +366,21 @@ describe("Test renderStatsCard", () => {
document.body.innerHTML = renderStatsCard(stats, { number_format: "long" });
expect(getByTestId(document.body, "commits").textContent).toBe("1999");
});
+
+ it("should render default rank icon with level A+", () => {
+ document.body.innerHTML = renderStatsCard(stats, {
+ rank_icon: "default",
+ });
+ expect(queryByTestId(document.body, "level-rank-icon")).toBeDefined();
+ expect(
+ queryByTestId(document.body, "level-rank-icon").textContent.trim(),
+ ).toBe("A+");
+ });
+
+ it("should render github rank icon", () => {
+ document.body.innerHTML = renderStatsCard(stats, {
+ rank_icon: "github",
+ });
+ expect(queryByTestId(document.body, "github-rank-icon")).toBeDefined();
+ });
});
From aec73d293ec6a8523b8889811d2e38f4cd3bc261 Mon Sep 17 00:00:00 2001
From: LOKESH SINGH <77314004+LokeshXs@users.noreply.github.com>
Date: Mon, 24 Apr 2023 23:54:05 +0530
Subject: [PATCH 144/157] Updated the custom error there was a Typo. (#2618)
"Something went while trying to retrieve the stats data using the GraphQL API." -> "Something went wrong while trying to retrieve the stats data using the GraphQL API."
---
src/fetchers/stats-fetcher.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/fetchers/stats-fetcher.js b/src/fetchers/stats-fetcher.js
index a7df1e504db2f..fc06fce15fa86 100644
--- a/src/fetchers/stats-fetcher.js
+++ b/src/fetchers/stats-fetcher.js
@@ -213,7 +213,7 @@ const fetchStats = async (
);
}
throw new CustomError(
- "Something went while trying to retrieve the stats data using the GraphQL API.",
+ "Something went wrong while trying to retrieve the stats data using the GraphQL API.",
CustomError.GRAPHQL_ERROR,
);
}
From be0d96615d9ae3cf4b4fc6cc07921ddca7efae11 Mon Sep 17 00:00:00 2001
From: Alexandr Garbuzov <53787217+qwerty541@users.noreply.github.com>
Date: Mon, 24 Apr 2023 21:24:41 +0300
Subject: [PATCH 145/157] Fix typos inside wakatime test name (#2617)
---
tests/renderWakatimeCard.test.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/renderWakatimeCard.test.js b/tests/renderWakatimeCard.test.js
index 67969bef50063..25e7ab4d802cd 100644
--- a/tests/renderWakatimeCard.test.js
+++ b/tests/renderWakatimeCard.test.js
@@ -55,7 +55,7 @@ describe("Test Render Wakatime Card", () => {
expect(document.querySelector("rect")).toHaveAttribute("rx", "4.5");
});
- it('should show "no coding activitiy this week" message when there hasn not been activity', () => {
+ it('should show "no coding activity this week" message when there has not been activity', () => {
document.body.innerHTML = renderWakatimeCard(
{
...wakaTimeData.data,
From da5f82ff02c203a493abd1778715f0f498f7c37d Mon Sep 17 00:00:00 2001
From: Alexandr Garbuzov <53787217+qwerty541@users.noreply.github.com>
Date: Tue, 25 Apr 2023 09:15:16 +0300
Subject: [PATCH 146/157] removed redundant comparison (#957)
---
src/cards/stats-card.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/cards/stats-card.js b/src/cards/stats-card.js
index cdb468d301f78..92701d8103c95 100644
--- a/src/cards/stats-card.js
+++ b/src/cards/stats-card.js
@@ -183,7 +183,7 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
"nl",
"zh-tw",
];
- const isLongLocale = longLocales.includes(locale) === true;
+ const isLongLocale = longLocales.includes(locale);
// filter out hidden stats defined by user & create the text nodes
const statItems = Object.keys(STATS)
From 8aacec098ba92e697c9ec3b5b1b67657bfaf366e Mon Sep 17 00:00:00 2001
From: Alexandr Garbuzov <53787217+qwerty541@users.noreply.github.com>
Date: Tue, 25 Apr 2023 09:16:37 +0300
Subject: [PATCH 147/157] dev (#1782)
---
docs/readme_cn.md | 2 ++
docs/readme_de.md | 2 ++
docs/readme_fr.md | 2 ++
docs/readme_it.md | 2 ++
docs/readme_ja.md | 2 ++
docs/readme_kr.md | 2 ++
docs/readme_nl.md | 2 ++
docs/readme_np.md | 4 ++++
8 files changed, 18 insertions(+)
diff --git a/docs/readme_cn.md b/docs/readme_cn.md
index 17fd2b710f220..f04324c9f4452 100644
--- a/docs/readme_cn.md
+++ b/docs/readme_cn.md
@@ -53,6 +53,8 @@
Nederlands
.
नेपाली
+ .
+ Türkçe
喜欢这个项目?请考虑捐赠来帮助它完善!
diff --git a/docs/readme_de.md b/docs/readme_de.md
index 55523fe342ef0..87f68faa7465a 100644
--- a/docs/readme_de.md
+++ b/docs/readme_de.md
@@ -54,6 +54,8 @@
Nederlands
.
नेपाली
+ .
+ Türkçe
Du magst das Projekt? Wie wäre es mit einer kleinen Spende um es weiterhin am Leben zu erhalten?
diff --git a/docs/readme_fr.md b/docs/readme_fr.md
index 20996bd66dda8..bf0ab9811b4b0 100644
--- a/docs/readme_fr.md
+++ b/docs/readme_fr.md
@@ -53,6 +53,8 @@
Nederlands
.
नेपाली
+ .
+ Türkçe
Vous aimez ce projet? Pensez à faire un don pour l'améliorer!
diff --git a/docs/readme_it.md b/docs/readme_it.md
index 1b2df96a5044d..05aa3e5c526ae 100644
--- a/docs/readme_it.md
+++ b/docs/readme_it.md
@@ -53,6 +53,8 @@
Nederlands
.
नेपाली
+ .
+ Türkçe
Se ti piace questo progetto, considera la possibilità di donare per aiutare a renderlo migliore!
diff --git a/docs/readme_ja.md b/docs/readme_ja.md
index b00c77a7712a1..0318984e40b97 100644
--- a/docs/readme_ja.md
+++ b/docs/readme_ja.md
@@ -53,6 +53,8 @@
Nederlands
.
नेपाली
+ .
+ Türkçe
diff --git a/docs/readme_kr.md b/docs/readme_kr.md
index ce0b4ad0379ee..1d64d50d2c0b7 100644
--- a/docs/readme_kr.md
+++ b/docs/readme_kr.md
@@ -53,6 +53,8 @@
Nederlands
.
नेपाली
+ .
+ Türkçe
기능들이 마음에 드시나요? 괜찮으시다면, 서비스 개선을 위해 기부를 고려해주세요!
diff --git a/docs/readme_nl.md b/docs/readme_nl.md
index 597f0c86445e3..bab581762572c 100644
--- a/docs/readme_nl.md
+++ b/docs/readme_nl.md
@@ -53,6 +53,8 @@
Nederlands
.
नेपाली
+ .
+ Türkçe
Bevalt het project? Doneer om het te verbeteren!
diff --git a/docs/readme_np.md b/docs/readme_np.md
index 654427fbda654..510e836f2d8b6 100644
--- a/docs/readme_np.md
+++ b/docs/readme_np.md
@@ -49,8 +49,12 @@
Italiano
·
한국어
+ .
+ Nederlands
·
नेपाली
+ .
+ Türkçe
परियोजना मनपर्यो? तपाईं मद्दत गर्न सक्नुहुन्छ यो परियोजना बढ्न
From 21a9ba4faeae5072f5c46009ab2f11bc3258508b Mon Sep 17 00:00:00 2001
From: Alexandr Garbuzov <53787217+qwerty541@users.noreply.github.com>
Date: Tue, 25 Apr 2023 09:17:10 +0300
Subject: [PATCH 148/157] fix path to powered by vercel image (#1792)
---
docs/readme_tr.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/readme_tr.md b/docs/readme_tr.md
index 7b11cf3706f1e..4e67c7ed00f13 100644
--- a/docs/readme_tr.md
+++ b/docs/readme_tr.md
@@ -409,7 +409,7 @@ Teşekkürler! :heart:
---
-[![https://vercel.com?utm_source=github_readme_stats_team&utm_campaign=oss](./powered-by-vercel.svg)](https://vercel.com?utm_source=github_readme_stats_team&utm_campaign=oss)
+[![https://vercel.com?utm_source=github_readme_stats_team&utm_campaign=oss](../powered-by-vercel.svg)](https://vercel.com?utm_source=github_readme_stats_team&utm_campaign=oss)
Katkılara açığız! <3
From da46a5093cd0f6c4a537196cb9e67865bbbe3aed Mon Sep 17 00:00:00 2001
From: Alexandr Garbuzov <53787217+qwerty541@users.noreply.github.com>
Date: Tue, 25 Apr 2023 09:17:50 +0300
Subject: [PATCH 149/157] Synchonize cache seconds min value inside docs
translations with main readme (#2616)
---
docs/readme_cn.md | 2 +-
docs/readme_de.md | 2 +-
docs/readme_es.md | 2 +-
docs/readme_fr.md | 2 +-
docs/readme_it.md | 2 +-
docs/readme_ja.md | 2 +-
docs/readme_kr.md | 2 +-
docs/readme_nl.md | 2 +-
docs/readme_np.md | 2 +-
docs/readme_pt-BR.md | 2 +-
docs/readme_tr.md | 2 +-
11 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/docs/readme_cn.md b/docs/readme_cn.md
index f04324c9f4452..d6487b6618264 100644
--- a/docs/readme_cn.md
+++ b/docs/readme_cn.md
@@ -140,7 +140,7 @@ dark, radical, merko, gruvbox, tokyonight, onedark, cobalt, synthwave, highcontr
- `bg_color` - 卡片背景颜色 _(十六进制色码)_ **或者** 以 _angle,start,end_ 的形式渐变
- `hide_border` - 隐藏卡的边框 _(布尔值)_
- `theme` - 主题名称,从[所有可用主题](../themes/README.md)中选择
-- `cache_seconds` - 手动设置缓存头 _(最小值: 1800,最大值: 86400)_
+- `cache_seconds` - 手动设置缓存头 _(最小值: 14400,最大值: 86400)_
- `locale` - 在卡片中设置语言 _(例如 cn, de, es, 等等)_
##### bg_color 渐变
diff --git a/docs/readme_de.md b/docs/readme_de.md
index 87f68faa7465a..8756670eaf4b9 100644
--- a/docs/readme_de.md
+++ b/docs/readme_de.md
@@ -130,7 +130,7 @@ Du kannst das Erscheinungsbild deiner `Stats Card` oder `Repo Card`, mithilfe vo
- `bg_color` - Hintergrundfarbe _(hex color)_ **oder** ein Farbverlauf in der Form von _winkel,start,ende_
- `hide_border` - Blendet den Rand der Karte aus _(Boolean)_
- `theme` - Name des Erscheinungsbildes/Themes [alle verfügbaren Themes](../themes/README.md)
-- `cache_seconds` - manuelles festlegen der Cachezeiten _(min: 1800, max: 86400)_
+- `cache_seconds` - manuelles festlegen der Cachezeiten _(min: 14400, max: 86400)_
- `locale` - Stellen Sie die Sprache auf der Karte ein _(z.B. cn, de, es, etc.)_
##### Farbverlauf in bg_color
diff --git a/docs/readme_es.md b/docs/readme_es.md
index 5ddceec7b5e99..b477e5c729cab 100644
--- a/docs/readme_es.md
+++ b/docs/readme_es.md
@@ -142,7 +142,7 @@ Puedes personalizar el aspecto de tu `Tarjeta de Estadísticas` o `Tarjeta de Re
- `bg_color` - Color de fondo _(hex color)_
- `hide_border` - Oculta el borde de la tarjeta _(booleano)_
- `theme` - Nombre del tema, elige uno de [todos los temas disponible ](../themes/README.md)
-- `cache_seconds` - Cache _(min: 1800, max: 86400)_
+- `cache_seconds` - Cache _(min: 14400, max: 86400)_
- `locale` - configurar el idioma en la tarjeta _(p.ej. cn, de, es, etc.)_
##### Gradiente en `bg_color`
diff --git a/docs/readme_fr.md b/docs/readme_fr.md
index bf0ab9811b4b0..ce0d3d495cc10 100644
--- a/docs/readme_fr.md
+++ b/docs/readme_fr.md
@@ -140,7 +140,7 @@ Vous pouvez personnaliser l'apparence de votre `Carte des stats` ou `Carte de d
- `bg_color` - Couleur du fond de la carte _(hex color)_ **ou** un gradiant de la forme _angle,start,end_
- `hide_border` - Cache la bordure de la carte _(booléen)_
- `theme` - Nom du thème, parmis [tous les thèmes disponibles](../themes/README.md)
-- `cache_seconds` - Paramétrer le cache manuellement _(min: 1800, max: 86400)_
+- `cache_seconds` - Paramétrer le cache manuellement _(min: 14400, max: 86400)_
- `locale` - définir la langue de la carte _(par exemple. cn, de, es, etc.)_
##### Gradient in bg_color
diff --git a/docs/readme_it.md b/docs/readme_it.md
index 05aa3e5c526ae..e54af7dc488ad 100644
--- a/docs/readme_it.md
+++ b/docs/readme_it.md
@@ -140,7 +140,7 @@ Puoi personalizzare l'aspetto delle tue `Stats Card` o delle `Repo Card` in qual
- `bg_color` - Colore dello sfondo _(in esadecimale)_ **oppure** un gradiente nella forma _angolo,inizio,fine_
- `hide_border` - Nasconde il bordo della carta _(booleano)_
- `theme` - Nome del tema, dai un'occhiata a [tutti i temi disponibili](../themes/README.md)
-- `cache_seconds` - Specifica manualmente il valore di cache, in secondi _(min: 1800, max: 86400)_
+- `cache_seconds` - Specifica manualmente il valore di cache, in secondi _(min: 14400, max: 86400)_
- `locale` - Impostare la lingua nella scheda _(per esempio. cn, de, es, eccetera.)_
##### Gradiente nello sfondo
diff --git a/docs/readme_ja.md b/docs/readme_ja.md
index 0318984e40b97..2c2def7fca1a6 100644
--- a/docs/readme_ja.md
+++ b/docs/readme_ja.md
@@ -141,7 +141,7 @@ dark, radical, merko, gruvbox, tokyonight, onedark, cobalt, synthwave, highcontr
- `bg_color` - 背景の色 _(16 進数カラーコード)_ **または** _angle,start,end_ の形式でグラデーションを指定することも可
- `hide_border` - カードの境界線を非表示にします _(ブール値)_
- `theme` - [使用可能なテーマ一覧](../themes/README.md) から選んだテーマ名
-- `cache_seconds` - キャッシュ時間の秒数 _(最小値: 1800, 最大値: 86400)_
+- `cache_seconds` - キャッシュ時間の秒数 _(最小値: 14400, 最大値: 86400)_
- `locale` - カードに言語を設定する _(例えば cn, de, es, 等)_
##### bg_color の グラデーション指定
diff --git a/docs/readme_kr.md b/docs/readme_kr.md
index 1d64d50d2c0b7..4a1c57cc1e977 100644
--- a/docs/readme_kr.md
+++ b/docs/readme_kr.md
@@ -151,7 +151,7 @@ dark, radical, merko, gruvbox, tokyonight, onedark, cobalt, synthwave, highcontr
- `bg_color` - 카드의 배경 색상 _(hex color)_ **혹은** 다음 양식으로 그라데이션 주기 _angle,start,end_
- `hide_border` - 카드의 테두리 표시 여부 _(boolean)_
- `theme` - 테마의 이름, [사용 가능한 모든 테마](../themes/README.md) 에서 선택
-- `cache_seconds` - 수동으로 캐시 헤더 설정 _(min: 1800, max: 86400)_
+- `cache_seconds` - 수동으로 캐시 헤더 설정 _(min: 14400, max: 86400)_
- `locale` - 카드에 표시할 언어 _(e.g. kr, cn, de, es, etc.)_
##### 배경에 그라데이션 주기
diff --git a/docs/readme_nl.md b/docs/readme_nl.md
index bab581762572c..b279c4f71fff4 100644
--- a/docs/readme_nl.md
+++ b/docs/readme_nl.md
@@ -144,7 +144,7 @@ Je kan het uiterlijk van je `Statistieken kaart` of `Repo kaart` aanpassen hoe j
- `bg_color` - Achtergrond kleur van de kaart _(hex kleur)_ **of** een verloop van kleuren in het formaat van _graden,start,einde_
- `hide_border` - Verbergt de rand van de kaart _(boolean)_
- `theme` - Naam van het thema, kies uit [alle beschikbare thema\'s](../themes/README.md)
-- `cache_seconds` - Stel de cache header handmatig in _(min: 1800, max: 86400)_
+- `cache_seconds` - Stel de cache header handmatig in _(min: 14400, max: 86400)_
- `locale` - Stel taal van de kaart in _(e.g. cn, de, es, etc.)_
##### Kleurenverloop in bg_color (achtergrond kleur):
diff --git a/docs/readme_np.md b/docs/readme_np.md
index 510e836f2d8b6..e90ee57bfe6b3 100644
--- a/docs/readme_np.md
+++ b/docs/readme_np.md
@@ -142,7 +142,7 @@ dark, radical, merko, gruvbox, tokyonight, onedark, cobalt, synthwave, highcontr
- `bg_color` - Card's background color _(hex color)_ **or** a gradient in the form of _angle,start,end_
- `hide_border` - Hides the card's border _(boolean)_
- `theme` - name of the theme, choose from [all available themes](./themes/README.md)
-- `cache_seconds` - set the cache header manually _(min: 1800, max: 86400)_
+- `cache_seconds` - set the cache header manually _(min: 14400, max: 86400)_
- `locale` - set the language in the card _(e.g. cn, de, es, etc.)_
##### Gradient in bg_color
diff --git a/docs/readme_pt-BR.md b/docs/readme_pt-BR.md
index 62c23dc55c7e2..1ac57716009be 100644
--- a/docs/readme_pt-BR.md
+++ b/docs/readme_pt-BR.md
@@ -141,7 +141,7 @@ Personalize a aparência do seu `Stats Card` ou `Repo Card` da maneira que desej
- `bg_color` - Cor de fundo do cartão _(hex color)_
- `hide_border` - Esconde a borda do cartão _(boleano)_
- `theme` - Nome do tema, escolha em [todos os temas disponíveis](../themes/README.md)
-- `cache_seconds` - Defina o cabeçalho do cache manualmente _(min: 1800, max: 86400)_
+- `cache_seconds` - Defina o cabeçalho do cache manualmente _(min: 14400, max: 86400)_
- `locale` - defina o idioma no cartão _(por exemplo. cn, de, es, etc.)_
> Nota sobre o cache: Cartões de repositório tem um cache padrão de 30 minutos (1800 segundos), se o número a contagem de forks e contagem de estrelas é menor que 1 mil o padrão é 2 horas (7200 segundos). Note também que o cache é limitado a um mínimo de 30 minutos e um máximo de 24 horas.
diff --git a/docs/readme_tr.md b/docs/readme_tr.md
index 4e67c7ed00f13..d8ae9778fb50c 100644
--- a/docs/readme_tr.md
+++ b/docs/readme_tr.md
@@ -143,7 +143,7 @@ dark, radical, merko, gruvbox, tokyonight, onedark, cobalt, synthwave, highcontr
- `bg_color` - Kartın arkaplan rengi _(hex color / hex rengi)_ **ya da** gradient şeklinde _açı,başlangıç,bitiş_
- `hide_border` - Kartın çerçevelerini gizler _(boolean)_
- `theme` - Temanın rengi [tüm temalar](./themes/README.md)
-- `cache_seconds` - Manuel olarak cache'i belirleyebilirsiniz _(en az: 1800, en fazla: 86400)_
+- `cache_seconds` - Manuel olarak cache'i belirleyebilirsiniz _(en az: 14400, en fazla: 86400)_
- `locale` - Karttaki dili seçebilirsiniz _(örneğin; tr, cn, de, es, vb.)_
##### bg_color'da Gradient
From 5577bbf07fae7f0e2fcbed24042a59e5442434dc Mon Sep 17 00:00:00 2001
From: kitswas <90329875+kitswas@users.noreply.github.com>
Date: Tue, 25 Apr 2023 11:49:05 +0530
Subject: [PATCH 150/157] New top language algorithm implementation (#1732)
* Reduced vercel maxDuration
* Implemented new algorithm for Top Langs
* Revert "Reduced vercel maxDuration"
This reverts commit b0bc626efe12c738cf5005e7f11c7d2a07b6387a.
* Added documentation
* Fixed broken implementation
* Update fetchTopLanguages.test.js
Changed tests
* Now uses the general formula
The parameters p and q can be set by the user.
* Updated tests and added new test
* Added new test
New test for order by repo count.
* Updated documentation
Added explanation and examples for new options.
* Updated documentation
This was overwritten in the merge commit.
* docs: improve docs and fix tests
* Renamed parameters
Renamed `p` and `q` to `size_weight` and `count_weight`, respectively.
* Updated the documentation
Changes introduced in f2516d60a442dfdbb9e24ddda8743664bcb8064d
---------
Co-authored-by: rickstaa
---
api/top-langs.js | 4 +++
readme.md | 40 +++++++++++++++------
src/fetchers/top-languages-fetcher.js | 24 +++++++++++--
tests/fetchTopLanguages.test.js | 52 ++++++++++++++++++++++++---
4 files changed, 104 insertions(+), 16 deletions(-)
diff --git a/api/top-langs.js b/api/top-langs.js
index e67d953323441..cde0a9af08a93 100644
--- a/api/top-langs.js
+++ b/api/top-langs.js
@@ -25,6 +25,8 @@ export default async (req, res) => {
layout,
langs_count,
exclude_repo,
+ size_weight,
+ count_weight,
custom_title,
locale,
border_radius,
@@ -46,6 +48,8 @@ export default async (req, res) => {
const topLangs = await fetchTopLanguages(
username,
parseArray(exclude_repo),
+ size_weight,
+ count_weight,
);
const cacheSeconds = clampValue(
diff --git a/readme.md b/readme.md
index fe04a88e81bba..76b46e0eaefb5 100644
--- a/readme.md
+++ b/readme.md
@@ -310,6 +310,8 @@ You can provide multiple comma-separated values in the bg_color option to render
- `custom_title` - Sets a custom title for the card _(string)_. Default `Most Used Languages`.
- `disable_animations` - Disables all animations in the card _(boolean)_. Default: `false`.
- `hide_progress` - It uses the compact layout option, hides percentages, and removes the bars. Default: `false`.
+- `size_weight` - Configures language stats algorithm _(number)_ (see [Language stats algorithm](#Language-stats-algorithm)), defaults to 1.
+- `count_weight` - Configures language stats algorithm _(number)_ (see [Language stats algorithm](#Language-stats-algorithm)), defaults to 0.
> **Warning**
> Language names should be URI-escaped, as specified in [Percent Encoding](https://en.wikipedia.org/wiki/Percent-encoding)
@@ -359,7 +361,25 @@ Use [show_owner](#customization) variable to include the repo's owner username
The top languages card shows a GitHub user's most frequently used top language.
> **Note**
-> Top Languages does not indicate my skill level or anything like that; it's a GitHub metric to determine which languages have the most code on GitHub. It is a new feature of github-readme-stats.
+> Top Languages does not indicate the user's skill level or anything like that; it's a GitHub metric to determine which languages have the most code on GitHub. It is a new feature of github-readme-stats.
+
+### Language stats algorithm
+
+We use the following algorithm to calculate the languages percentages on the language card:
+
+```js
+ranking_index = (byte_count ^ size_weight) * (repo_count ^ count_weight)
+```
+
+By default, only the byte count is used for determining the languages percentages shown on the language card (i.e. `size_weight=1` and `count_weight=0`). You can, however, use the `&size_weight=` and `&count_weight=` options to weight the language usage calculation. The values must be positive real numbers. [More details about the algorithm can be found here](https://github.com/anuraghazra/github-readme-stats/issues/1600#issuecomment-1046056305).
+
+- `&size_weight=1&count_weight=0` - _(default)_ Orders by byte count.
+- `&size_weight=0.5&count_weight=0.5` - _(recommended)_ Uses both byte and repo count for ranking
+- `&size_weight=0&count_weight=1` - Orders by repo count
+
+```md
+[![Top Langs](https://github-readme-stats.vercel.app/api/top-langs/?username=anuraghazra&size_weight=0.5&count_weight=0.5)](https://github.com/anuraghazra/github-readme-stats)
+```
### Usage
@@ -419,7 +439,7 @@ You can use the `&hide_progress=true` option to hide the percentages and the pro
[![Top Langs](https://github-readme-stats.vercel.app/api/top-langs/?username=anuraghazra&layout=compact)](https://github.com/anuraghazra/github-readme-stats)
-- Hidden progress bars
+- Hidden progress bars
[![Top Langs](https://github-readme-stats.vercel.app/api/top-langs/?username=anuraghazra&hide_progress=true)](https://github.com/anuraghazra/github-readme-stats)
@@ -564,14 +584,14 @@ Since the GitHub API only allows 5k requests per hour, my `https://github-readme
:hammer_and_wrench: Step-by-step guide for deploying on other platforms
-1. Fork or clone this repo as per your needs
-2. Add `express` to the dependencies section of `package.json`
-https://github.com/anuraghazra/github-readme-stats/blob/ba7c2f8b55eac8452e479c8bd38b044d204d0424/package.json#L54-L61
-3. Run `npm i` if needed (initial setup)
-4. Run `node express.js` to start the server, or set the entry point to `express.js` in `package.json` if you're deploying on a managed service
-https://github.com/anuraghazra/github-readme-stats/blob/ba7c2f8b55eac8452e479c8bd38b044d204d0424/package.json#L11
-5. You're done 🎉
-
+1. Fork or clone this repo as per your needs
+2. Add `express` to the dependencies section of `package.json`
+
+3. Run `npm i` if needed (initial setup)
+4. Run `node express.js` to start the server, or set the entry point to `express.js` in `package.json` if you're deploying on a managed service
+
+5. You're done 🎉
+
### Keep your fork up to date
diff --git a/src/fetchers/top-languages-fetcher.js b/src/fetchers/top-languages-fetcher.js
index 86d794435be08..45b2ba7d85183 100644
--- a/src/fetchers/top-languages-fetcher.js
+++ b/src/fetchers/top-languages-fetcher.js
@@ -54,7 +54,12 @@ const fetcher = (variables, token) => {
* @param {string[]} exclude_repo List of repositories to exclude.
* @returns {Promise} Top languages data.
*/
-const fetchTopLanguages = async (username, exclude_repo = []) => {
+const fetchTopLanguages = async (
+ username,
+ exclude_repo = [],
+ size_weight = 1,
+ count_weight = 0,
+) => {
if (!username) throw new MissingParamError(["username"]);
const res = await retryer(fetcher, { login: username });
@@ -101,6 +106,8 @@ const fetchTopLanguages = async (username, exclude_repo = []) => {
.sort((a, b) => b.size - a.size)
.filter((name) => !repoToHide[name.name]);
+ let repoCount = 0;
+
repoNodes = repoNodes
.filter((node) => node.languages.edges.length > 0)
// flatten the list of language nodes
@@ -111,9 +118,14 @@ const fetchTopLanguages = async (username, exclude_repo = []) => {
// if we already have the language in the accumulator
// & the current language name is same as previous name
- // add the size to the language size.
+ // add the size to the language size and increase repoCount.
if (acc[prev.node.name] && prev.node.name === acc[prev.node.name].name) {
langSize = prev.size + acc[prev.node.name].size;
+ repoCount += 1;
+ } else {
+ // reset repoCount to 1
+ // language must exist in at least one repo to be detected
+ repoCount = 1;
}
return {
...acc,
@@ -121,10 +133,18 @@ const fetchTopLanguages = async (username, exclude_repo = []) => {
name: prev.node.name,
color: prev.node.color,
size: langSize,
+ count: repoCount,
},
};
}, {});
+ Object.keys(repoNodes).forEach((name) => {
+ // comparison index calculation
+ repoNodes[name].size =
+ Math.pow(repoNodes[name].size, size_weight) *
+ Math.pow(repoNodes[name].count, count_weight);
+ });
+
const topLangs = Object.keys(repoNodes)
.sort((a, b) => repoNodes[b].size - repoNodes[a].size)
.reduce((result, key) => {
diff --git a/tests/fetchTopLanguages.test.js b/tests/fetchTopLanguages.test.js
index 24416cd294525..c3f558bf4236f 100644
--- a/tests/fetchTopLanguages.test.js
+++ b/tests/fetchTopLanguages.test.js
@@ -60,20 +60,22 @@ const error = {
};
describe("FetchTopLanguages", () => {
- it("should fetch correct language data", async () => {
+ it("should fetch correct language data while using the new calculation", async () => {
mock.onPost("https://api.github.com/graphql").reply(200, data_langs);
- let repo = await fetchTopLanguages("anuraghazra");
+ let repo = await fetchTopLanguages("anuraghazra", [], 0.5, 0.5);
expect(repo).toStrictEqual({
HTML: {
color: "#0f0",
+ count: 2,
name: "HTML",
- size: 200,
+ size: 20.000000000000004,
},
javascript: {
color: "#0ff",
+ count: 2,
name: "javascript",
- size: 200,
+ size: 20.000000000000004,
},
});
});
@@ -85,17 +87,59 @@ describe("FetchTopLanguages", () => {
expect(repo).toStrictEqual({
HTML: {
color: "#0f0",
+ count: 1,
name: "HTML",
size: 100,
},
javascript: {
color: "#0ff",
+ count: 2,
+ name: "javascript",
+ size: 200,
+ },
+ });
+ });
+
+ it("should fetch correct language data while using the old calculation", async () => {
+ mock.onPost("https://api.github.com/graphql").reply(200, data_langs);
+
+ let repo = await fetchTopLanguages("anuraghazra", [], 1, 0);
+ expect(repo).toStrictEqual({
+ HTML: {
+ color: "#0f0",
+ count: 2,
+ name: "HTML",
+ size: 200,
+ },
+ javascript: {
+ color: "#0ff",
+ count: 2,
name: "javascript",
size: 200,
},
});
});
+ it("should rank languages by the number of repositories they appear in", async () => {
+ mock.onPost("https://api.github.com/graphql").reply(200, data_langs);
+
+ let repo = await fetchTopLanguages("anuraghazra", [], 0, 1);
+ expect(repo).toStrictEqual({
+ HTML: {
+ color: "#0f0",
+ count: 2,
+ name: "HTML",
+ size: 2,
+ },
+ javascript: {
+ color: "#0ff",
+ count: 2,
+ name: "javascript",
+ size: 2,
+ },
+ });
+ });
+
it("should throw error", async () => {
mock.onPost("https://api.github.com/graphql").reply(200, error);
From f5f0a79bc12a35c58609f3fa6ced2f6722bbfdf1 Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Fri, 28 Apr 2023 04:00:13 +0200
Subject: [PATCH 151/157] feat: improve CONTRIBUTING.md (#2609)
---
CONTRIBUTING.md | 20 ++++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 0d4b558abe6f1..7d450d6076d8e 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -2,11 +2,11 @@
We love your input! We want to make contributing to this project as easy and transparent as possible, whether it's:
-- Reporting an issue
-- Discussing the current state of the code
-- Submitting a fix
-- Proposing new features
-- Becoming a maintainer
+- Reporting [an issue](https://github.com/anuraghazra/github-readme-stats/issues/new?assignees=&labels=bug&template=bug_report.yml).
+- [Discussing](https://github.com/anuraghazra/github-readme-stats/discussions) the current state of the code.
+- Submitting [a fix](https://github.com/anuraghazra/github-readme-stats/compare).
+- Proposing [new features](https://github.com/anuraghazra/github-readme-stats/issues/new?assignees=&labels=enhancement&template=feature_request.yml).
+- Becoming a maintainer.
## All Changes Happen Through Pull Requests
@@ -33,11 +33,15 @@ _(make sure you already have a [Vercel](https://vercel.com/) account)_
1. Install [Vercel CLI](https://vercel.com/download).
2. Fork the repository and clone the code to your local machine.
3. Run `npm install` in the repository root.
-4. Run the command "vercel" in the root and follow the steps there.
+4. Run the command `vercel` in the root and follow the steps there.
5. Open `vercel.json` and set the maxDuration to 10.
6. Create a `.env` file in the root of the directory.
-7. In the .env file add a new variable named "PAT_1" with your [GitHub Personal Access Token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token).
-8. Run the command "vercel dev" to start a development server at .
+7. In the .env file add a new variable named `PAT_1` with your [GitHub Personal Access Token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token).
+8. Run the command `vercel dev` to start a development server at .
+9. The cards will then be available from this local endpoint (i.e. `https://localhost:3000/api?username=anuraghazra`).
+
+> **Note**
+> You can also debug any tests using the [VSCode Jest extension](https://marketplace.visualstudio.com/items?itemName=Orta.vscode-jest). For more information see https://github.com/jest-community/vscode-jest/issues/912.
## Themes Contribution
From fd64333211fa9f39f59028fcb3892d2cf2fbb57a Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Fri, 28 Apr 2023 04:00:33 +0200
Subject: [PATCH 152/157] docs: update give logo (#2605)
---
readme.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/readme.md b/readme.md
index 76b46e0eaefb5..6b4cefdf84116 100644
--- a/readme.md
+++ b/readme.md
@@ -66,7 +66,7 @@
Love the project? Please consider donating to help it improve!
-
+
Are you considering supporting the project by donating? Please DO NOT!!
From 30a45d3c136033a0459d0c0423a4836d78e8b0e7 Mon Sep 17 00:00:00 2001
From: Alexandr Garbuzov <53787217+qwerty541@users.noreply.github.com>
Date: Fri, 28 Apr 2023 10:50:57 +0300
Subject: [PATCH 153/157] Fixed typo in word color inside README (#2652)
---
readme.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/readme.md b/readme.md
index 6b4cefdf84116..538b4e8840646 100644
--- a/readme.md
+++ b/readme.md
@@ -183,7 +183,7 @@ We have included a `transparent` theme that has a transparent background. This t
##### Add transparent alpha channel to a themes bg_color
-You can use the `bg_color` parameter to make any of [the available themes](./themes/README.md) transparent. This is done by setting the `bg_color` to a colour with a transparent alpha channel (i.e. `bg_color=00000000`):
+You can use the `bg_color` parameter to make any of [the available themes](./themes/README.md) transparent. This is done by setting the `bg_color` to a color with a transparent alpha channel (i.e. `bg_color=00000000`):
```md
![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&bg_color=00000000)
From 6eebfe36e8406730ae13d088060eb5ea6503e1d5 Mon Sep 17 00:00:00 2001
From: Alexandr Garbuzov <53787217+qwerty541@users.noreply.github.com>
Date: Fri, 28 Apr 2023 10:51:24 +0300
Subject: [PATCH 154/157] Fixed docs typo inside src/common/utils.js (#2651)
---
src/common/utils.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/common/utils.js b/src/common/utils.js
index c600c717ae3e5..f82544604cf9c 100644
--- a/src/common/utils.js
+++ b/src/common/utils.js
@@ -392,7 +392,7 @@ const lowercaseTrim = (name) => name.toLowerCase().trim();
/**
* Split array of languages in two columns.
*
- * @template T Langauge object.
+ * @template T Language object.
* @param {Array} arr Array of languages.
* @param {number} perChunk Number of languages per column.
* @returns {Array} Array of languages split in two columns.
From a82a617a37a986c9ee7f9285190c82d106034974 Mon Sep 17 00:00:00 2001
From: Alexandr Garbuzov <53787217+qwerty541@users.noreply.github.com>
Date: Fri, 28 Apr 2023 10:51:54 +0300
Subject: [PATCH 155/157] Fixed several typos inside preview theme script
(#2650)
---
scripts/preview-theme.js | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/scripts/preview-theme.js b/scripts/preview-theme.js
index e18c01b8615af..57b792a369c95 100644
--- a/scripts/preview-theme.js
+++ b/scripts/preview-theme.js
@@ -26,9 +26,9 @@ const FAIL_TEXT = `
\rUnfortunately, your theme PR contains an error or does not adhere to our [theme guidelines](https://github.com/anuraghazra/github-readme-stats/blob/master/CONTRIBUTING.md#themes-contribution). Please fix the issues below, and we will review your\
\r PR again. This pull request will **automatically close in 20 days** if no changes are made. After this time, you must re-open the PR for it to be reviewed.
`;
-const THEME_CONTRIB_GUIDELINESS = `
+const THEME_CONTRIB_GUIDELINES = `
\rHi, thanks for the theme contribution. Please read our theme [contribution guidelines](https://github.com/anuraghazra/github-readme-stats/blob/master/CONTRIBUTING.md#themes-contribution).
- \rWe are currently only accepting color combinations from any VSCode theme or themes with good colour combinations to minimize bloating the themes collection.
+ \rWe are currently only accepting color combinations from any VSCode theme or themes with good color combinations to minimize bloating the themes collection.
\r> Also, note that if this theme is exclusively for your personal use, then instead of adding it to our theme collection, you can use card [customization options](https://github.com/anuraghazra/github-readme-stats#customization).
`;
@@ -363,7 +363,7 @@ export const run = async () => {
debug(`Context: ${inspect(github.context)}`);
let commentBody = `
\r# ${COMMENT_TITLE}
- \r${THEME_CONTRIB_GUIDELINESS}
+ \r${THEME_CONTRIB_GUIDELINES}
`;
const ccc = new ColorContrastChecker();
OCTOKIT = github.getOctokit(getGithubToken());
From 31d1ab43d0cae0ecbaba5748fb6a5ca9ae1c7609 Mon Sep 17 00:00:00 2001
From: Alexandr Garbuzov <53787217+qwerty541@users.noreply.github.com>
Date: Fri, 28 Apr 2023 18:48:34 +0300
Subject: [PATCH 156/157] Fixed todo inside stats card data fetcher (#2649)
---
src/calculateRank.js | 15 ++++++++-------
src/fetchers/stats-fetcher.js | 1 -
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/calculateRank.js b/src/calculateRank.js
index 24845bc7d9944..215c24d848c34 100644
--- a/src/calculateRank.js
+++ b/src/calculateRank.js
@@ -29,13 +29,14 @@ const normalcdf = (mean, sigma, to) => {
/**
* Calculates the users rank.
*
- * @param {number} totalRepos Total number of repos.
- * @param {number} totalCommits Total number of commits.
- * @param {number} contributions The number of contributions.
- * @param {number} followers The number of followers.
- * @param {number} prs The number of pull requests.
- * @param {number} issues The number of issues.
- * @param {number} stargazers The number of stars.
+ * @param {object} params Parameters on which the user's rank depends.
+ * @param {number} params.totalRepos Total number of repos.
+ * @param {number} params.totalCommits Total number of commits.
+ * @param {number} params.contributions The number of contributions.
+ * @param {number} params.followers The number of followers.
+ * @param {number} params.prs The number of pull requests.
+ * @param {number} params.issues The number of issues.
+ * @param {number} params.stargazers The number of stars.
* @returns {{level: string, score: number}}} The users rank.
*/
const calculateRank = ({
diff --git a/src/fetchers/stats-fetcher.js b/src/fetchers/stats-fetcher.js
index fc06fce15fa86..8603e38bbf59d 100644
--- a/src/fetchers/stats-fetcher.js
+++ b/src/fetchers/stats-fetcher.js
@@ -259,7 +259,6 @@ const fetchStats = async (
return prev + curr.stargazers.totalCount;
}, 0);
- // @ts-ignore // TODO: Fix this.
stats.rank = calculateRank({
totalCommits: stats.totalCommits,
totalRepos: user.repositories.totalCount,
From 3bd6519d39cbd6b0a078af17c2756b2804d85fb3 Mon Sep 17 00:00:00 2001
From: Rick Staa
Date: Sat, 29 Apr 2023 04:55:37 +0200
Subject: [PATCH 157/157] docs: fix README language card usage order (#2659)
---
readme.md | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/readme.md b/readme.md
index 538b4e8840646..ae18c9e6002c6 100644
--- a/readme.md
+++ b/readme.md
@@ -363,6 +363,16 @@ The top languages card shows a GitHub user's most frequently used top language.
> **Note**
> Top Languages does not indicate the user's skill level or anything like that; it's a GitHub metric to determine which languages have the most code on GitHub. It is a new feature of github-readme-stats.
+### Usage
+
+Copy-paste this code into your readme and change the links.
+
+Endpoint: `api/top-langs?username=anuraghazra`
+
+```md
+[![Top Langs](https://github-readme-stats.vercel.app/api/top-langs/?username=anuraghazra)](https://github.com/anuraghazra/github-readme-stats)
+```
+
### Language stats algorithm
We use the following algorithm to calculate the languages percentages on the language card:
@@ -381,16 +391,6 @@ By default, only the byte count is used for determining the languages percentage
[![Top Langs](https://github-readme-stats.vercel.app/api/top-langs/?username=anuraghazra&size_weight=0.5&count_weight=0.5)](https://github.com/anuraghazra/github-readme-stats)
```
-### Usage
-
-Copy-paste this code into your readme and change the links.
-
-Endpoint: `api/top-langs?username=anuraghazra`
-
-```md
-[![Top Langs](https://github-readme-stats.vercel.app/api/top-langs/?username=anuraghazra)](https://github.com/anuraghazra/github-readme-stats)
-```
-
### Exclude individual repositories
You can use the `&exclude_repo=repo1,repo2` parameter to exclude individual repositories.