From f8e32f9e0cbb8ee5d9d7ca8c896a8ef6d71a3379 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Sat, 1 Oct 2022 13:59:02 +0200 Subject: [PATCH 001/157] ci: add e2e vercel test action (#2054) * ci: add e2e vercel test action This commit adds several end-to-end tests that can be used to test whether the Vercel Preview deployment successfully returns the cards. * test: add additional e2e card tests * test: improve e2e card tests This commit makes sure that the tests also check whether a valid cards are returned from the preview deployment. --- .github/workflows/e2e-test.yml | 20 ++++ jest.config.js | 6 ++ jest.e2e.config.js | 7 ++ package-lock.json | 2 +- package.json | 3 +- tests/e2e/e2e.test.js | 173 +++++++++++++++++++++++++++++++++ 6 files changed, 209 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/e2e-test.yml create mode 100644 jest.e2e.config.js create mode 100644 tests/e2e/e2e.test.js diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml new file mode 100644 index 0000000000000..4699b67d5ba15 --- /dev/null +++ b/.github/workflows/e2e-test.yml @@ -0,0 +1,20 @@ +name: Test Deployment +on: + deployment_status: + +jobs: + preview: + if: + github.event_name == 'deployment_status' && + github.event.deployment_status.state == 'success' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install dependencies + run: npm ci + env: + CI: true + - name: Run end-to-end tests. + run: npm run test:e2e + env: + VERCEL_PREVIEW_URL: ${{ github.event.deployment_status.target_url }} diff --git a/jest.config.js b/jest.config.js index 312d88ad8e023..b4578cf5aaad5 100644 --- a/jest.config.js +++ b/jest.config.js @@ -3,4 +3,10 @@ export default { transform: {}, testEnvironment: "jsdom", coverageProvider: "v8", + testPathIgnorePatterns: ["/node_modules/", "/tests/e2e/"], + modulePathIgnorePatterns: ["/node_modules/", "/tests/e2e/"], + coveragePathIgnorePatterns: [ + "/node_modules/", + "/tests/E2E/", + ], }; diff --git a/jest.e2e.config.js b/jest.e2e.config.js new file mode 100644 index 0000000000000..656ab61f7c054 --- /dev/null +++ b/jest.e2e.config.js @@ -0,0 +1,7 @@ +export default { + clearMocks: true, + transform: {}, + testEnvironment: "node", + coverageProvider: "v8", + testMatch: ["/tests/e2e/**/*.test.js"], +}; diff --git a/package-lock.json b/package-lock.json index 2ffe6ec9008b2..2235a4b45ac63 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "word-wrap": "^1.2.3" }, "devDependencies": { - "@actions/core": "^1.2.4", + "@actions/core": "^1.9.1", "@actions/github": "^4.0.0", "@testing-library/dom": "^8.17.1", "@testing-library/jest-dom": "^5.16.5", diff --git a/package.json b/package.json index c256229340145..b1bce12bfe7bc 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --coverage", "test:watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch", "test:update:snapshot": "node --experimental-vm-modules node_modules/jest/bin/jest.js -u", + "test:e2e": "node --experimental-vm-modules node_modules/jest/bin/jest.js --config jest.e2e.config.js", "theme-readme-gen": "node scripts/generate-theme-doc", "preview-theme": "node scripts/preview-theme", "generate-langs-json": "node scripts/generate-langs-json", @@ -17,7 +18,7 @@ "author": "Anurag Hazra", "license": "MIT", "devDependencies": { - "@actions/core": "^1.2.4", + "@actions/core": "^1.9.1", "@actions/github": "^4.0.0", "@testing-library/dom": "^8.17.1", "@testing-library/jest-dom": "^5.16.5", diff --git a/tests/e2e/e2e.test.js b/tests/e2e/e2e.test.js new file mode 100644 index 0000000000000..91c9c38fe83aa --- /dev/null +++ b/tests/e2e/e2e.test.js @@ -0,0 +1,173 @@ +/** + * @file Contains end-to-end tests for the Vercel preview instance. + */ +import dotenv from "dotenv"; +dotenv.config(); + +import { describe } from "@jest/globals"; +import axios from "axios"; +import { renderRepoCard } from "../../src/cards/repo-card.js"; +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"; + +// Script variables +const REPO = "dummy-cra"; +const USER = "grsdummy"; +const STATS_DATA = { + name: "grsdummy", + totalPRs: 1, + totalCommits: 2, + totalIssues: 1, + totalStars: 1, + contributedTo: 1, + rank: { + level: "A+", + score: 51.01622937949586, + }, +}; +const LANGS_DATA = { + TypeScript: { + color: "#3178c6", + name: "TypeScript", + size: 2049, + }, + HTML: { + color: "#e34c26", + name: "HTML", + size: 1721, + }, + CSS: { + color: "#563d7c", + name: "CSS", + size: 930, + }, + Python: { + color: "#3572A5", + name: "Python", + size: 671, + }, +}; +const WAKATIME_DATA = { + human_readable_range: "last week", + is_already_updating: false, + is_coding_activity_visible: false, + is_including_today: false, + is_other_usage_visible: false, + is_stuck: false, + is_up_to_date: false, + is_up_to_date_pending_future: false, + percent_calculated: 0, + range: "last_7_days", + status: "pending_update", + timeout: 15, + username: "grsdummy", + writes_only: false, +}; +const REPOSITORY_DATA = { + name: "dummy-cra", + nameWithOwner: "grsdummy/dummy-cra", + isPrivate: false, + isArchived: false, + isTemplate: false, + stargazers: { + totalCount: 1, + }, + description: "Dummy create react app.", + primaryLanguage: { + color: "#3178c6", + id: "MDg6TGFuZ3VhZ2UyODc=", + name: "TypeScript", + }, + forkCount: 0, + starCount: 1, +}; + +describe("Fetch Cards", () => { + let VERCEL_PREVIEW_URL; + + beforeAll(() => { + process.env.NODE_ENV = "development"; + VERCEL_PREVIEW_URL = process.env.VERCEL_PREVIEW_URL; + }); + + test("retrieve stats card", async () => { + expect(VERCEL_PREVIEW_URL).toBeDefined(); + + // Check if the Vercel preview instance stats card function is up and running. + await expect( + axios.get(`${VERCEL_PREVIEW_URL}/api?username=${USER}`), + ).resolves.not.toThrow(); + + // Get local stats card. + const localStatsCardSVG = renderStatsCard(STATS_DATA); + + // Get the Vercel preview stats card response. + const serverStatsSvg = await axios.get( + `${VERCEL_PREVIEW_URL}/api?username=${USER}`, + ); + + // Check if stats card from deployment matches the stats card from local. + expect(serverStatsSvg.data).toEqual(localStatsCardSVG); + }); + + test("retrieve language card", async () => { + expect(VERCEL_PREVIEW_URL).toBeDefined(); + + // Check if the Vercel preview instance language card function is up and running. + await expect( + axios.get(`${VERCEL_PREVIEW_URL}/api/top-langs/?username=${USER}`), + ).resolves.not.toThrow(); + + // Get local language card. + const localLanguageCardSVG = renderTopLanguages(LANGS_DATA); + + // Get the Vercel preview language card response. + const severLanguageSVG = await axios.get( + `${VERCEL_PREVIEW_URL}/api/top-langs/?username=${USER}`, + ); + + // Check if language card from deployment matches the local language card. + expect(severLanguageSVG.data).toEqual(localLanguageCardSVG); + }); + + test("retrieve WakaTime card", async () => { + expect(VERCEL_PREVIEW_URL).toBeDefined(); + + // Check if the Vercel preview instance WakaTime function is up and running. + await expect( + axios.get(`${VERCEL_PREVIEW_URL}/api/wakatime?username=${USER}`), + ).resolves.not.toThrow(); + + // Get local WakaTime card. + const localWakaCardSVG = renderWakatimeCard(WAKATIME_DATA); + + // Get the Vercel preview WakaTime card response. + const serverWakaTimeSvg = await axios.get( + `${VERCEL_PREVIEW_URL}/api/wakatime?username=${USER}`, + ); + + // Check if WakaTime card from deployment matches the local WakaTime card. + expect(serverWakaTimeSvg.data).toEqual(localWakaCardSVG); + }); + + test("retrieve repo card", async () => { + expect(VERCEL_PREVIEW_URL).toBeDefined(); + + // Check if the Vercel preview instance Repo function is up and running. + await expect( + axios.get(`${VERCEL_PREVIEW_URL}/api/pin/?username=${USER}&repo=${REPO}`), + ).resolves.not.toThrow(); + + // Get local repo card. + const localRepoCardSVG = renderRepoCard(REPOSITORY_DATA); + + // Get the Vercel preview repo card response. + const serverRepoSvg = await axios.get( + `${VERCEL_PREVIEW_URL}/api/pin/?username=${USER}&repo=${REPO}`, + ); + + // Check if Repo card from deployment matches the local Repo card. + expect(serverRepoSvg.data).toEqual(localRepoCardSVG); + }); +}); From 6b7e91abb6a7c1d1266289c32d95e304c76425f5 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Sat, 1 Oct 2022 14:01:29 +0200 Subject: [PATCH 002/157] ci: improve theme-preview actiot push (#2065) This commit makes sure that: - The theme-preview action can test multiple themes. - Fails if something goes wrong. - Requests changes if the theme does not adhere to the guidelines. - Approves the PR if the theme adheres to the guidelines. --- .github/workflows/preview-theme.yml | 14 +- scripts/preview-theme.js | 625 +++++++++++++++++++++++----- 2 files changed, 520 insertions(+), 119 deletions(-) diff --git a/.github/workflows/preview-theme.yml b/.github/workflows/preview-theme.yml index db7e291daad8a..709cba4cc9071 100644 --- a/.github/workflows/preview-theme.yml +++ b/.github/workflows/preview-theme.yml @@ -2,25 +2,25 @@ name: Theme preview on: pull_request_target: - types: [opened, synchronize, reopened] + types: [opened, edited, reopened, synchronize] branches: - master - - theme_preview_script paths: - "themes/index.js" - - "scripts/preview-theme.js" jobs: - build: + previewTheme: runs-on: ubuntu-latest name: Install & Preview steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 16 - uses: bahmutov/npm-install@v1 with: useLockFile: false - run: npm run preview-theme env: - CI: true - PERSONAL_TOKEN: ${{ secrets.PERSONAL_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/scripts/preview-theme.js b/scripts/preview-theme.js index 33ee96bc2f01a..ea511a9e0268b 100644 --- a/scripts/preview-theme.js +++ b/scripts/preview-theme.js @@ -1,27 +1,111 @@ -import core from "@actions/core"; +/** + * @file This script is used to preview the theme on theme PRs. + */ +import * as dotenv from "dotenv"; +dotenv.config(); + +import core, { debug, setFailed } from "@actions/core"; import github from "@actions/github"; import ColorContrastChecker from "color-contrast-checker"; -import * as dotenv from "dotenv"; +import { info } from "console"; import Hjson from "hjson"; import snakeCase from "lodash.snakecase"; import parse from "parse-diff"; +import { inspect } from "util"; +import { themes } from "../themes/index.js"; -dotenv.config(); - +// Script variables const OWNER = "anuraghazra"; const REPO = "github-readme-stats"; +const COMMENTER = "github-actions[bot]"; + const COMMENT_TITLE = "Automated Theme Preview"; +const THEME_PR_FAIL_TEXT = ":x: Theme PR does not adhere to our guidelines."; +const THEME_PR_SUCCESS_TEXT = + ":heavy_check_mark: Theme PR does adhere to our guidelines."; +const FAIL_TEXT = ` + \rUnfortunately, your theme PR 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 15 days** if no changes are made. After this time, you must re-open the PR for it to be reviewed. +`; +const THEME_CONTRIB_GUIDELINESS = ` + \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. + + \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). +`; +const AVAILABLE_COLOR_PROPS = [ + "bg_color", + "icon_color", + "text_color", + "title_color", +]; +const INVALID_REVIEW_COMMENT = (commentUrl) => + `Some themes are invalid. See the [Automated Theme Preview](${commentUrl}) comment above for more information.`; + +/** + * Retrieve information about the repository that ran the action. + * + * @param {Object} context Action context. + * @returns {Object} Repository information. + */ +export const getRepoInfo = (ctx) => { + try { + return { + owner: ctx.repo.owner, + repo: ctx.repo.repo, + }; + } catch (error) { + return { + owner: OWNER, + repo: REPO, + }; + } +}; + +/** + * Retrieve PR number from the event payload. + * + * @returns {number} PR number. + */ +const getPrNumber = () => { + if (process.env.MOCK_PR_NUMBER) return process.env.MOCK_PR_NUMBER; // For testing purposes. -function getPrNumber() { const pullRequest = github.context.payload.pull_request; if (!pullRequest) { - return undefined; + throw Error("Could not get pull request number from context"); } - return pullRequest.number; -} - -function findCommentPredicate(inputs, comment) { +}; + +/** + * Retrieve the commenting user. + * @returns {string} Commenting user. + */ +const getCommenter = () => { + return process.env.COMMENTER ? process.env.COMMENTER : COMMENTER; +}; + +/** + * Retrieve github token and throw error if it is not found. + * + * @returns {string} Github token. + */ +const getGithubToken = () => { + const token = core.getInput("github_token") || process.env.GITHUB_TOKEN; + if (!token) { + throw Error("Could not find github token"); + } + return token; +}; + +/** + * Returns whether the comment is a preview comment. + * + * @param {Object} inputs Action inputs. + * @param {Object} comment Comment object. + * @returns {boolean} Whether the comment is a preview comment. + */ +const isPreviewComment = (inputs, comment) => { return ( (inputs.commentAuthor && comment.user ? comment.user.login === inputs.commentAuthor @@ -30,160 +114,477 @@ function findCommentPredicate(inputs, comment) { ? comment.body.includes(inputs.bodyIncludes) : true) ); -} - -async function findComment(octokit, issueNumber) { +}; + +/** + * Find the preview theme comment. + * + * @param {Object} octokit Octokit instance. + * @param {number} issueNumber Issue number. + * @param {string} repo Repository name. + * @param {string} owner Owner of the repository. + * @returns {Object} The Github comment object. + */ +const findComment = async (octokit, issueNumber, owner, repo, commenter) => { const parameters = { - owner: OWNER, - repo: REPO, + owner, + repo, issue_number: issueNumber, }; const inputs = { - commentAuthor: OWNER, + commentAuthor: commenter, bodyIncludes: COMMENT_TITLE, }; + // Search each page for the comment for await (const { data: comments } of octokit.paginate.iterator( octokit.rest.issues.listComments, parameters, )) { - // Search each page for the comment const comment = comments.find((comment) => - findCommentPredicate(inputs, comment), + isPreviewComment(inputs, comment), ); - if (comment) return comment; + if (comment) { + debug(`Found theme preview comment: ${inspect(comment)}`); + return comment; + } else { + debug(`No theme preview comment found.`); + } } -} - -async function upsertComment(octokit, props) { +}; + +/** + * Create or update the preview comment. + * + * @param {Object} octokit Octokit instance. + * @param {Object} props Comment properties. + * @return {string} The comment URL. + */ +const upsertComment = async (octokit, props) => { + let resp; if (props.comment_id !== undefined) { - await octokit.issues.updateComment(props); + resp = await octokit.issues.updateComment(props); } else { - await octokit.issues.createComment(props); + resp = await octokit.issues.createComment(props); } -} - -function getWebAimLink(color1, color2) { + return resp.data.html_url; +}; + +/** + * Adds a review to the pull request. + * + * @param {Object} octokit Octokit instance. + * @param {number} prNumber Pull request number. + * @param {string} owner Owner of the repository. + * @param {string} repo Repository name. + * @param {string} reviewState The review state. Options are (APPROVE, REQUEST_CHANGES, COMMENT, PENDING). + * @param {string} reason The reason for the review. + */ +const addReview = async ( + octokit, + prNumber, + owner, + repo, + reviewState, + reason, +) => { + await octokit.pulls.createReview({ + owner, + repo, + pull_number: prNumber, + event: reviewState, + body: reason, + }); +}; + +/** + * Add label to pull request. + * + * @param {Object} octokit Octokit instance. + * @param {number} prNumber Pull request number. + * @param {string} owner Repository owner. + * @param {string} repo Repository name. + * @param {string[]} labels Labels to add. + */ +const addLabel = async (octokit, prNumber, owner, repo, labels) => { + await octokit.issues.addLabels({ + owner, + repo, + issue_number: prNumber, + labels, + }); +}; + +/** + * Remove label from the pull request. + * + * @param {Object} octokit Octokit instance. + * @param {number} prNumber Pull request number. + * @param {string} owner Repository owner. + * @param {string} repo Repository name. + * @param {string} label Label to add or remove. + */ +const removeLabel = async (octokit, prNumber, owner, repo, label) => { + await octokit.issues.removeLabel({ + owner, + repo, + issue_number: prNumber, + name: label, + }); +}; + +/** + * Adds or removes a label from the pull request. + * + * @param {Object} octokit Octokit instance. + * @param {number} prNumber Pull request number. + * @param {string} owner Repository owner. + * @param {string} repo Repository name. + * @param {string} label Label to add or remove. + * @param {boolean} add Whether to add or remove the label. + */ +const addRemoveLabel = async (octokit, prNumber, owner, repo, label, add) => { + const res = await octokit.pulls.get({ + owner, + repo, + pull_number: prNumber, + }); + if (add) { + if (!res.data.labels.find((l) => l.name === label)) { + await addLabel(octokit, prNumber, owner, repo, [label]); + } + } else { + if (res.data.labels.find((l) => l.name === label)) { + await removeLabel(octokit, prNumber, owner, repo, label); + } + } +}; + +/** + * Retrieve webAim contrast color check link. + * + * @param {string} color1 First color. + * @param {string} color2 Second color. + * @returns {string} WebAim contrast color check link. + */ +const getWebAimLink = (color1, color2) => { return `https://webaim.org/resources/contrastchecker/?fcolor=${color1}&bcolor=${color2}`; -} - -function getGrsLink(colors) { +}; + +/** + * Retrieves the theme GRS url. + * + * @param {Object} colors The theme colors. + * @returns {string} GRS theme url. + */ +const getGRSLink = (colors) => { const url = `https://github-readme-stats.vercel.app/api?username=anuraghazra`; const colorString = Object.keys(colors) .map((colorKey) => `${colorKey}=${colors[colorKey]}`) .join("&"); return `${url}&${colorString}&show_icons=true`; -} - -const themeContribGuidelines = ` - \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 which have good color combination 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) -`; - -async function run() { +}; + +/** + * Retrieve javascript object from json string. + * + * @description Wraps the Hjson parse function to fix several known json syntax errors. + * + * @param {string} json The json to parse. + * @returns {Object} Object parsed from the json. + */ +const parseJSON = (json) => { + try { + const parsedJson = Hjson.parse(json); + if (typeof parsedJson === "object") { + return parsedJson; + } else { + throw new Error("PR diff is not a valid theme JSON object."); + } + } catch (error) { + let parsedJson = json + .split(/(?:\s*)(}\s*,?)(?:\s*)(?=\s*[a-z_"]+:+)/) + .filter((x) => typeof x !== "string" || !!x.trim()); + if (parsedJson[0].replace(/\s+/g, "") === "},") { + parsedJson[0] = "},"; + if (!/\s*}\s*,?\s*$/.test(parsedJson[0])) { + parsedJson.push(parsedJson.shift()); + } else { + parsedJson.shift(); + } + return Hjson.parse(parsedJson.join("")); + } else { + throw error; + } + } +}; + +/** + * Check if string is a valid hex color. + * + * @param {string} str String to check. + * @returns {boolean} Whether the string is a valid hex color. + */ +const isHexColor = (str, prefix = false) => { + if (prefix) { + return /^#[a-f0-9]{6}$/i.exec(str); + } else { + return /^[a-f0-9]{6}$/i.exec(str); + } +}; + +/** + * Check whether the theme name is still available. + * @param {string} name Theme name. + * @returns {boolean} Whether the theme name is available. + */ +const themeNameAlreadyExists = (name) => { + return themes[name] !== undefined; +}; + +/** + * Main function. + */ +const run = async () => { try { + const dryRun = process.env.DRY_RUN === "true" || false; + debug("Retrieve action information from context..."); + debug(`Context: ${inspect(github.context)}`); + let commentBody = ` + \r# ${COMMENT_TITLE} + \r${THEME_CONTRIB_GUIDELINESS} + `; const ccc = new ColorContrastChecker(); - const warnings = []; - const token = core.getInput("token"); - const octokit = github.getOctokit(token || process.env.PERSONAL_TOKEN); + const octokit = github.getOctokit(getGithubToken()); const pullRequestId = getPrNumber(); - - if (!pullRequestId) { - console.log("PR not found"); - return; - } - + const commenter = getCommenter(); + const { owner, repo } = getRepoInfo(github.context); + 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: OWNER, - repo: REPO, + owner, + repo, pull_number: pullRequestId, mediaType: { format: "diff", }, }); - const comment = await findComment(octokit, pullRequestId); + debug("Retrieve preview-theme comment..."); + const comment = await findComment( + octokit, + pullRequestId, + owner, + repo, + commenter, + ); + // Retrieve theme changes from the PR diff. + debug("Retrieve themes..."); const diff = parse(res.data); const content = diff .find((file) => file.to === "themes/index.js") .chunks[0].changes.filter((c) => c.type === "add") .map((c) => c.content.replace("+", "")) .join(""); - - const themeObject = Hjson.parse(content); - const themeName = Object.keys(themeObject)[0]; - const colors = themeObject[themeName]; - - if (themeName !== snakeCase(themeName)) { - warnings.push("Theme name isn't in snake_case"); - } - - if (!colors) { - await upsertComment({ - comment_id: comment?.id, - owner: OWNER, - repo: REPO, - issue_number: pullRequestId, - body: ` - \r**${COMMENT_TITLE}** - - \rCannot create theme preview - - ${themeContribGuidelines} - `, - }); - return; + const themeObject = parseJSON(content); + if ( + Object.keys(themeObject).every( + (key) => typeof themeObject[key] !== "object", + ) + ) { + throw new Error("PR diff is not a valid theme JSON object."); } - const titleColor = colors.title_color; - const iconColor = colors.icon_color; - const textColor = colors.text_color; - const bgColor = colors.bg_color; - const url = getGrsLink(colors); - - const colorPairs = { - title_color: [titleColor, bgColor], - icon_color: [iconColor, bgColor], - text_color: [textColor, bgColor], - }; + // Loop through themes and create theme preview body. + debug("Create theme preview body..."); + const themeValid = Object.fromEntries( + Object.keys(themeObject).map((name) => [name, true]), + ); + let previewBody = ""; + for (const theme in themeObject) { + debug(`Create theme preview for ${theme}...`); + const themeName = theme; + const colors = themeObject[theme]; + const warnings = []; + const errors = []; + + // Check if the theme name is valid. + debug("Theme preview body: Check if the theme name is valid..."); + if (themeNameAlreadyExists(themeName)) { + warnings.push("Theme name already taken"); + themeValid[theme] = false; + } + if (themeName !== snakeCase(themeName)) { + warnings.push("Theme name isn't in snake_case"); + themeValid[theme] = false; + } - // check color contrast - Object.keys(colorPairs).forEach((key) => { - const color1 = colorPairs[key][0]; - const color2 = colorPairs[key][1]; - if (!ccc.isLevelAA(`#${color1}`, `#${color2}`)) { - const permalink = getWebAimLink(color1, color2); - warnings.push( - `\`${key}\` does not pass [AA contrast ratio](${permalink})`, + // Check if the theme colors are valid. + debug("Theme preview body: Check if the theme colors are valid..."); + let invalidColors = false; + if (!colors) { + warning.push("Theme colors are missing"); + invalidColors = true; + } else { + const missingKeys = AVAILABLE_COLOR_PROPS.filter( + (x) => !Object.keys(colors).includes(x), ); + if (missingKeys.length > 0) { + for (const missingKey of missingKeys) { + errors.push(`Theme color properties \`${missingKey}\` are missing`); + } + invalidColors = true; + } else { + for (const [colorKey, colorValue] of Object.entries(colors)) { + if (colorValue[0] === "#") { + errors.push( + `Theme color property \`${colorKey}\` should not start with '#'`, + ); + invalidColors = true; + } else if (!isHexColor(colorValue)) { + errors.push( + `Theme color property \`${colorKey}\` is not a valid hex color: #${colorValue}`, + ); + invalidColors = true; + } + } + } + } + if (invalidColors) { + themeValid[theme] = false; + previewBody += ` + \r### ${ + themeName.charAt(0).toUpperCase() + themeName.slice(1) + } theme preview + + \r${warnings.map((warning) => `- :warning: ${warning}.\n`).join("")} + \r${errors.map((error) => `- :x: ${error}.\n`).join("")} + + \r>:x: Cannot create theme preview. + `; + continue; } - }); - await upsertComment(octokit, { - comment_id: comment?.id, - issue_number: pullRequestId, - owner: OWNER, - repo: REPO, - body: ` - \r**${COMMENT_TITLE}** + // Check color contrast. + debug("Theme preview body: Check color contrast..."); + const titleColor = colors.title_color; + const iconColor = colors.icon_color; + const textColor = colors.text_color; + const bgColor = colors.bg_color; + const url = getGRSLink(colors); + const colorPairs = { + title_color: [titleColor, bgColor], + icon_color: [iconColor, bgColor], + text_color: [textColor, bgColor], + }; + Object.keys(colorPairs).forEach((item) => { + const color1 = colorPairs[item][0]; + const color2 = colorPairs[item][1]; + if (!ccc.isLevelAA(`#${color1}`, `#${color2}`)) { + const permalink = getWebAimLink(color1, color2); + warnings.push( + `\`${item}\` does not pass [AA contrast ratio](${permalink})`, + ); + themeValid[theme] = false; + } + }); - \r${warnings.map((warning) => `- :warning: ${warning}\n`).join("")} + // Create theme preview body. + debug("Theme preview body: Create theme preview body..."); + previewBody += ` + \r### ${ + themeName.charAt(0).toUpperCase() + themeName.slice(1) + } theme preview + + \r${warnings.map((warning) => `- :warning: ${warning}.\n`).join("")} - \ntitle_color: #${titleColor} | icon_color: #${iconColor} | text_color: #${textColor} | bg_color: #${bgColor} + \ntitle_color: #${titleColor} | icon_color: #${iconColor} | text_color: #${textColor} | bg_color: #${bgColor} - \r[Preview Link](${url}) + \r[Preview Link](${url}) - \r[![](${url})](${url}) + \r[![](${url})](${url}) + `; + } - ${themeContribGuidelines} - `, - }); + // Create comment body. + debug("Create comment body..."); + commentBody += ` + \r${ + Object.values(themeValid).every((value) => value) + ? THEME_PR_SUCCESS_TEXT + : THEME_PR_FAIL_TEXT + } + \r## Test results + \r${Object.entries(themeValid) + .map( + ([key, value]) => `- ${value ? ":heavy_check_mark:" : ":x:"} ${key}`, + ) + .join("\r")} + + \r${ + Object.values(themeValid).every((value) => value) + ? "**Result:** :heavy_check_mark: All themes are valid." + : "**Result:** :x: Some themes are invalid.\n\n" + FAIL_TEXT + } + + \r## Details + \r${previewBody} + `; + + // Create or update theme-preview comment. + debug("Create or update theme-preview comment..."); + let comment_url; + if (!dryRun) { + comment_url = await upsertComment(octokit, { + comment_id: comment?.id, + issue_number: pullRequestId, + owner, + repo, + body: commentBody, + }); + } else { + info(`DRY_RUN: Comment body: ${commentBody}`); + comment_url = ""; + } + + // Change review state and add/remove `invalid` label based on theme PR validity. + debug( + "Change review state and add/remove `invalid` label based on whether all themes passed...", + ); + const themesValid = Object.values(themeValid).every((value) => value); + const reviewState = themesValid ? "APPROVE" : "REQUEST_CHANGES"; + const reviewReason = themesValid + ? undefined + : INVALID_REVIEW_COMMENT(comment_url); + if (!dryRun) { + await addReview( + octokit, + pullRequestId, + owner, + repo, + reviewState, + reviewReason, + ); + await addRemoveLabel( + octokit, + pullRequestId, + owner, + repo, + "invalid", + !themesValid, + ); + } else { + info(`DRY_RUN: Review state: ${reviewState}`); + info(`DRY_RUN: Review reason: ${reviewReason}`); + } } catch (error) { - console.log(error); + setFailed(error.message); } -} +}; run(); From d5d8912954a1b7fe4203777f567be7ab428a976c Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Sun, 2 Oct 2022 10:33:29 +0200 Subject: [PATCH 003/157] ci: improve theme preview action (#2088) This commit makes sure that 4,5,6,8 digit hex colors are also accepted. It further also includes the border_color attribute in the tests. --- scripts/preview-theme.js | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/scripts/preview-theme.js b/scripts/preview-theme.js index ea511a9e0268b..c6312b401b8f0 100644 --- a/scripts/preview-theme.js +++ b/scripts/preview-theme.js @@ -12,6 +12,7 @@ import Hjson from "hjson"; import snakeCase from "lodash.snakecase"; import parse from "parse-diff"; import { inspect } from "util"; +import { isValidHexColor } from "../src/common/utils.js"; import { themes } from "../themes/index.js"; // Script variables @@ -33,11 +34,11 @@ const THEME_CONTRIB_GUIDELINESS = ` \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). `; -const AVAILABLE_COLOR_PROPS = [ - "bg_color", +const REQUIRED_COLOR_PROPS = [ + "title_color", "icon_color", "text_color", - "title_color", + "bg_color", ]; const INVALID_REVIEW_COMMENT = (commentUrl) => `Some themes are invalid. See the [Automated Theme Preview](${commentUrl}) comment above for more information.`; @@ -320,20 +321,6 @@ const parseJSON = (json) => { } }; -/** - * Check if string is a valid hex color. - * - * @param {string} str String to check. - * @returns {boolean} Whether the string is a valid hex color. - */ -const isHexColor = (str, prefix = false) => { - if (prefix) { - return /^#[a-f0-9]{6}$/i.exec(str); - } else { - return /^[a-f0-9]{6}$/i.exec(str); - } -}; - /** * Check whether the theme name is still available. * @param {string} name Theme name. @@ -431,7 +418,7 @@ const run = async () => { warning.push("Theme colors are missing"); invalidColors = true; } else { - const missingKeys = AVAILABLE_COLOR_PROPS.filter( + const missingKeys = REQUIRED_COLOR_PROPS.filter( (x) => !Object.keys(colors).includes(x), ); if (missingKeys.length > 0) { @@ -446,7 +433,7 @@ const run = async () => { `Theme color property \`${colorKey}\` should not start with '#'`, ); invalidColors = true; - } else if (!isHexColor(colorValue)) { + } else if (!isValidHexColor(colorValue)) { errors.push( `Theme color property \`${colorKey}\` is not a valid hex color: #${colorValue}`, ); @@ -476,6 +463,7 @@ const run = async () => { const iconColor = colors.icon_color; const textColor = colors.text_color; const bgColor = colors.bg_color; + const borderColor = colors.border_color; const url = getGRSLink(colors); const colorPairs = { title_color: [titleColor, bgColor], @@ -503,7 +491,9 @@ const run = async () => { \r${warnings.map((warning) => `- :warning: ${warning}.\n`).join("")} - \ntitle_color: #${titleColor} | icon_color: #${iconColor} | text_color: #${textColor} | bg_color: #${bgColor} + \ntitle_color: #${titleColor} | icon_color: #${iconColor} | text_color: #${textColor} | bg_color: #${bgColor}${ + borderColor ? ` | border_color: #${borderColor}` : "" + } \r[Preview Link](${url}) From aaf710c024632cbcc782815b43d2953885b2a0dd Mon Sep 17 00:00:00 2001 From: rickstaa Date: Sun, 2 Oct 2022 10:35:11 +0200 Subject: [PATCH 004/157] ci: fix e2e test --- 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 91c9c38fe83aa..8a29712ee36c3 100644 --- a/tests/e2e/e2e.test.js +++ b/tests/e2e/e2e.test.js @@ -16,7 +16,7 @@ const REPO = "dummy-cra"; const USER = "grsdummy"; const STATS_DATA = { name: "grsdummy", - totalPRs: 1, + totalPRs: 2, totalCommits: 2, totalIssues: 1, totalStars: 1, From f86059f097fc624a44a037a05efee597e2abac7f Mon Sep 17 00:00:00 2001 From: Jongwoo Han Date: Sun, 2 Oct 2022 17:38:07 +0900 Subject: [PATCH 005/157] chore: Update workflows to cache dependencies (#2083) --- .github/workflows/e2e-test.yml | 12 ++++++++++++ .github/workflows/generate-theme-doc.yml | 13 +++++++++---- .github/workflows/preview-theme.yml | 12 ++++++++++-- .github/workflows/test.yml | 10 +++++++--- 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index 4699b67d5ba15..804a2008abd5f 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -8,12 +8,24 @@ jobs: github.event_name == 'deployment_status' && github.event.deployment_status.state == 'success' 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 end-to-end tests. run: npm run test:e2e env: diff --git a/.github/workflows/generate-theme-doc.yml b/.github/workflows/generate-theme-doc.yml index 23ea02100e07f..ef076f3a0af0f 100644 --- a/.github/workflows/generate-theme-doc.yml +++ b/.github/workflows/generate-theme-doc.yml @@ -10,13 +10,18 @@ on: jobs: build: runs-on: ubuntu-latest + strategy: + matrix: + node-version: [16.x] steps: - - uses: actions/checkout@v1 - - name: setup node - uses: actions/setup-node@v1 + - uses: actions/checkout@v3 + + - name: Setup Node + uses: actions/setup-node@v3 with: - node-version: "16.x" + node-version: ${{ matrix.node-version }} + cache: npm - name: npm install, generate readme run: | diff --git a/.github/workflows/preview-theme.yml b/.github/workflows/preview-theme.yml index 709cba4cc9071..5c5cf9a1b4fa3 100644 --- a/.github/workflows/preview-theme.yml +++ b/.github/workflows/preview-theme.yml @@ -11,16 +11,24 @@ on: jobs: previewTheme: runs-on: ubuntu-latest + strategy: + matrix: + node-version: [16.x] name: Install & Preview steps: - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + + - name: Setup Node + uses: actions/setup-node@v3 with: - node-version: 16 + node-version: ${{ matrix.node-version }} + cache: npm + - uses: bahmutov/npm-install@v1 with: useLockFile: false + - run: npm run preview-theme env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 57fabc5e5f024..c051f96ba70db 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,14 +11,18 @@ on: jobs: build: runs-on: ubuntu-latest + strategy: + matrix: + node-version: [16.x] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup Node - uses: actions/setup-node@v1 + uses: actions/setup-node@v3 with: - node-version: "16.x" + node-version: ${{ matrix.node-version }} + cache: npm - name: Install & Test run: | From 098331069a271d93db8de3e87daf394c66fc9288 Mon Sep 17 00:00:00 2001 From: Oscar Dominguez Date: Sun, 2 Oct 2022 10:51:37 +0200 Subject: [PATCH 006/157] ci(label-pr): upgrade actions/labeler to v4 (#2080) Co-authored-by: rickstaa --- .github/workflows/label-pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/label-pr.yml b/.github/workflows/label-pr.yml index 93cb767bf9a04..c401d32ee4b9c 100644 --- a/.github/workflows/label-pr.yml +++ b/.github/workflows/label-pr.yml @@ -6,6 +6,6 @@ jobs: triage: runs-on: ubuntu-latest steps: - - uses: actions/labeler@v2 + - uses: actions/labeler@v4 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" From 51e7887b9553cf97c6e74e9655597a33ba696f0b Mon Sep 17 00:00:00 2001 From: rickstaa Date: Sun, 2 Oct 2022 10:52:33 +0200 Subject: [PATCH 007/157] ci: fix e2e test --- 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 8a29712ee36c3..7e59acb4d1ecd 100644 --- a/tests/e2e/e2e.test.js +++ b/tests/e2e/e2e.test.js @@ -20,7 +20,7 @@ const STATS_DATA = { totalCommits: 2, totalIssues: 1, totalStars: 1, - contributedTo: 1, + contributedTo: 2, rank: { level: "A+", score: 51.01622937949586, From b8faef6857c1c9c9baad3c64daa8a8807a8b0205 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Sun, 2 Oct 2022 11:05:13 +0200 Subject: [PATCH 008/157] ci: add stale theme pull request closer action push (#2067) This commit adds the `stale-theme-pr-closer` closer action. This action is used to close theme pull requests with an `invalid` label that has been stale for a given number of `STALE_DAYS`. --- .github/workflows/e2e-test.yml | 3 +- .github/workflows/empty-issues-closer.yaml | 1 + .github/workflows/generate-theme-doc.yml | 4 +- .github/workflows/preview-theme.yml | 3 +- .github/workflows/stale-theme-pr-closer.yaml | 30 ++++ .github/workflows/test.yml | 2 +- package.json | 1 + scripts/close-stale-theme-prs.js | 161 +++++++++++++++++++ scripts/helpers.js | 40 +++++ scripts/preview-theme.js | 40 +---- 10 files changed, 242 insertions(+), 43 deletions(-) create mode 100644 .github/workflows/stale-theme-pr-closer.yaml create mode 100644 scripts/close-stale-theme-prs.js create mode 100644 scripts/helpers.js diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index 804a2008abd5f..b9d275f5d5828 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -3,10 +3,11 @@ on: deployment_status: jobs: - preview: + e2eTests: if: github.event_name == 'deployment_status' && github.event.deployment_status.state == 'success' + name: Perform 2e2 tests runs-on: ubuntu-latest strategy: matrix: diff --git a/.github/workflows/empty-issues-closer.yaml b/.github/workflows/empty-issues-closer.yaml index 5f050fe067abc..b20eef32fefb8 100644 --- a/.github/workflows/empty-issues-closer.yaml +++ b/.github/workflows/empty-issues-closer.yaml @@ -12,6 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 # NOTE: Retrieve issue templates. + - name: Run empty issues closer action uses: rickstaa/empty-issues-closer-action@v1 env: diff --git a/.github/workflows/generate-theme-doc.yml b/.github/workflows/generate-theme-doc.yml index ef076f3a0af0f..d5fac06381943 100644 --- a/.github/workflows/generate-theme-doc.yml +++ b/.github/workflows/generate-theme-doc.yml @@ -1,5 +1,4 @@ name: Generate Theme Readme - on: push: branches: @@ -8,8 +7,9 @@ on: - "themes/index.js" jobs: - build: + generateThemeDoc: runs-on: ubuntu-latest + name: Generate theme doc strategy: matrix: node-version: [16.x] diff --git a/.github/workflows/preview-theme.yml b/.github/workflows/preview-theme.yml index 5c5cf9a1b4fa3..132d4eb741e14 100644 --- a/.github/workflows/preview-theme.yml +++ b/.github/workflows/preview-theme.yml @@ -1,5 +1,4 @@ name: Theme preview - on: pull_request_target: types: [opened, edited, reopened, synchronize] @@ -10,11 +9,11 @@ on: jobs: previewTheme: + name: Install & Preview runs-on: ubuntu-latest strategy: matrix: node-version: [16.x] - name: Install & Preview steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/stale-theme-pr-closer.yaml b/.github/workflows/stale-theme-pr-closer.yaml new file mode 100644 index 0000000000000..8b1c78b4d8694 --- /dev/null +++ b/.github/workflows/stale-theme-pr-closer.yaml @@ -0,0 +1,30 @@ +name: Close stale theme pull requests that have the 'invalid' label. +on: + schedule: + - cron: "0 0 */7 * *" + +jobs: + closeOldThemePrs: + name: Close stale 'invalid' theme PRs + 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 + + - uses: bahmutov/npm-install@v1 + with: + useLockFile: false + + - run: npm run close-stale-theme-prs + env: + STALE_DAYS: 15 + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c051f96ba70db..fe34668d3e8d2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,5 +1,4 @@ name: Test - on: push: branches: @@ -10,6 +9,7 @@ on: jobs: build: + name: Perform tests runs-on: ubuntu-latest strategy: matrix: diff --git a/package.json b/package.json index b1bce12bfe7bc..ffadefdeda100 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "test:e2e": "node --experimental-vm-modules node_modules/jest/bin/jest.js --config jest.e2e.config.js", "theme-readme-gen": "node scripts/generate-theme-doc", "preview-theme": "node scripts/preview-theme", + "close-stale-theme-prs": "node scripts/close-stale-theme-prs", "generate-langs-json": "node scripts/generate-langs-json", "format": "./node_modules/.bin/prettier --write .", "format:check": "./node_modules/.bin/prettier --check ." diff --git a/scripts/close-stale-theme-prs.js b/scripts/close-stale-theme-prs.js new file mode 100644 index 0000000000000..69e5e193c6b85 --- /dev/null +++ b/scripts/close-stale-theme-prs.js @@ -0,0 +1,161 @@ +/** + * @file Script that can be used to close stale theme PRs that have a `invalid` label. + */ +import * as dotenv from "dotenv"; +dotenv.config(); + +import { debug, setFailed } from "@actions/core"; +import github from "@actions/github"; +import { RequestError } from "@octokit/request-error"; +import { getGithubToken, getRepoInfo } from "./helpers.js"; + +// Script parameters +const CLOSING_COMMENT = ` + \rThis PR has been automatically closed due to inactivity. Please feel free to reopen it if you need to continue working on it.\ + \rThank you for your contributions. +`; + +/** + * Fetch open PRs from a given repository. + * @param user The user name of the repository owner. + * @param repo The name of the repository. + * @returns The open PRs. + */ +export const fetchOpenPRs = async (octokit, user, repo) => { + const openPRs = []; + let hasNextPage = true; + let endCursor; + while (hasNextPage) { + try { + const { repository } = await octokit.graphql( + ` + { + repository(owner: "${user}", name: "${repo}") { + open_prs: pullRequests(${ + endCursor ? `after: "${endCursor}", ` : "" + } + first: 100, states: OPEN, orderBy: {field: CREATED_AT, direction: DESC}) { + nodes { + number + commits(last:1){ + nodes{ + commit{ + pushedDate + } + } + } + labels(first: 100, orderBy:{field: CREATED_AT, direction: DESC}) { + nodes { + name + } + } + reviews(first: 1, states: CHANGES_REQUESTED, author: "github-actions[bot]") { + nodes { + updatedAt + } + } + } + pageInfo { + endCursor + hasNextPage + } + } + } + } + `, + ); + openPRs.push(...repository.open_prs.nodes); + hasNextPage = repository.open_prs.pageInfo.hasNextPage; + endCursor = repository.open_prs.pageInfo.endCursor; + } catch (error) { + if (error instanceof RequestError) { + setFailed(`Could not retrieve top PRs using GraphQl: ${error.message}`); + } + throw error; + } + } + return openPRs; +}; + +/** + * Retrieve pull requests that have a given label. + * @param pull The pull requests to check. + * @param label The label to check for. + */ +export const pullsWithLabel = (pulls, label) => { + return pulls.filter((pr) => { + return pr.labels.nodes.some((lab) => lab.name === label); + }); +}; + +/** + * Check if PR is stale. Meaning that it hasn't been updated in a given time. + * @param {Object} pullRequest request object. + * @param {number} days number of days. + * @returns Boolean indicating if PR is stale. + */ +const isStale = (pullRequest, staleDays) => { + const lastCommitDate = new Date( + pullRequest.commits.nodes[0].commit.pushedDate, + ); + if (pullRequest.reviews.nodes[0]) { + const lastReviewDate = new Date(pullRequest.reviews.nodes[0].updatedAt); + const lastUpdateDate = + lastCommitDate >= lastReviewDate ? lastCommitDate : lastReviewDate; + const now = new Date(); + return now - lastUpdateDate > 1000 * 60 * 60 * 24 * staleDays; + } else { + return false; + } +}; + +/** + * Main function. + */ +const run = async () => { + try { + // Create octokit client. + const dryRun = process.env.DRY_RUN === "true" || false; + const staleDays = process.env.STALE_DAYS || 15; + debug("Creating octokit client..."); + const octokit = github.getOctokit(getGithubToken()); + const { owner, repo } = getRepoInfo(github.context); + + // Retrieve all theme pull requests. + debug("Retrieving all theme pull requests..."); + const prs = await fetchOpenPRs(octokit, owner, repo); + const themePRs = pullsWithLabel(prs, "themes"); + const invalidThemePRs = pullsWithLabel(themePRs, "invalid"); + debug("Retrieving stale themePRs..."); + const staleThemePRs = invalidThemePRs.filter((pr) => + isStale(pr, staleDays), + ); + const staleThemePRsNumbers = staleThemePRs.map((pr) => pr.number); + debug(`Found ${staleThemePRs.length} stale theme PRs`); + + // Loop through all stale invalid theme pull requests and close them. + for (const prNumber of staleThemePRsNumbers) { + debug(`Closing #${prNumber} because it is stale...`); + if (!dryRun) { + await octokit.issues.createComment({ + owner, + repo, + issue_number: prNumber, + body: CLOSING_COMMENT, + }); + await octokit.pulls.update({ + owner, + repo, + pull_number: prNumber, + state: "closed", + }); + } else { + debug("Dry run enabled, skipping..."); + } + } + } catch (error) { + setFailed(error.message); + } +}; + +run(); diff --git a/scripts/helpers.js b/scripts/helpers.js new file mode 100644 index 0000000000000..fabf300f477be --- /dev/null +++ b/scripts/helpers.js @@ -0,0 +1,40 @@ +/** + * @file Contains helper functions used in the scripts. + */ + +// Script variables. +const OWNER = "anuraghazra"; +const REPO = "github-readme-stats"; + +/** + * Retrieve information about the repository that ran the action. + * + * @param {Object} context Action context. + * @returns {Object} Repository information. + */ +export const getRepoInfo = (ctx) => { + try { + return { + owner: ctx.repo.owner, + repo: ctx.repo.repo, + }; + } catch (error) { + return { + owner: OWNER, + repo: REPO, + }; + } +}; + +/** + * Retrieve github token and throw error if it is not found. + * + * @returns {string} Github token. + */ +export const getGithubToken = () => { + const token = core.getInput("github_token") || process.env.GITHUB_TOKEN; + if (!token) { + throw Error("Could not find github token"); + } + return token; +}; diff --git a/scripts/preview-theme.js b/scripts/preview-theme.js index c6312b401b8f0..94145fb253c71 100644 --- a/scripts/preview-theme.js +++ b/scripts/preview-theme.js @@ -4,7 +4,7 @@ import * as dotenv from "dotenv"; dotenv.config(); -import core, { debug, setFailed } from "@actions/core"; +import { debug, setFailed } from "@actions/core"; import github from "@actions/github"; import ColorContrastChecker from "color-contrast-checker"; import { info } from "console"; @@ -14,10 +14,9 @@ import parse from "parse-diff"; import { inspect } from "util"; import { isValidHexColor } from "../src/common/utils.js"; import { themes } from "../themes/index.js"; +import { getGithubToken, getRepoInfo } from "./helpers.js"; -// Script variables -const OWNER = "anuraghazra"; -const REPO = "github-readme-stats"; +// Script variables. const COMMENTER = "github-actions[bot]"; const COMMENT_TITLE = "Automated Theme Preview"; @@ -43,26 +42,6 @@ const REQUIRED_COLOR_PROPS = [ const INVALID_REVIEW_COMMENT = (commentUrl) => `Some themes are invalid. See the [Automated Theme Preview](${commentUrl}) comment above for more information.`; -/** - * Retrieve information about the repository that ran the action. - * - * @param {Object} context Action context. - * @returns {Object} Repository information. - */ -export const getRepoInfo = (ctx) => { - try { - return { - owner: ctx.repo.owner, - repo: ctx.repo.repo, - }; - } catch (error) { - return { - owner: OWNER, - repo: REPO, - }; - } -}; - /** * Retrieve PR number from the event payload. * @@ -86,19 +65,6 @@ const getCommenter = () => { return process.env.COMMENTER ? process.env.COMMENTER : COMMENTER; }; -/** - * Retrieve github token and throw error if it is not found. - * - * @returns {string} Github token. - */ -const getGithubToken = () => { - const token = core.getInput("github_token") || process.env.GITHUB_TOKEN; - if (!token) { - throw Error("Could not find github token"); - } - return token; -}; - /** * Returns whether the comment is a preview comment. * From 406dbc5656ea8e12ff224967cd7ebacc5f0d8729 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Sun, 2 Oct 2022 11:45:55 +0200 Subject: [PATCH 009/157] feat: add transparent theme Adds a transparent theme with a contrast ratio of 4.5 on both black and white (see https://ux.stackexchange.com/a/86226). --- themes/index.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/themes/index.js b/themes/index.js index 6ca5fde62de26..d5c0e4c21b3fd 100644 --- a/themes/index.js +++ b/themes/index.js @@ -12,6 +12,13 @@ export const themes = { text_color: "434d58", bg_color: "fffefe", }, + transparent: { + title_color: "006AFF", + icon_color: "0579C3", + text_color: "417E87", + bg_color: "ffffff00", + border_color: "e4e2e2", + }, dark: { title_color: "fff", icon_color: "79ff97", From 510cf6266cdae5c8c81cd9e541b593413b86e5e5 Mon Sep 17 00:00:00 2001 From: rickstaa Date: Sun, 2 Oct 2022 11:47:56 +0200 Subject: [PATCH 010/157] feat: remove border color from transparent theme --- themes/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/themes/index.js b/themes/index.js index d5c0e4c21b3fd..4279317b3edc3 100644 --- a/themes/index.js +++ b/themes/index.js @@ -17,7 +17,6 @@ export const themes = { icon_color: "0579C3", text_color: "417E87", bg_color: "ffffff00", - border_color: "e4e2e2", }, dark: { title_color: "fff", From 3a07cb02db0a69238cb75d802b6485537d73c27e Mon Sep 17 00:00:00 2001 From: rickstaa Date: Sun, 2 Oct 2022 12:27:34 +0200 Subject: [PATCH 011/157] ci: fix e2e test --- 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 7e59acb4d1ecd..becf5c82d891f 100644 --- a/tests/e2e/e2e.test.js +++ b/tests/e2e/e2e.test.js @@ -23,7 +23,7 @@ const STATS_DATA = { contributedTo: 2, rank: { level: "A+", - score: 51.01622937949586, + score: 51.01013099671447, }, }; const LANGS_DATA = { From f0daab11c8ab9e6a2eb00cd5794075a41b47c9e0 Mon Sep 17 00:00:00 2001 From: Jagruti Tiwari Date: Sun, 2 Oct 2022 17:33:22 +0530 Subject: [PATCH 012/157] feat: added default options to readme (#2051) * feat: added default options to readme * Update readme.md Co-authored-by: Rick Staa * fix: added default values for stats card * style: some small readme changes Co-authored-by: Rick Staa --- readme.md | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/readme.md b/readme.md index 3ef407248312e..6f4575566b8ec 100644 --- a/readme.md +++ b/readme.md @@ -160,16 +160,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)_ -- `text_color` - Body text color _(hex color)_ -- `icon_color` - Icons color if available _(hex color)_ -- `border_color` - Card's border color _(hex color)_. (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_ -- `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: 7200, max: 86400)_ -- `locale` - set the language in the card _(e.g. cn, de, es, etc.)_ -- `border_radius` - Corner rounding on the card +- `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. @@ -185,18 +185,21 @@ You can provide multiple comma-separated values in the bg_color option to render #### Stats Card Exclusive Options: -- `hide` - Hides the [specified items](#hiding-individual-stats) from stats _(Comma-separated values)_ -- `hide_title` - _(boolean)_ -- `card_width` - Set the card's width manually _(number)_ -- `hide_rank` - _(boolean)_ hides the rank and automatically resizes the card width -- `show_icons` - _(boolean)_ -- `include_all_commits` - Count total commits instead of just the current year commits _(boolean)_ -- `count_private` - Count private commits _(boolean)_ -- `line_height` - Sets the line-height between text _(number)_ -- `exclude_repo` - Exclude stars from specified repositories _(Comma-separated values)_ -- `custom_title` - Sets a custom title for the card -- `text_bold` - Use bold text _(boolean)_ -- `disable_animations` - Disables all animations in the card _(boolean)_ +- `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. #### Repo Card Exclusive Options: @@ -454,4 +457,3 @@ Thanks! :heart: Contributions are welcome! <3 Made with :heart: and JavaScript. - From 6f8bd9fe1019dccb7bea99d52cfd51342d388b25 Mon Sep 17 00:00:00 2001 From: rickstaa Date: Sun, 2 Oct 2022 14:15:25 +0200 Subject: [PATCH 013/157] ci: increase top-issues dashboard update frequency --- .github/workflows/top-issues-dashboard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/top-issues-dashboard.yml b/.github/workflows/top-issues-dashboard.yml index 97947947befb2..2b36e529de454 100644 --- a/.github/workflows/top-issues-dashboard.yml +++ b/.github/workflows/top-issues-dashboard.yml @@ -1,7 +1,7 @@ name: Update top issues dashboard on: schedule: - - cron: "0 0 */7 * *" + - cron: "0 0 */3 * *" jobs: showAndLabelTopIssues: From d56b294ca16e63c58567ac3b54fabf30bb508446 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Sun, 2 Oct 2022 14:50:03 +0200 Subject: [PATCH 014/157] style: improve code style --- scripts/close-stale-theme-prs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/close-stale-theme-prs.js b/scripts/close-stale-theme-prs.js index 69e5e193c6b85..8c14c1e3ce471 100644 --- a/scripts/close-stale-theme-prs.js +++ b/scripts/close-stale-theme-prs.js @@ -126,7 +126,7 @@ const run = async () => { const prs = await fetchOpenPRs(octokit, owner, repo); const themePRs = pullsWithLabel(prs, "themes"); const invalidThemePRs = pullsWithLabel(themePRs, "invalid"); - debug("Retrieving stale themePRs..."); + debug("Retrieving stale theme PRs..."); const staleThemePRs = invalidThemePRs.filter((pr) => isStale(pr, staleDays), ); From 84c9d354b3fabec196b1a4fc9cb4700582b803dd Mon Sep 17 00:00:00 2001 From: Anurag Hazra Date: Sun, 2 Oct 2022 21:01:38 +0530 Subject: [PATCH 015/157] docs(theme): Auto update theme readme (#2091) Co-authored-by: Github Readme Stats Bot --- themes/README.md | 84 +++++++++++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/themes/README.md b/themes/README.md index e8b22b269b90e..b8649d43b9564 100644 --- a/themes/README.md +++ b/themes/README.md @@ -16,26 +16,27 @@ Use `?theme=THEME_NAME` parameter like so :- | | | | | :--: | :--: | :--: | -| `default` ![default][default] | `dark` ![dark][dark] | `radical` ![radical][radical] | -| `merko` ![merko][merko] | `gruvbox` ![gruvbox][gruvbox] | `gruvbox_light` ![gruvbox_light][gruvbox_light] | -| `tokyonight` ![tokyonight][tokyonight] | `onedark` ![onedark][onedark] | `cobalt` ![cobalt][cobalt] | -| `synthwave` ![synthwave][synthwave] | `highcontrast` ![highcontrast][highcontrast] | `dracula` ![dracula][dracula] | -| `prussian` ![prussian][prussian] | `monokai` ![monokai][monokai] | `vue` ![vue][vue] | -| `vue-dark` ![vue-dark][vue-dark] | `shades-of-purple` ![shades-of-purple][shades-of-purple] | `nightowl` ![nightowl][nightowl] | -| `buefy` ![buefy][buefy] | `blue-green` ![blue-green][blue-green] | `algolia` ![algolia][algolia] | -| `great-gatsby` ![great-gatsby][great-gatsby] | `darcula` ![darcula][darcula] | `bear` ![bear][bear] | -| `solarized-dark` ![solarized-dark][solarized-dark] | `solarized-light` ![solarized-light][solarized-light] | `chartreuse-dark` ![chartreuse-dark][chartreuse-dark] | -| `nord` ![nord][nord] | `gotham` ![gotham][gotham] | `material-palenight` ![material-palenight][material-palenight] | -| `graywhite` ![graywhite][graywhite] | `vision-friendly-dark` ![vision-friendly-dark][vision-friendly-dark] | `ayu-mirage` ![ayu-mirage][ayu-mirage] | -| `midnight-purple` ![midnight-purple][midnight-purple] | `calm` ![calm][calm] | `flag-india` ![flag-india][flag-india] | -| `omni` ![omni][omni] | `react` ![react][react] | `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] | `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] | [Add your theme][add-theme] | +| `default` ![default][default] | `transparent` ![transparent][transparent] | `dark` ![dark][dark] | +| `radical` ![radical][radical] | `merko` ![merko][merko] | `gruvbox` ![gruvbox][gruvbox] | +| `gruvbox_light` ![gruvbox_light][gruvbox_light] | `tokyonight` ![tokyonight][tokyonight] | `onedark` ![onedark][onedark] | +| `cobalt` ![cobalt][cobalt] | `synthwave` ![synthwave][synthwave] | `highcontrast` ![highcontrast][highcontrast] | +| `dracula` ![dracula][dracula] | `prussian` ![prussian][prussian] | `monokai` ![monokai][monokai] | +| `vue` ![vue][vue] | `vue-dark` ![vue-dark][vue-dark] | `shades-of-purple` ![shades-of-purple][shades-of-purple] | +| `nightowl` ![nightowl][nightowl] | `buefy` ![buefy][buefy] | `blue-green` ![blue-green][blue-green] | +| `algolia` ![algolia][algolia] | `great-gatsby` ![great-gatsby][great-gatsby] | `darcula` ![darcula][darcula] | +| `bear` ![bear][bear] | `solarized-dark` ![solarized-dark][solarized-dark] | `solarized-light` ![solarized-light][solarized-light] | +| `chartreuse-dark` ![chartreuse-dark][chartreuse-dark] | `nord` ![nord][nord] | `gotham` ![gotham][gotham] | +| `material-palenight` ![material-palenight][material-palenight] | `graywhite` ![graywhite][graywhite] | `vision-friendly-dark` ![vision-friendly-dark][vision-friendly-dark] | +| `ayu-mirage` ![ayu-mirage][ayu-mirage] | `midnight-purple` ![midnight-purple][midnight-purple] | `calm` ![calm][calm] | +| `flag-india` ![flag-india][flag-india] | `omni` ![omni][omni] | `react` ![react][react] | +| `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] | +| `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] | +| [Add your theme][add-theme] | | | ## Repo Card @@ -43,30 +44,32 @@ Use `?theme=THEME_NAME` parameter like so :- | | | | | :--: | :--: | :--: | -| `default_repocard` ![default_repocard][default_repocard_repo] | `dark` ![dark][dark_repo] | `radical` ![radical][radical_repo] | -| `merko` ![merko][merko_repo] | `gruvbox` ![gruvbox][gruvbox_repo] | `gruvbox_light` ![gruvbox_light][gruvbox_light_repo] | -| `tokyonight` ![tokyonight][tokyonight_repo] | `onedark` ![onedark][onedark_repo] | `cobalt` ![cobalt][cobalt_repo] | -| `synthwave` ![synthwave][synthwave_repo] | `highcontrast` ![highcontrast][highcontrast_repo] | `dracula` ![dracula][dracula_repo] | -| `prussian` ![prussian][prussian_repo] | `monokai` ![monokai][monokai_repo] | `vue` ![vue][vue_repo] | -| `vue-dark` ![vue-dark][vue-dark_repo] | `shades-of-purple` ![shades-of-purple][shades-of-purple_repo] | `nightowl` ![nightowl][nightowl_repo] | -| `buefy` ![buefy][buefy_repo] | `blue-green` ![blue-green][blue-green_repo] | `algolia` ![algolia][algolia_repo] | -| `great-gatsby` ![great-gatsby][great-gatsby_repo] | `darcula` ![darcula][darcula_repo] | `bear` ![bear][bear_repo] | -| `solarized-dark` ![solarized-dark][solarized-dark_repo] | `solarized-light` ![solarized-light][solarized-light_repo] | `chartreuse-dark` ![chartreuse-dark][chartreuse-dark_repo] | -| `nord` ![nord][nord_repo] | `gotham` ![gotham][gotham_repo] | `material-palenight` ![material-palenight][material-palenight_repo] | -| `graywhite` ![graywhite][graywhite_repo] | `vision-friendly-dark` ![vision-friendly-dark][vision-friendly-dark_repo] | `ayu-mirage` ![ayu-mirage][ayu-mirage_repo] | -| `midnight-purple` ![midnight-purple][midnight-purple_repo] | `calm` ![calm][calm_repo] | `flag-india` ![flag-india][flag-india_repo] | -| `omni` ![omni][omni_repo] | `react` ![react][react_repo] | `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] | `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] | [Add your theme][add-theme] | +| `default_repocard` ![default_repocard][default_repocard_repo] | `transparent` ![transparent][transparent_repo] | `dark` ![dark][dark_repo] | +| `radical` ![radical][radical_repo] | `merko` ![merko][merko_repo] | `gruvbox` ![gruvbox][gruvbox_repo] | +| `gruvbox_light` ![gruvbox_light][gruvbox_light_repo] | `tokyonight` ![tokyonight][tokyonight_repo] | `onedark` ![onedark][onedark_repo] | +| `cobalt` ![cobalt][cobalt_repo] | `synthwave` ![synthwave][synthwave_repo] | `highcontrast` ![highcontrast][highcontrast_repo] | +| `dracula` ![dracula][dracula_repo] | `prussian` ![prussian][prussian_repo] | `monokai` ![monokai][monokai_repo] | +| `vue` ![vue][vue_repo] | `vue-dark` ![vue-dark][vue-dark_repo] | `shades-of-purple` ![shades-of-purple][shades-of-purple_repo] | +| `nightowl` ![nightowl][nightowl_repo] | `buefy` ![buefy][buefy_repo] | `blue-green` ![blue-green][blue-green_repo] | +| `algolia` ![algolia][algolia_repo] | `great-gatsby` ![great-gatsby][great-gatsby_repo] | `darcula` ![darcula][darcula_repo] | +| `bear` ![bear][bear_repo] | `solarized-dark` ![solarized-dark][solarized-dark_repo] | `solarized-light` ![solarized-light][solarized-light_repo] | +| `chartreuse-dark` ![chartreuse-dark][chartreuse-dark_repo] | `nord` ![nord][nord_repo] | `gotham` ![gotham][gotham_repo] | +| `material-palenight` ![material-palenight][material-palenight_repo] | `graywhite` ![graywhite][graywhite_repo] | `vision-friendly-dark` ![vision-friendly-dark][vision-friendly-dark_repo] | +| `ayu-mirage` ![ayu-mirage][ayu-mirage_repo] | `midnight-purple` ![midnight-purple][midnight-purple_repo] | `calm` ![calm][calm_repo] | +| `flag-india` ![flag-india][flag-india_repo] | `omni` ![omni][omni_repo] | `react` ![react][react_repo] | +| `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] | +| `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] | +| [Add your theme][add-theme] | | | [default]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=default [default_repocard]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=default_repocard +[transparent]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=transparent [dark]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=dark [radical]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=radical [merko]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=merko @@ -129,6 +132,7 @@ Use `?theme=THEME_NAME` parameter like so :- [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 +[transparent_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=transparent [dark_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=dark [radical_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=radical [merko_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=merko From 822efbf6cb991732ed3fe7460c6831e48a407a38 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Sun, 2 Oct 2022 17:41:28 +0200 Subject: [PATCH 016/157] ci: fix small bugs in theme-preview action (#2093) * ci: fix small bugs in theme-preview action * ci: format code --- scripts/helpers.js | 4 +++- scripts/preview-theme.js | 49 ++++++++++++++++++++++++++++------------ 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/scripts/helpers.js b/scripts/helpers.js index fabf300f477be..3fc5fc7d00eee 100644 --- a/scripts/helpers.js +++ b/scripts/helpers.js @@ -2,6 +2,8 @@ * @file Contains helper functions used in the scripts. */ +import { getInput } from "@actions/core"; + // Script variables. const OWNER = "anuraghazra"; const REPO = "github-readme-stats"; @@ -32,7 +34,7 @@ export const getRepoInfo = (ctx) => { * @returns {string} Github token. */ export const getGithubToken = () => { - const token = core.getInput("github_token") || process.env.GITHUB_TOKEN; + const token = getInput("github_token") || process.env.GITHUB_TOKEN; if (!token) { throw Error("Could not find github token"); } diff --git a/scripts/preview-theme.js b/scripts/preview-theme.js index 94145fb253c71..6bb29e68006c0 100644 --- a/scripts/preview-theme.js +++ b/scripts/preview-theme.js @@ -33,12 +33,15 @@ const THEME_CONTRIB_GUIDELINESS = ` \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). `; -const REQUIRED_COLOR_PROPS = [ - "title_color", - "icon_color", - "text_color", - "bg_color", -]; +const COLOR_PROPS = { + title_color: 6, + icon_color: 6, + text_color: 6, + bg_color: 8, + border_color: 6, +}; +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.`; @@ -271,11 +274,11 @@ const parseJSON = (json) => { } } catch (error) { let parsedJson = json - .split(/(?:\s*)(}\s*,?)(?:\s*)(?=\s*[a-z_"]+:+)/) + .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[0])) { + if (!/\s*}\s*,?\s*$/.test(parsedJson[1])) { parsedJson.push(parsedJson.shift()); } else { parsedJson.shift(); @@ -299,7 +302,7 @@ const themeNameAlreadyExists = (name) => { /** * Main function. */ -const run = async () => { +export const run = async (prNumber) => { try { const dryRun = process.env.DRY_RUN === "true" || false; debug("Retrieve action information from context..."); @@ -310,7 +313,7 @@ const run = async () => { `; const ccc = new ColorContrastChecker(); const octokit = github.getOctokit(getGithubToken()); - const pullRequestId = getPrNumber(); + const pullRequestId = prNumber ? prNumber : getPrNumber(); const commenter = getCommenter(); const { owner, repo } = getRepoInfo(github.context); debug(`Owner: ${owner}`); @@ -387,10 +390,19 @@ const run = async () => { const missingKeys = REQUIRED_COLOR_PROPS.filter( (x) => !Object.keys(colors).includes(x), ); - if (missingKeys.length > 0) { + const extraKeys = Object.keys(colors).filter( + (x) => !ACCEPTED_COLOR_PROPS.includes(x), + ); + if (missingKeys.length > 0 || extraKeys.length > 0) { for (const missingKey of missingKeys) { errors.push(`Theme color properties \`${missingKey}\` are missing`); } + + for (const extraKey of extraKeys) { + warnings.push( + `Theme color properties \`${extraKey}\` is not supported`, + ); + } invalidColors = true; } else { for (const [colorKey, colorValue] of Object.entries(colors)) { @@ -399,6 +411,11 @@ const run = async () => { `Theme color property \`${colorKey}\` should not start with '#'`, ); invalidColors = true; + } else if (colorValue.length > COLOR_PROPS[colorKey]) { + errors.push( + `Theme color property \`${colorKey}\` can not be longer than \`${COLOR_PROPS[colorKey]}\` characters`, + ); + invalidColors = true; } else if (!isValidHexColor(colorValue)) { errors.push( `Theme color property \`${colorKey}\` is not a valid hex color: #${colorValue}`, @@ -437,8 +454,10 @@ const run = async () => { text_color: [textColor, bgColor], }; Object.keys(colorPairs).forEach((item) => { - const color1 = colorPairs[item][0]; - const color2 = colorPairs[item][1]; + let color1 = colorPairs[item][0]; + let color2 = colorPairs[item][1]; + color1 = color1.length === 4 ? color1.slice(0, 3) : color1.slice(0, 6); + color2 = color2.length === 4 ? color2.slice(0, 3) : color2.slice(0, 6); if (!ccc.isLevelAA(`#${color1}`, `#${color2}`)) { const permalink = getWebAimLink(color1, color2); warnings.push( @@ -543,4 +562,6 @@ const run = async () => { } }; -run(); +if (typeof require !== "undefined" && require.main === module) { + run(); +} From 5d42af59c0214de3627788c7b1a4e22c5f32a655 Mon Sep 17 00:00:00 2001 From: rickstaa Date: Sun, 2 Oct 2022 17:42:58 +0200 Subject: [PATCH 017/157] ci: fix small bug in theme-preview action --- scripts/preview-theme.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/scripts/preview-theme.js b/scripts/preview-theme.js index 6bb29e68006c0..58aad0282e764 100644 --- a/scripts/preview-theme.js +++ b/scripts/preview-theme.js @@ -562,6 +562,4 @@ export const run = async (prNumber) => { } }; -if (typeof require !== "undefined" && require.main === module) { - run(); -} +run(); From 2faf9c54fff7f18fe4818a2427c5bbe1f81e062b Mon Sep 17 00:00:00 2001 From: ianbromwichuos <112479962+ianbromwichuos@users.noreply.github.com> Date: Sun, 2 Oct 2022 16:47:14 +0100 Subject: [PATCH 018/157] docs: fix link to go India logo svg (#2085) --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 6f4575566b8ec..f7a04fb3dbda6 100644 --- a/readme.md +++ b/readme.md @@ -64,7 +64,7 @@

-Give india logo +Give india logo Are you considering supporting the project by donating? Please DON'T!! From c2c984a872fef19d605de51907c3e60a0e73c4de Mon Sep 17 00:00:00 2001 From: rickstaa Date: Sun, 2 Oct 2022 17:58:34 +0200 Subject: [PATCH 019/157] docs: format readme --- readme.md | 192 ++++++++++++++++++++++++++---------------------------- 1 file changed, 94 insertions(+), 98 deletions(-) diff --git a/readme.md b/readme.md index f7a04fb3dbda6..51c7229b13706 100644 --- a/readme.md +++ b/readme.md @@ -61,7 +61,6 @@

Love the project? Please consider donating to help it improve! -

Give india logo @@ -72,25 +71,25 @@ 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 [https://indiafightscorona.giveindia.org](https://indiafightscorona.giveindia.org) and make a small donation to help us fight COVID and overcome this crisis. +Visit and make a small donation to help us fight COVID and overcome this crisis. A small donation goes a long way. :heart: -

+

# 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 @@

-Give india logo +Give india logo 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 @@

Tests Passing + + + GitHub Contributors From 9e1fc0b7da0e8f3721958c6db4d7b59ff841e5a3 Mon Sep 17 00:00:00 2001 From: Ayushi Vishwakarma Date: Mon, 3 Oct 2022 12:44:37 +0530 Subject: [PATCH 022/157] update default values in readme (#2094) * update default values in readme * docs: improve formatting * docs: improve readme punctation Co-authored-by: rickstaa --- readme.md | 8 ++++---- src/cards/repo-card.js | 2 +- src/cards/top-languages-card.js | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/readme.md b/readme.md index b18cdf64d2a83..2f183364e9390 100644 --- a/readme.md +++ b/readme.md @@ -203,12 +203,12 @@ You can provide multiple comma-separated values in the bg_color option to render #### Repo Card Exclusive Options: -- `show_owner` - Show the repo's owner name _(boolean)_ +- `show_owner` - Show the repo's owner name _(boolean)_. Defaults to `false`. #### Language Card Exclusive Options: - `hide` - Hide the languages specified from the card _(Comma-separated values)_ -- `hide_title` - _(boolean)_ +- `hide_title` - _(boolean)_. Defaults to `false`. - `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)_ @@ -223,8 +223,8 @@ You can provide multiple comma-separated values in the bg_color option to render #### 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_title` - _(boolean)_. Defaults to `false`. +- `line_height` - Sets the line-height between text _(number)_. Default Value: `25`. - `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` diff --git a/src/cards/repo-card.js b/src/cards/repo-card.js index 7c9c4b5771b50..5730ea4ff0e60 100644 --- a/src/cards/repo-card.js +++ b/src/cards/repo-card.js @@ -88,7 +88,7 @@ const renderRepoCard = (repo, options = {}) => { icon_color, text_color, bg_color, - show_owner, + show_owner = false, theme = "default_repocard", border_radius, border_color, diff --git a/src/cards/top-languages-card.js b/src/cards/top-languages-card.js index b181fc12adf61..b837b3587a513 100644 --- a/src/cards/top-languages-card.js +++ b/src/cards/top-languages-card.js @@ -235,7 +235,7 @@ const useLanguages = (topLangs, hide, langs_count) => { */ const renderTopLanguages = (topLangs, options = {}) => { const { - hide_title, + hide_title = false, hide_border, card_width, title_color, From c03bb2f250f6d65802ca16101aa38baef1022a5c Mon Sep 17 00:00:00 2001 From: Jagruti Tiwari Date: Mon, 3 Oct 2022 16:33:23 +0530 Subject: [PATCH 023/157] fix: adding docstrings to the files where it was missing (#2101) * fix: adding docstrings to missing files * style: format code * style: improve formatting Co-authored-by: Jagruti Tiwari Co-authored-by: rickstaa --- src/calculateRank.js | 24 +++++++++++++++++++++++- src/cards/stats-card.js | 13 +++++++++++++ src/common/retryer.js | 9 +++++++++ src/common/utils.js | 19 ++++++++++++++----- 4 files changed, 59 insertions(+), 6 deletions(-) diff --git a/src/calculateRank.js b/src/calculateRank.js index bbfece157c2c8..6c161f3f87dd8 100644 --- a/src/calculateRank.js +++ b/src/calculateRank.js @@ -1,4 +1,14 @@ -// https://stackoverflow.com/a/5263759/10629172 +/** + * Calculates the probability of x taking on x or a value less than x in a normal distribution + * with mean and standard deviation. + * + * @see https://stackoverflow.com/a/5263759/10629172 + * + * @param {string} mean + * @param {number} sigma + * @param {number} to + * @returns {number} Probability. + */ function normalcdf(mean, sigma, to) { var z = (to - mean) / Math.sqrt(2 * sigma * sigma); var t = 1 / (1 + 0.3275911 * Math.abs(z)); @@ -16,6 +26,18 @@ function normalcdf(mean, sigma, to) { return (1 / 2) * (1 + sign * erf); } +/** + * Calculates the users rank. + * + * @param {number} totalRepos + * @param {number} totalCommits + * @param {number} contributions + * @param {number} followers + * @param {number} prs + * @param {number} issues + * @param {number} stargazers + * @returns {{level: string, score: number}}} The users rank. + */ function calculateRank({ totalRepos, totalCommits, diff --git a/src/cards/stats-card.js b/src/cards/stats-card.js index 4b0cd33a49a21..f880560e93a1b 100644 --- a/src/cards/stats-card.js +++ b/src/cards/stats-card.js @@ -12,6 +12,19 @@ import { import { getStyles } from "../getStyles.js"; import { statCardLocales } from "../translations.js"; +/** + * Create a stats card text item. + * + * @param {object[]} createTextNodeParams Object that contains the createTextNode parameters. + * @param {string} createTextNodeParams.label The label to display. + * @param {string} createTextNodeParams.value The value to display. + * @param {string} createTextNodeParams.id The id of the stat. + * @param {number} createTextNodeParams.index The index of the stat. + * @param {boolean} createTextNodeParams.showIcons Whether to show icons. + * @param {number} createTextNodeParams.shiftValuePos Number of pixels the value has to be shifted to the right. + * @param {boolean} createTextNodeParams.bold Whether to bold the label. + * @returns + */ const createTextNode = ({ icon, label, diff --git a/src/common/retryer.js b/src/common/retryer.js index c898ef3f9e207..859e94b08207e 100644 --- a/src/common/retryer.js +++ b/src/common/retryer.js @@ -1,5 +1,14 @@ import { CustomError, logger } from "./utils.js"; +/** + * Try to execute the fetcher function until it succeeds or the max number of retries is reached. + * + * @param {object[]} retryerParams Object that contains the createTextNode parameters. + * @param {object[]} retryerParams.fetcher The fetcher function. + * @param {object[]} retryerParams.variables Object with arguments to pass to the fetcher function. + * @param {number} retryerParams.retries How many times to retry. + * @returns Promise + */ const retryer = async (fetcher, variables, retries = 0) => { if (retries > 7) { throw new CustomError("Maximum retries exceeded", CustomError.MAX_RETRY); diff --git a/src/common/utils.js b/src/common/utils.js index 7660bbd1355d1..ba61cf8119830 100644 --- a/src/common/utils.js +++ b/src/common/utils.js @@ -74,7 +74,10 @@ function parseBoolean(value) { } /** - * @param {string} str + * Parse string to array of strings. + * + * @param {string} str The string to parse. + * @returns {string[]} The array of strings. */ function parseArray(str) { if (!str) return []; @@ -82,9 +85,12 @@ function parseArray(str) { } /** - * @param {number} number - * @param {number} min - * @param {number} max + * Clamp the given number between the given range. + * + * @param {number} number The number to clamp. + * @param {number} min The minimum value. + * @param {number} max The maximum value. + * returns {number} The clamped number. */ function clampValue(number, min, max) { // @ts-ignore @@ -93,7 +99,10 @@ function clampValue(number, min, max) { } /** - * @param {string[]} colors + * Check if the given string is a valid gradient. + * + * @param {string[]} colors Array of colors. + * returns {boolean} True if the given string is a valid gradient. */ function isValidGradient(colors) { return isValidHexColor(colors[1]) && isValidHexColor(colors[2]); From 7accd1a8d7ead16ba32ac119f12941d7c17683e7 Mon Sep 17 00:00:00 2001 From: Aditya Shelke <103348863+adi-uchiha@users.noreply.github.com> Date: Tue, 4 Oct 2022 12:28:18 +0530 Subject: [PATCH 024/157] feat: default values for wakatime and language (#2103) * default values for wakatime and language * docs: update formatting Co-authored-by: rickstaa --- readme.md | 58 +++++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/readme.md b/readme.md index 2f183364e9390..0b6a54ccf1caf 100644 --- a/readme.md +++ b/readme.md @@ -6,7 +6,7 @@

Tests Passing - + GitHub Contributors @@ -64,9 +64,8 @@

Love the project? Please consider donating to help it improve! -

-Give india logo + Give india logo 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:

@@ -142,13 +140,13 @@ To enable icons, you can pass `show_icons=true` in the query param, like so: With inbuilt themes, you can customize the look of the card without doing any [manual customization](#customization). -Use `&theme=THEME_NAME` parameter like so :- +Use `&theme=THEME_NAME` parameter like so : ```md ![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&theme=radical) ``` -#### All inbuilt themes:- +#### All inbuilt themes dark, radical, merko, gruvbox, tokyonight, onedark, cobalt, synthwave, highcontrast, dracula @@ -160,7 +158,7 @@ You can look at a preview for [all available themes](./themes/README.md) or chec You can customize the appearance of your `Stats Card` or `Repo Card` however you wish with URL params. -#### Common Options: +#### Common Options - `title_color` - Card's title color _(hex color)_. Default: `2f80ed`. - `text_color` - Body text color _(hex color)_. Default: `434d58`. @@ -183,7 +181,7 @@ You can provide multiple comma-separated values in the bg_color option to render > 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: +#### 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`. @@ -201,36 +199,36 @@ You can provide multiple comma-separated values in the bg_color option to render > Note on `hide_rank`: > When hide_rank=`true`, the minimum card width is 270 px + the title length and padding. -#### Repo Card Exclusive Options: +#### Repo Card Exclusive Options -- `show_owner` - Show the repo's owner name _(boolean)_. Defaults to `false`. +- `show_owner` - Show the repo's owner name _(boolean)_. Default: `false`. -#### Language Card Exclusive Options: +#### Language Card Exclusive Options -- `hide` - Hide the languages specified from the card _(Comma-separated values)_ -- `hide_title` - _(boolean)_. Defaults to `false`. -- `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)_ .Default: `[] (blank array)`. +- `hide_title` - _(boolean)_. Default: `false`. +- `layout` - Switch between two available layouts `default` & `compact`. Default: `default`. +- `card_width` - Set the card's width manually _(number)_. Default `300`. +- `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`. > :warning: **Important:** > Language names should be uri-escaped, as specified in [Percent Encoding](https://en.wikipedia.org/wiki/Percent-encoding) > (i.e: `c++` should become `c%2B%2B`, `jupyter notebook` should become `jupyter%20notebook`, etc.) You can use > [urlencoder.org](https://www.urlencoder.org/) to help you do this automatically. -#### Wakatime Card Exclusive Options: +#### Wakatime Card Exclusive Options -- `hide` - Hide the languages specified from the card _(Comma-separated values)_ -- `hide_title` - _(boolean)_. Defaults to `false`. -- `line_height` - Sets the line-height between text _(number)_. Default Value: `25`. -- `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)_. Default: `[] (blank array)`. +- `hide_title` - _(boolean)_. Default `false`. +- `line_height` - Sets the line-height between text _(number)_. Default `25`. +- `hide_progress` - Hides the progress bar and percentage _(boolean)_. Default `false`. +- `custom_title` - Sets a custom title for the card _(string)_. Default `Wakatime Stats`. +- `layout` - Switch between two available layouts `default` & `compact`. Default `default`. +- `langs_count` - Limit the number of languages on the card, defaults to all reported languages _(number)_. Default `50`. +- `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) _(string)_. Default `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. _(YYYY-MM, last_7_days, last_30_days, last_6_months, last_year, or all_time)_. Default `all_time`. * * * @@ -441,7 +439,7 @@ NOTE: Since [#58](https://github.com/anuraghazra/github-readme-stats/pull/58) we I open-source almost everything I can, and I try to reply to everyone needing help using these projects. Obviously, 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:- +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: From e6a6384eff601d201a9a37b75d004b5e555c3c49 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Tue, 4 Oct 2022 09:19:37 +0200 Subject: [PATCH 025/157] docs: improve readme syntax (#2106) --- readme.md | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/readme.md b/readme.md index 0b6a54ccf1caf..6f741b745b102 100644 --- a/readme.md +++ b/readme.md @@ -68,9 +68,9 @@ Give india logo -Are you considering supporting the project by donating? Please DON'T!! +Are you considering supporting the project by donating? Please DO NOT!! -Instead, Help India fight the 2nd deadly wave of COVID-19. +Instead, Help India fight the second 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: @@ -94,7 +94,7 @@ Visit and make a small donation to hel # GitHub Stats Card -Copy-paste this into your markdown content, and that's it. Simple! +Copy-paste this into your markdown content, and that is it. Simple! Change the `?username=` value to your GitHub username. @@ -108,7 +108,7 @@ The implementation can be investigated at [src/calculateRank.js](./src/calculate ### Hiding individual stats -To hide any specific stats, you can pass a query parameter `&hide=` with comma-separated values. +You can pass a query parameter `&hide=` to hide any specific stats with comma-separated values. > Options: `&hide=stars,commits,prs,issues,contribs` @@ -120,7 +120,7 @@ To hide any specific stats, you can pass a query parameter `&hide=` with comma-s You can add the count of all your private contributions to the total commits count by using the query parameter `&count_private=true`. -_Note: If you are deploying this project yourself, the private contributions will be counted by default. Otherwise, you need to choose to share your private contribution counts._ +_Note: If you are deploying this project yourself, the private contributions will be counted by default. If you are using the public Vercel instance, you need to choose to [share your private contributions](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/showing-your-private-contributions-and-achievements-on-your-profile)._ > Options: `&count_private=true` @@ -148,7 +148,7 @@ Use `&theme=THEME_NAME` parameter like so : #### All inbuilt themes -dark, radical, merko, gruvbox, tokyonight, onedark, cobalt, synthwave, highcontrast, dracula +Github readme stats comes with several built-in themes (e.g. `dark`, `radical`, `merko`, `gruvbox`, `tokyonight`, `onedark`, `cobalt`, `synthwave`, `highcontrast`, `dracula`). GitHub Readme Stats Themes @@ -156,7 +156,7 @@ You can look at a preview for [all available themes](./themes/README.md) or chec ### Customization -You can customize the appearance of your `Stats Card` or `Repo Card` however you wish with URL params. +You can customize the appearance of your `Stats Card` or `Repo Card` however you wish with URL parameters. #### Common Options @@ -175,11 +175,11 @@ You can customize the appearance of your `Stats Card` or `Repo Card` however you ##### Gradient in bg_color -You can provide multiple comma-separated values in the bg_color option to render a gradient, with the following format: +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 -> 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. +> 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 is 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 @@ -190,7 +190,7 @@ You can provide multiple comma-separated values in the bg_color option to render - `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`. +- `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`. @@ -205,7 +205,7 @@ You can provide multiple comma-separated values in the bg_color option to render #### Language Card Exclusive Options -- `hide` - Hide the languages specified from the card _(Comma-separated values)_ .Default: `[] (blank array)`. +- `hide` - Hide the languages specified from the card _(Comma-separated values)_. Default: `[] (blank array)`. - `hide_title` - _(boolean)_. Default: `false`. - `layout` - Switch between two available layouts `default` & `compact`. Default: `default`. - `card_width` - Set the card's width manually _(number)_. Default `300`. @@ -214,7 +214,7 @@ 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`. > :warning: **Important:** -> Language names should be uri-escaped, as specified in [Percent Encoding](https://en.wikipedia.org/wiki/Percent-encoding) +> Language names should be URI-escaped, as specified in [Percent Encoding](https://en.wikipedia.org/wiki/Percent-encoding) > (i.e: `c++` should become `c%2B%2B`, `jupyter notebook` should become `jupyter%20notebook`, etc.) You can use > [urlencoder.org](https://www.urlencoder.org/) to help you do this automatically. @@ -222,19 +222,19 @@ You can provide multiple comma-separated values in the bg_color option to render - `hide` - Hide the languages specified from the card _(Comma-separated values)_. Default: `[] (blank array)`. - `hide_title` - _(boolean)_. Default `false`. -- `line_height` - Sets the line-height between text _(number)_. Default `25`. +- `line_height` - Sets the line height between text _(number)_. Default `25`. - `hide_progress` - Hides the progress bar and percentage _(boolean)_. Default `false`. - `custom_title` - Sets a custom title for the card _(string)_. Default `Wakatime Stats`. - `layout` - Switch between two available layouts `default` & `compact`. Default `default`. -- `langs_count` - Limit the number of languages on the card, defaults to all reported languages _(number)_. Default `50`. -- `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) _(string)_. Default `Wakapi`. +- `langs_count` - Limit the number of languages on the card, defaults to all reported languages _(number)_. +- `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) _(string)_. Default `Waka API`. - `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. _(YYYY-MM, last_7_days, last_30_days, last_6_months, last_year, or all_time)_. Default `all_time`. * * * # GitHub Extra Pins -GitHub extra pins allow you to pin more than 6 repositories in your profile using a GitHub readme profile. +GitHub extra pins allow you to pin more than six repositories in your profile using a GitHub readme profile. Yay! You are no longer limited to 6 pinned repositories. @@ -260,7 +260,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's a new feature of github-readme-stats._ +_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._ ### Usage @@ -274,7 +274,7 @@ Endpoint: `api/top-langs?username=anuraghazra` ### Exclude individual repositories -You can use `&exclude_repo=repo1,repo2` parameter to exclude individual repositories. +You can use the `&exclude_repo=repo1,repo2` parameter to exclude individual repositories. ```md [![Top Langs](https://github-readme-stats.vercel.app/api/top-langs/?username=anuraghazra&exclude_repo=github-readme-stats,anuraghazra.github.io)](https://github.com/anuraghazra/github-readme-stats) @@ -382,7 +382,7 @@ Choose from any of the [default themes](#themes) [![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) @@ -390,7 +390,7 @@ Choose from any of the [default themes](#themes) ### Quick Tip (Align The Repo Cards) -You usually won't be able to layout the images side by side. To do that you can use this approach: +By default, GitHub does not lay out the cards side by side. To do that, you can use this approach: ```html @@ -405,7 +405,7 @@ You usually won't be able to layout the images side by side. To do that you can #### [Check Out Step By Step Video Tutorial By @codeSTACKr](https://youtu.be/n6d4KHSKqGk?t=107) -Since the GitHub API only allows 5k requests per hour, my `https://github-readme-stats.vercel.app/api` could possibly hit the rate limiter. If you host it on your own Vercel server, then you don't have to worry about anything. Click on the deploy button to get started! +Since the GitHub API only allows 5k requests per hour, my `https://github-readme-stats.vercel.app/api` could possibly hit the rate limiter. If you host it on your own Vercel server, then you do not have to worry about anything. Click on the deploy button to get started! NOTE: Since [#58](https://github.com/anuraghazra/github-readme-stats/pull/58) we should be able to handle more than 5k requests and have no issues with downtime :D @@ -436,7 +436,7 @@ NOTE: Since [#58](https://github.com/anuraghazra/github-readme-stats/pull/58) we ## :sparkling_heart: Support the project -I open-source almost everything I can, and I try to reply to everyone needing help using these projects. Obviously, +I open-source almost everything I can and try to reply to everyone needing help using these projects. Obviously, 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: From 388ba06a8fb3880cae8734498c8564bb70a99e7c Mon Sep 17 00:00:00 2001 From: Akshat Goel <98082704+DecryptAG@users.noreply.github.com> Date: Tue, 4 Oct 2022 13:02:40 +0530 Subject: [PATCH 026/157] Update the Vercel deployement guide (#2102) * Update the Vercel deployement guide Updated Readme.md - The guide on deploying your own Vercel instance * docs: fix some small grammer errors Co-authored-by: rickstaa --- readme.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/readme.md b/readme.md index 6f741b745b102..8130a3346952c 100644 --- a/readme.md +++ b/readme.md @@ -414,22 +414,22 @@ 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/) -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) +1. Go to [vercel.com](https://vercel.com/). +2. Click on `Log in`. + ![](https://files.catbox.moe/pcxk33.png) +3. Sign in with GitHub by pressing `Continue with GitHub`. + ![](https://files.catbox.moe/b9oxey.png) +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. To import a project, click the `Add New...` button and select the `Project` option. + ![](https://files.catbox.moe/3n76fh.png) +9. Click the `Continue with GitHub` button, search for the required Git Repository and import it by clicking the `Import` button. Alternatively, you can import a Third-Party Git Repository using the `Import Third-Party Git Repository ->` link at the bottom of the page. + ![](https://files.catbox.moe/mg5p04.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) + ![](https://files.catbox.moe/0yclio.png) 12. Click deploy, and you're good to go. See your domains to use the API!
From acbc03dc0f2e70da946fbb75822bbe9d041fb729 Mon Sep 17 00:00:00 2001 From: nekiwo <58634064+nekiwo@users.noreply.github.com> Date: Tue, 4 Oct 2022 03:00:48 -0500 Subject: [PATCH 027/157] Fix card length during error (#2105) * Fix card length during error Fixes #1774 The size of the box should be 550px to allow 25px padding from both sides I found the width of the text using `getComputedTextLength()` method * fix: improve error card size Co-authored-by: rickstaa --- src/common/utils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/utils.js b/src/common/utils.js index ba61cf8119830..fc462d3214c9f 100644 --- a/src/common/utils.js +++ b/src/common/utils.js @@ -11,13 +11,13 @@ import { themes } from "../../themes/index.js"; */ const renderError = (message, secondaryMessage = "") => { return ` - + - + Something went wrong! file an issue at https://tiny.one/readme-stats ${encodeHTML(message)} From af97e5765bea4945e3208e63d272248b91da2b3c Mon Sep 17 00:00:00 2001 From: Matteo Pierro Date: Tue, 4 Oct 2022 12:10:50 +0100 Subject: [PATCH 028/157] fix: fetch all repos for for the stats card (#2100) * fetch all stars * stop fetching when there are repos with zero stars * remove not needed parameters from the query * add docstring * removed not needed mock * style: update formatting Co-authored-by: rickstaa --- src/fetchers/stats-fetcher.js | 78 ++++++++++++++++++++++++---- tests/api.test.js | 20 +++++++- tests/fetchStats.test.js | 95 ++++++++++++++++++++++++++++++++--- 3 files changed, 175 insertions(+), 18 deletions(-) diff --git a/src/fetchers/stats-fetcher.js b/src/fetchers/stats-fetcher.js index b9493adfdbb43..8f8a820013068 100644 --- a/src/fetchers/stats-fetcher.js +++ b/src/fetchers/stats-fetcher.js @@ -29,10 +29,10 @@ const fetcher = (variables, token) => { totalCommitContributions restrictedContributionsCount } - repositoriesContributedTo(first: 1, contributionTypes: [COMMIT, ISSUE, PULL_REQUEST, REPOSITORY]) { + repositoriesContributedTo(contributionTypes: [COMMIT, ISSUE, PULL_REQUEST, REPOSITORY]) { totalCount } - pullRequests(first: 1) { + pullRequests { totalCount } openIssues: issues(states: OPEN) { @@ -44,14 +44,41 @@ const fetcher = (variables, token) => { followers { totalCount } - repositories(first: 100, ownerAffiliations: OWNER, orderBy: {direction: DESC, field: STARGAZERS}) { + repositories(ownerAffiliations: OWNER) { totalCount + } + } + } + `, + variables, + }, + { + Authorization: `bearer ${token}`, + }, + ); +}; + +/** + * @param {import('axios').AxiosRequestHeaders} variables + * @param {string} token + */ +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 + } } } } @@ -99,6 +126,43 @@ const totalCommitsFetcher = async (username) => { return 0; }; +/** + * Fetch all the stars for all the repositories of a given username + * @param {string} username + * @param {array} repoToHide + */ +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; + endCursor = res.data.data.user.repositories.pageInfo.endCursor; + } + + return nodes + .filter((data) => !repoToHide[data.name]) + .reduce((prev, curr) => prev + curr.stargazers.totalCount, 0); +}; + /** * @param {string} username * @param {boolean} count_private @@ -166,13 +230,7 @@ async function fetchStats( stats.contributedTo = user.repositoriesContributedTo.totalCount; // Retrieve stars while filtering out repositories to be hidden - stats.totalStars = user.repositories.nodes - .filter((data) => { - return !repoToHide[data.name]; - }) - .reduce((prev, curr) => { - return prev + curr.stargazers.totalCount; - }, 0); + stats.totalStars = await totalStarsFetcher(username, repoToHide); stats.rank = calculateRank({ totalCommits: stats.totalCommits, diff --git a/tests/api.test.js b/tests/api.test.js index b0dfc59f17e2e..a6bb0920449e4 100644 --- a/tests/api.test.js +++ b/tests/api.test.js @@ -40,7 +40,20 @@ const data = { followers: { totalCount: 0 }, repositories: { totalCount: 1, + }, + }, + }, +}; + +const repositoriesData = { + data: { + user: { + repositories: { nodes: [{ stargazers: { totalCount: 100 } }], + pageInfo: { + hasNextPage: false, + cursor: "cursor", + }, }, }, }, @@ -70,7 +83,11 @@ const faker = (query, data) => { setHeader: jest.fn(), send: jest.fn(), }; - mock.onPost("https://api.github.com/graphql").reply(200, data); + mock + .onPost("https://api.github.com/graphql") + .replyOnce(200, data) + .onPost("https://api.github.com/graphql") + .replyOnce(200, repositoriesData); return { req, res }; }; @@ -138,7 +155,6 @@ describe("Test /api/", () => { it("should have proper cache", async () => { const { req, res } = faker({}, data); - mock.onPost("https://api.github.com/graphql").reply(200, data); await api(req, res); diff --git a/tests/fetchStats.test.js b/tests/fetchStats.test.js index f8eae98139442..9ccdcb2163f6d 100644 --- a/tests/fetchStats.test.js +++ b/tests/fetchStats.test.js @@ -19,13 +19,61 @@ 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 } }, { name: "test-repo-3", stargazers: { totalCount: 100 } }, + ], + pageInfo: { + hasNextPage: true, + cursor: "cursor", + }, + }, + }, + }, +}; + +const secondRepositoriesData = { + data: { + user: { + repositories: { + nodes: [ { name: "test-repo-4", stargazers: { totalCount: 50 } }, { name: "test-repo-5", stargazers: { totalCount: 50 } }, ], + pageInfo: { + hasNextPage: false, + cursor: "cursor", + }, + }, + }, + }, +}; + +const repositoriesWithZeroStarsData = { + data: { + user: { + repositories: { + nodes: [ + { name: "test-repo-1", stargazers: { totalCount: 100 } }, + { name: "test-repo-2", stargazers: { totalCount: 100 } }, + { name: "test-repo-3", stargazers: { totalCount: 100 } }, + { name: "test-repo-4", stargazers: { totalCount: 0 } }, + { name: "test-repo-5", stargazers: { totalCount: 0 } }, + ], + pageInfo: { + hasNextPage: true, + cursor: "cursor", + }, }, }, }, @@ -44,14 +92,22 @@ const error = { const mock = new MockAdapter(axios); +beforeEach(() => { + mock + .onPost("https://api.github.com/graphql") + .replyOnce(200, data) + .onPost("https://api.github.com/graphql") + .replyOnce(200, firstRepositoriesData) + .onPost("https://api.github.com/graphql") + .replyOnce(200, secondRepositoriesData); +}); + afterEach(() => { mock.reset(); }); describe("Test fetchStats", () => { it("should fetch correct stats", async () => { - mock.onPost("https://api.github.com/graphql").reply(200, data); - let stats = await fetchStats("anuraghazra"); const rank = calculateRank({ totalCommits: 100, @@ -74,7 +130,38 @@ describe("Test fetchStats", () => { }); }); + it("should stop fetching when there are repos with zero stars", async () => { + mock.reset(); + mock + .onPost("https://api.github.com/graphql") + .replyOnce(200, data) + .onPost("https://api.github.com/graphql") + .replyOnce(200, repositoriesWithZeroStarsData); + + 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 throw error", async () => { + mock.reset(); mock.onPost("https://api.github.com/graphql").reply(200, error); await expect(fetchStats("anuraghazra")).rejects.toThrow( @@ -83,8 +170,6 @@ describe("Test fetchStats", () => { }); it("should fetch and add private contributions", async () => { - mock.onPost("https://api.github.com/graphql").reply(200, data); - let stats = await fetchStats("anuraghazra", true); const rank = calculateRank({ totalCommits: 150, @@ -108,7 +193,6 @@ describe("Test fetchStats", () => { }); it("should fetch total commits", async () => { - mock.onPost("https://api.github.com/graphql").reply(200, data); mock .onGet("https://api.github.com/search/commits?q=author:anuraghazra") .reply(200, { total_count: 1000 }); @@ -136,7 +220,6 @@ describe("Test fetchStats", () => { }); it("should exclude stars of the `test-repo-1` repository", async () => { - mock.onPost("https://api.github.com/graphql").reply(200, data); mock .onGet("https://api.github.com/search/commits?q=author:anuraghazra") .reply(200, { total_count: 1000 }); From 94d0978d2bf7c5324513ac924cb42afe1e7774cc Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Tue, 4 Oct 2022 14:19:30 +0200 Subject: [PATCH 029/157] docs: fix readme logo alignment (#2112) --- readme.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 8130a3346952c..c905155f2164d 100644 --- a/readme.md +++ b/readme.md @@ -62,7 +62,8 @@ Türkçe

-

Love the project? Please consider donating to help it improve! + +

Love the project? Please consider donating to help it improve!

Give india logo From aae83cb22e64e48b3b0546b719bb25c328c31aa3 Mon Sep 17 00:00:00 2001 From: rickstaa Date: Wed, 5 Oct 2022 00:47:14 +0200 Subject: [PATCH 030/157] fix: temporary disable multi page star fetch --- src/fetchers/stats-fetcher.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/fetchers/stats-fetcher.js b/src/fetchers/stats-fetcher.js index 8f8a820013068..4fa2604455330 100644 --- a/src/fetchers/stats-fetcher.js +++ b/src/fetchers/stats-fetcher.js @@ -152,9 +152,10 @@ const totalStarsFetcher = async (username, repoToHide) => { (node) => node.stargazers.totalCount !== 0, ); nodes.push(...nodesWithStars); - hasNextPage = - allNodes.length === nodesWithStars.length && - res.data.data.user.repositories.pageInfo.hasNextPage; + // hasNextPage = + // allNodes.length === nodesWithStars.length && + // res.data.data.user.repositories.pageInfo.hasNextPage; + hasNextPage = false // NOTE: Temporarily disable fetching of multiple pages. endCursor = res.data.data.user.repositories.pageInfo.endCursor; } From cea4a39548e81f387b819b9dab81e88f41ff1c20 Mon Sep 17 00:00:00 2001 From: rickstaa Date: Fri, 7 Oct 2022 11:09:31 +0200 Subject: [PATCH 031/157] ci: improve theme preview action This commit makes sure that theme PRs that contain invalid JSON are labeled `invalid` and changes are requested. --- scripts/preview-theme.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/scripts/preview-theme.js b/scripts/preview-theme.js index 58aad0282e764..f7c0719476d86 100644 --- a/scripts/preview-theme.js +++ b/scripts/preview-theme.js @@ -24,7 +24,7 @@ const THEME_PR_FAIL_TEXT = ":x: Theme PR does not adhere to our guidelines."; const THEME_PR_SUCCESS_TEXT = ":heavy_check_mark: Theme PR does adhere to our guidelines."; const FAIL_TEXT = ` - \rUnfortunately, your theme PR 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 Unfortunately, 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 15 days** if no changes are made. After this time, you must re-open the PR for it to be reviewed. `; const THEME_CONTRIB_GUIDELINESS = ` @@ -558,6 +558,21 @@ export const run = async (prNumber) => { info(`DRY_RUN: Review reason: ${reviewReason}`); } } catch (error) { + debug("Set review state to `REQUEST_CHANGES` and add `invalid` label..."); + if (!dryRun) { + await addReview( + octokit, + pullRequestId, + owner, + repo, + "REQUEST_CHANGES", + error.message, + ); + await addRemoveLabel(octokit, pullRequestId, owner, repo, "invalid", true); + } else { + info(`DRY_RUN: Review state: REQUEST_CHANGES`); + info(`DRY_RUN: Review reason: ${error.message}`); + } setFailed(error.message); } }; From 04595dfe62fca2f0cf6a7a7b9d24d3694cf6c4b0 Mon Sep 17 00:00:00 2001 From: rickstaa Date: Fri, 7 Oct 2022 11:10:48 +0200 Subject: [PATCH 032/157] style: improve formatting --- scripts/preview-theme.js | 9 ++++++++- src/fetchers/stats-fetcher.js | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/scripts/preview-theme.js b/scripts/preview-theme.js index f7c0719476d86..1747ee973f368 100644 --- a/scripts/preview-theme.js +++ b/scripts/preview-theme.js @@ -568,7 +568,14 @@ export const run = async (prNumber) => { "REQUEST_CHANGES", error.message, ); - await addRemoveLabel(octokit, pullRequestId, owner, repo, "invalid", true); + await addRemoveLabel( + octokit, + pullRequestId, + owner, + repo, + "invalid", + true, + ); } else { info(`DRY_RUN: Review state: REQUEST_CHANGES`); info(`DRY_RUN: Review reason: ${error.message}`); diff --git a/src/fetchers/stats-fetcher.js b/src/fetchers/stats-fetcher.js index 4fa2604455330..409475644655b 100644 --- a/src/fetchers/stats-fetcher.js +++ b/src/fetchers/stats-fetcher.js @@ -155,7 +155,7 @@ const totalStarsFetcher = async (username, repoToHide) => { // hasNextPage = // allNodes.length === nodesWithStars.length && // res.data.data.user.repositories.pageInfo.hasNextPage; - hasNextPage = false // NOTE: Temporarily disable fetching of multiple pages. + hasNextPage = false; // NOTE: Temporarily disable fetching of multiple pages. endCursor = res.data.data.user.repositories.pageInfo.endCursor; } From bcb8ae92818de7430a9b340e2b78cd8437ee65e6 Mon Sep 17 00:00:00 2001 From: rickstaa Date: Fri, 7 Oct 2022 11:13:01 +0200 Subject: [PATCH 033/157] style: improve small syntax error --- scripts/preview-theme.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/preview-theme.js b/scripts/preview-theme.js index 1747ee973f368..0dc3da253d22a 100644 --- a/scripts/preview-theme.js +++ b/scripts/preview-theme.js @@ -24,7 +24,7 @@ const THEME_PR_FAIL_TEXT = ":x: Theme PR does not adhere to our guidelines."; const THEME_PR_SUCCESS_TEXT = ":heavy_check_mark: Theme PR does adhere to our guidelines."; const FAIL_TEXT = ` - \r Unfortunately, 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\ + \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 15 days** if no changes are made. After this time, you must re-open the PR for it to be reviewed. `; const THEME_CONTRIB_GUIDELINESS = ` From e8dfbde7bb4e05e3e6600e3837ebbdd1b9ff5f3b Mon Sep 17 00:00:00 2001 From: Taehyun Hwang Date: Fri, 7 Oct 2022 19:33:54 +0900 Subject: [PATCH 034/157] Add format script to pre-commit hook (#2146) * Add format script to pre-commit hook * build: add husky prepare step * build: add lint-staged * build: add lint-staged Co-authored-by: rickstaa --- .husky/.gitignore | 1 + .husky/pre-commit | 5 + package-lock.json | 1269 +++++++++++++++++++++++++++++++-------------- package.json | 14 +- 4 files changed, 894 insertions(+), 395 deletions(-) create mode 100644 .husky/.gitignore create mode 100755 .husky/pre-commit diff --git a/.husky/.gitignore b/.husky/.gitignore new file mode 100644 index 0000000000000..31354ec138999 --- /dev/null +++ b/.husky/.gitignore @@ -0,0 +1 @@ +_ diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000000000..e1c12eb032030 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,5 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +npm test +npx lint-staged diff --git a/package-lock.json b/package-lock.json index 2235a4b45ac63..048c316bfde58 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,10 +25,11 @@ "axios-mock-adapter": "^1.18.1", "color-contrast-checker": "^2.1.0", "hjson": "^3.2.2", - "husky": "^4.2.5", + "husky": "^8.0.0", "jest": "^29.0.3", "jest-environment-jsdom": "^29.0.3", "js-yaml": "^4.1.0", + "lint-staged": "^13.0.3", "lodash.snakecase": "^4.1.1", "parse-diff": "^0.7.0", "prettier": "^2.1.2" @@ -1427,12 +1428,6 @@ "integrity": "sha512-Sq1itGUKUX1ap7GgZlrzdBydjbsJL/NSQt/4wkAxUJ7/OS5c2WkoN6WSpWc2Yc5wtKMZOUA0VCs/j2XJadN3HA==", "dev": true }, - "node_modules/@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true - }, "node_modules/@types/prettier": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", @@ -1542,6 +1537,19 @@ "node": ">= 6.0.0" } }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -1609,6 +1617,15 @@ "node": ">=6.0" } }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -1869,18 +1886,99 @@ "node": ">=10" } }, - "node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, "node_modules/cjs-module-lexer": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", "dev": true }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-truncate": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", + "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", + "dev": true, + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/cli-truncate/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -1932,6 +2030,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -1944,11 +2048,14 @@ "node": ">= 0.8" } }, - "node_modules/compare-versions": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", - "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==", - "dev": true + "node_modules/commander": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", + "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } }, "node_modules/concat-map": { "version": "0.0.1", @@ -1965,22 +2072,6 @@ "safe-buffer": "~5.1.1" } }, - "node_modules/cosmiconfig": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", - "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", - "dev": true, - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -2142,6 +2233,12 @@ "node": ">=10" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, "node_modules/electron-to-chromium": { "version": "1.4.260", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.260.tgz", @@ -2373,21 +2470,6 @@ "node": ">=8" } }, - "node_modules/find-versions": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-4.0.0.tgz", - "integrity": "sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ==", - "dev": true, - "dependencies": { - "semver-regex": "^3.1.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/follow-redirects": { "version": "1.15.2", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", @@ -2611,33 +2693,18 @@ } }, "node_modules/husky": { - "version": "4.3.8", - "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.8.tgz", - "integrity": "sha512-LCqqsB0PzJQ/AlCgfrfzRe3e3+NvmefAdKQhRYpxS4u6clblBoDdzzvHi8fmxKRzvMxPY/1WZWzomPZww0Anow==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.1.tgz", + "integrity": "sha512-xs7/chUH/CKdOCs7Zy0Aev9e/dKOMZf3K1Az1nar3tzlv0jfqnYtu235bstsWTmXOR0EfINrPa97yy4Lz6RiKw==", "dev": true, - "hasInstallScript": true, - "dependencies": { - "chalk": "^4.0.0", - "ci-info": "^2.0.0", - "compare-versions": "^3.6.0", - "cosmiconfig": "^7.0.0", - "find-versions": "^4.0.0", - "opencollective-postinstall": "^2.0.2", - "pkg-dir": "^5.0.0", - "please-upgrade-node": "^3.2.0", - "slash": "^3.0.0", - "which-pm-runs": "^1.0.0" - }, "bin": { - "husky-run": "bin/run.js", - "husky-upgrade": "lib/upgrader/bin.js" + "husky": "lib/bin.js" }, "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/husky" + "url": "https://github.com/sponsors/typicode" } }, "node_modules/iconv-lite": { @@ -2652,22 +2719,6 @@ "node": ">=0.10.0" } }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/import-local": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", @@ -3920,12 +3971,218 @@ "node": ">= 0.8.0" } }, + "node_modules/lilconfig": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz", + "integrity": "sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, + "node_modules/lint-staged": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.0.3.tgz", + "integrity": "sha512-9hmrwSCFroTSYLjflGI8Uk+GWAwMB4OlpU4bMJEAT5d/llQwtYKoim4bLOyLCuWFAhWEupE0vkIFqtw/WIsPug==", + "dev": true, + "dependencies": { + "cli-truncate": "^3.1.0", + "colorette": "^2.0.17", + "commander": "^9.3.0", + "debug": "^4.3.4", + "execa": "^6.1.0", + "lilconfig": "2.0.5", + "listr2": "^4.0.5", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-inspect": "^1.12.2", + "pidtree": "^0.6.0", + "string-argv": "^0.3.1", + "yaml": "^2.1.1" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": "^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/lint-staged/node_modules/execa": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-6.1.0.tgz", + "integrity": "sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^3.0.1", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/human-signals": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-3.0.1.tgz", + "integrity": "sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==", + "dev": true, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/lint-staged/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-4.0.5.tgz", + "integrity": "sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA==", + "dev": true, + "dependencies": { + "cli-truncate": "^2.1.0", + "colorette": "^2.0.16", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rfdc": "^1.3.0", + "rxjs": "^7.5.5", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "enquirer": ">= 2.3.0 < 3" + }, + "peerDependenciesMeta": { + "enquirer": { + "optional": true + } + } + }, + "node_modules/listr2/node_modules/cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "dependencies": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -3950,6 +4207,55 @@ "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", "dev": true }, + "node_modules/log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -4166,6 +4472,15 @@ "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==", "dev": true }, + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -4190,15 +4505,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/opencollective-postinstall": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", - "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", - "dev": true, - "bin": { - "opencollective-postinstall": "index.js" - } - }, "node_modules/optionator": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", @@ -4258,23 +4564,26 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, "engines": { "node": ">=6" } @@ -4348,15 +4657,6 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -4375,80 +4675,25 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", - "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", - "dev": true, - "dependencies": { - "find-up": "^5.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", "dev": true, - "dependencies": { - "p-locate": "^5.0.0" + "bin": { + "pidtree": "bin/pidtree.js" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10" } }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "node_modules/pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/please-upgrade-node": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", - "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", - "dev": true, - "dependencies": { - "semver-compare": "^1.0.0" + "node": ">= 6" } }, "node_modules/prelude-ls": { @@ -4613,15 +4858,6 @@ "node": ">=8" } }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/resolve.exports": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", @@ -4631,6 +4867,34 @@ "node": ">=10" } }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, + "node_modules/rxjs": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz", + "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -4664,24 +4928,6 @@ "semver": "bin/semver.js" } }, - "node_modules/semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", - "dev": true - }, - "node_modules/semver-regex": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-3.1.4.tgz", - "integrity": "sha512-6IiqeZNgq01qGf0TId0t3NvKzSvUsjcpdEO3AQNeIjR6A2+ckTnQlDpl4qu1bjRv0RzN3FP9hzFmws3lKqRWkA==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -4715,13 +4961,53 @@ "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", "dev": true }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.1.1.tgz", + "integrity": "sha512-qDOv24WjnYuL+wbwHdlsYZFy+cgPtrYw0Tn7GLORicQp9BkQLzrgI3Pm4VyR9ERZ41YTn7KlMPuL1n05WdZvmg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", "dev": true, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/source-map": { @@ -4761,6 +5047,15 @@ "node": ">=10" } }, + "node_modules/string-argv": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", + "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", + "dev": true, + "engines": { + "node": ">=0.6.19" + } + }, "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -4915,6 +5210,12 @@ "node": ">=8" } }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -4969,6 +5270,12 @@ "node": ">=12" } }, + "node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true + }, "node_modules/tunnel": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", @@ -5178,15 +5485,6 @@ "node": ">= 8" } }, - "node_modules/which-pm-runs": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", - "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -5283,12 +5581,12 @@ "dev": true }, "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.1.3.tgz", + "integrity": "sha512-AacA8nRULjKMX2DvWvOAdBZMOfQlypSFkjcOcu9FalllIDJ1kvlREzcdIZmidQUqqeMv7jorHjq2HlLv/+c2lg==", "dev": true, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/yargs": { @@ -6471,12 +6769,6 @@ "integrity": "sha512-Sq1itGUKUX1ap7GgZlrzdBydjbsJL/NSQt/4wkAxUJ7/OS5c2WkoN6WSpWc2Yc5wtKMZOUA0VCs/j2XJadN3HA==", "dev": true }, - "@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true - }, "@types/prettier": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", @@ -6570,6 +6862,16 @@ "debug": "4" } }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, "ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -6616,6 +6918,12 @@ "integrity": "sha512-eigU3vhqSO+Z8BKDnVLN/ompjhf3pYzecKXz8+whRy+9gZu8n1TCGfwzQUUPnqdHl9ax1Hr9031orZ+UOEYr7Q==", "dev": true }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -6808,18 +7116,71 @@ "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, "cjs-module-lexer": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", "dev": true }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-truncate": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", + "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", + "dev": true, + "requires": { + "slice-ansi": "^5.0.0", + "string-width": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + } + } + }, "cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -6864,6 +7225,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -6873,10 +7240,10 @@ "delayed-stream": "~1.0.0" } }, - "compare-versions": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", - "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==", + "commander": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", + "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==", "dev": true }, "concat-map": { @@ -6894,19 +7261,6 @@ "safe-buffer": "~5.1.1" } }, - "cosmiconfig": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", - "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", - "dev": true, - "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - } - }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -7035,6 +7389,12 @@ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==" }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, "electron-to-chromium": { "version": "1.4.260", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.260.tgz", @@ -7208,15 +7568,6 @@ "path-exists": "^4.0.0" } }, - "find-versions": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-4.0.0.tgz", - "integrity": "sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ==", - "dev": true, - "requires": { - "semver-regex": "^3.1.2" - } - }, "follow-redirects": { "version": "1.15.2", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", @@ -7371,22 +7722,10 @@ "dev": true }, "husky": { - "version": "4.3.8", - "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.8.tgz", - "integrity": "sha512-LCqqsB0PzJQ/AlCgfrfzRe3e3+NvmefAdKQhRYpxS4u6clblBoDdzzvHi8fmxKRzvMxPY/1WZWzomPZww0Anow==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "ci-info": "^2.0.0", - "compare-versions": "^3.6.0", - "cosmiconfig": "^7.0.0", - "find-versions": "^4.0.0", - "opencollective-postinstall": "^2.0.2", - "pkg-dir": "^5.0.0", - "please-upgrade-node": "^3.2.0", - "slash": "^3.0.0", - "which-pm-runs": "^1.0.0" - } + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.1.tgz", + "integrity": "sha512-xs7/chUH/CKdOCs7Zy0Aev9e/dKOMZf3K1Az1nar3tzlv0jfqnYtu235bstsWTmXOR0EfINrPa97yy4Lz6RiKw==", + "dev": true }, "iconv-lite": { "version": "0.6.3", @@ -7397,16 +7736,6 @@ "safer-buffer": ">= 2.1.2 < 3.0.0" } }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, "import-local": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", @@ -8354,12 +8683,145 @@ "type-check": "~0.3.2" } }, + "lilconfig": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz", + "integrity": "sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==", + "dev": true + }, "lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, + "lint-staged": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.0.3.tgz", + "integrity": "sha512-9hmrwSCFroTSYLjflGI8Uk+GWAwMB4OlpU4bMJEAT5d/llQwtYKoim4bLOyLCuWFAhWEupE0vkIFqtw/WIsPug==", + "dev": true, + "requires": { + "cli-truncate": "^3.1.0", + "colorette": "^2.0.17", + "commander": "^9.3.0", + "debug": "^4.3.4", + "execa": "^6.1.0", + "lilconfig": "2.0.5", + "listr2": "^4.0.5", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-inspect": "^1.12.2", + "pidtree": "^0.6.0", + "string-argv": "^0.3.1", + "yaml": "^2.1.1" + }, + "dependencies": { + "execa": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-6.1.0.tgz", + "integrity": "sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^3.0.1", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + } + }, + "human-signals": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-3.0.1.tgz", + "integrity": "sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==", + "dev": true + }, + "is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true + }, + "mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true + }, + "npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "requires": { + "path-key": "^4.0.0" + } + }, + "onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "requires": { + "mimic-fn": "^4.0.0" + } + }, + "path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true + }, + "strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true + } + } + }, + "listr2": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-4.0.5.tgz", + "integrity": "sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA==", + "dev": true, + "requires": { + "cli-truncate": "^2.1.0", + "colorette": "^2.0.16", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rfdc": "^1.3.0", + "rxjs": "^7.5.5", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "requires": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + } + }, + "slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + } + } + }, "locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -8381,6 +8843,42 @@ "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", "dev": true }, + "log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "dev": true, + "requires": { + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" + }, + "dependencies": { + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + } + } + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -8552,6 +9050,12 @@ "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==", "dev": true }, + "object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -8570,12 +9074,6 @@ "mimic-fn": "^2.1.0" } }, - "opencollective-postinstall": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", - "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", - "dev": true - }, "optionator": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", @@ -8619,21 +9117,21 @@ } } }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, "parse-diff": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/parse-diff/-/parse-diff-0.7.1.tgz", @@ -8685,12 +9183,6 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -8703,60 +9195,18 @@ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, + "pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true + }, "pirates": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", "dev": true }, - "pkg-dir": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", - "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", - "dev": true, - "requires": { - "find-up": "^5.0.0" - }, - "dependencies": { - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - } - } - }, - "please-upgrade-node": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", - "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", - "dev": true, - "requires": { - "semver-compare": "^1.0.0" - } - }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -8878,18 +9328,37 @@ } } }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, "resolve.exports": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", "dev": true }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, + "rxjs": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz", + "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==", + "dev": true, + "requires": { + "tslib": "^2.1.0" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -8917,18 +9386,6 @@ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, - "semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", - "dev": true - }, - "semver-regex": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-3.1.4.tgz", - "integrity": "sha512-6IiqeZNgq01qGf0TId0t3NvKzSvUsjcpdEO3AQNeIjR6A2+ckTnQlDpl4qu1bjRv0RzN3FP9hzFmws3lKqRWkA==", - "dev": true - }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -8962,6 +9419,30 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, + "slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "requires": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.1.1.tgz", + "integrity": "sha512-qDOv24WjnYuL+wbwHdlsYZFy+cgPtrYw0Tn7GLORicQp9BkQLzrgI3Pm4VyR9ERZ41YTn7KlMPuL1n05WdZvmg==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true + } + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -8993,6 +9474,12 @@ "escape-string-regexp": "^2.0.0" } }, + "string-argv": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", + "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", + "dev": true + }, "string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -9102,6 +9589,12 @@ "minimatch": "^3.0.4" } }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, "tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -9144,6 +9637,12 @@ "punycode": "^2.1.1" } }, + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true + }, "tunnel": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", @@ -9292,12 +9791,6 @@ "isexe": "^2.0.0" } }, - "which-pm-runs": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", - "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==", - "dev": true - }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -9362,9 +9855,9 @@ "dev": true }, "yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.1.3.tgz", + "integrity": "sha512-AacA8nRULjKMX2DvWvOAdBZMOfQlypSFkjcOcu9FalllIDJ1kvlREzcdIZmidQUqqeMv7jorHjq2HlLv/+c2lg==", "dev": true }, "yargs": { diff --git a/package.json b/package.json index ffadefdeda100..5fc4492764901 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,9 @@ "preview-theme": "node scripts/preview-theme", "close-stale-theme-prs": "node scripts/close-stale-theme-prs", "generate-langs-json": "node scripts/generate-langs-json", - "format": "./node_modules/.bin/prettier --write .", - "format:check": "./node_modules/.bin/prettier --check ." + "format": "prettier --write .", + "format:check": "prettier --check .", + "prepare": "husky install" }, "author": "Anurag Hazra", "license": "MIT", @@ -27,10 +28,11 @@ "axios-mock-adapter": "^1.18.1", "color-contrast-checker": "^2.1.0", "hjson": "^3.2.2", - "husky": "^4.2.5", + "husky": "^8.0.0", "jest": "^29.0.3", "jest-environment-jsdom": "^29.0.3", "js-yaml": "^4.1.0", + "lint-staged": "^13.0.3", "lodash.snakecase": "^4.1.1", "parse-diff": "^0.7.0", "prettier": "^2.1.2" @@ -43,9 +45,7 @@ "upgrade": "^1.1.0", "word-wrap": "^1.2.3" }, - "husky": { - "hooks": { - "pre-commit": "npm test" - } + "lint-staged": { + "*.{js,css,md}": "prettier --write" } } From 15620a11db5c57c5ac066ba4b0caf31a09c65ea7 Mon Sep 17 00:00:00 2001 From: rickstaa Date: Fri, 7 Oct 2022 12:42:04 +0200 Subject: [PATCH 035/157] test: fix tests --- src/fetchers/stats-fetcher.js | 2 +- tests/fetchStats.test.js | 30 +++++++++++++++++++----------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/fetchers/stats-fetcher.js b/src/fetchers/stats-fetcher.js index 409475644655b..941c7e145a14f 100644 --- a/src/fetchers/stats-fetcher.js +++ b/src/fetchers/stats-fetcher.js @@ -155,7 +155,7 @@ const totalStarsFetcher = async (username, repoToHide) => { // hasNextPage = // allNodes.length === nodesWithStars.length && // res.data.data.user.repositories.pageInfo.hasNextPage; - hasNextPage = false; // NOTE: Temporarily disable fetching of multiple pages. + hasNextPage = false; // NOTE: Temporarily disable fetching of multiple pages. Done because of #2130. endCursor = res.data.data.user.repositories.pageInfo.endCursor; } diff --git a/tests/fetchStats.test.js b/tests/fetchStats.test.js index 9ccdcb2163f6d..192146ea5fbe0 100644 --- a/tests/fetchStats.test.js +++ b/tests/fetchStats.test.js @@ -97,9 +97,9 @@ beforeEach(() => { .onPost("https://api.github.com/graphql") .replyOnce(200, data) .onPost("https://api.github.com/graphql") - .replyOnce(200, firstRepositoriesData) - .onPost("https://api.github.com/graphql") - .replyOnce(200, secondRepositoriesData); + .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. }); afterEach(() => { @@ -114,7 +114,8 @@ describe("Test fetchStats", () => { totalRepos: 5, followers: 100, contributions: 61, - stargazers: 400, + // 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. prs: 300, issues: 200, }); @@ -125,7 +126,8 @@ describe("Test fetchStats", () => { totalCommits: 100, totalIssues: 200, totalPRs: 300, - totalStars: 400, + // 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. rank, }); }); @@ -176,7 +178,8 @@ describe("Test fetchStats", () => { totalRepos: 5, followers: 100, contributions: 61, - stargazers: 400, + // 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. prs: 300, issues: 200, }); @@ -187,7 +190,8 @@ describe("Test fetchStats", () => { totalCommits: 150, totalIssues: 200, totalPRs: 300, - totalStars: 400, + // 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. rank, }); }); @@ -203,7 +207,8 @@ describe("Test fetchStats", () => { totalRepos: 5, followers: 100, contributions: 61, - stargazers: 400, + // 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. prs: 300, issues: 200, }); @@ -214,7 +219,8 @@ describe("Test fetchStats", () => { totalCommits: 1050, totalIssues: 200, totalPRs: 300, - totalStars: 400, + // 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. rank, }); }); @@ -230,7 +236,8 @@ describe("Test fetchStats", () => { totalRepos: 5, followers: 100, contributions: 61, - stargazers: 300, + // 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. prs: 300, issues: 200, }); @@ -241,7 +248,8 @@ describe("Test fetchStats", () => { totalCommits: 1050, totalIssues: 200, totalPRs: 300, - totalStars: 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. rank, }); }); From df243efdd54231d597f825d8578f9012aaf9c6e7 Mon Sep 17 00:00:00 2001 From: rickstaa Date: Fri, 7 Oct 2022 14:32:01 +0200 Subject: [PATCH 036/157] docs: update readme --- readme.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index c905155f2164d..90c2723cf2def 100644 --- a/readme.md +++ b/readme.md @@ -406,14 +406,16 @@ By default, GitHub does not lay out the cards side by side. To do that, you can #### [Check Out Step By Step Video Tutorial By @codeSTACKr](https://youtu.be/n6d4KHSKqGk?t=107) +> **NOTE**: 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 for more information). +> Since the GitHub API only allows 5k requests per hour, my `https://github-readme-stats.vercel.app/api` could possibly hit the rate limiter. If you host it on your own Vercel server, then you do not have to worry about anything. Click on the deploy button to get started! -NOTE: Since [#58](https://github.com/anuraghazra/github-readme-stats/pull/58) we should be able to handle more than 5k requests and have no issues with downtime :D +**NOTE:** Since [#58](https://github.com/anuraghazra/github-readme-stats/pull/58), we should be able to handle more than 5k requests and have fewer issues with downtime :grin:. [![Deploy to Vercel](https://vercel.com/button)](https://vercel.com/import/project?template=https://github.com/anuraghazra/github-readme-stats)
- Guide on setting up Vercel 🔨 + :hammer_and_wrench: Step-by-step guide on setting up your own Vercel instance 1. Go to [vercel.com](https://vercel.com/). 2. Click on `Log in`. From 15533596e6d6702606644e9ec2492e35db13c35b Mon Sep 17 00:00:00 2001 From: rickstaa Date: Fri, 7 Oct 2022 14:40:19 +0200 Subject: [PATCH 037/157] docs: add admonition boxes --- readme.md | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/readme.md b/readme.md index 90c2723cf2def..7dabb06b6b41e 100644 --- a/readme.md +++ b/readme.md @@ -103,9 +103,8 @@ Change the `?username=` value to your GitHub username. [![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra)](https://github.com/anuraghazra/github-readme-stats) ``` -_Note: Available ranks are S+ (top 1%), S (top 25%), A++ (top 45%), A+ (top 60%), and B+ (everyone). -The values are calculated by using the [cumulative distribution function](https://en.wikipedia.org/wiki/Cumulative_distribution_function) using commits, contributions, issues, stars, pull requests, followers, and owned repositories. -The implementation can be investigated at [src/calculateRank.js](./src/calculateRank.js)._ +> **Note** +> Available ranks are S+ (top 1%), S (top 25%), A++ (top 45%), A+ (top 60%), and B+ (everyone). The values are calculated by using the [cumulative distribution function](https://en.wikipedia.org/wiki/Cumulative_distribution_function) using commits, contributions, issues, stars, pull requests, followers, and owned repositories. The implementation can be investigated at [src/calculateRank.js](./src/calculateRank.js). ### Hiding individual stats @@ -121,7 +120,8 @@ You can pass a query parameter `&hide=` to hide any specific stats with comma-se You can add the count of all your private contributions to the total commits count by using the query parameter `&count_private=true`. -_Note: If you are deploying this project yourself, the private contributions will be counted by default. If you are using the public Vercel instance, you need to choose to [share your private contributions](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/showing-your-private-contributions-and-achievements-on-your-profile)._ +> **Note** +> If you are deploying this project yourself, the private contributions will be counted by default. If you are using the public Vercel instance, you need to choose to [share your private contributions](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/showing-your-private-contributions-and-achievements-on-your-profile). > Options: `&count_private=true` @@ -172,7 +172,8 @@ You can customize the appearance of your `Stats Card` or `Repo Card` however you - `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. +> **Note** +> The minimum of cache_seconds is currently 4 hours as a temporary fix for PATs exhaustion. ##### Gradient in bg_color @@ -180,6 +181,7 @@ You can provide multiple comma-separated values in the bg_color option to render &bg_color=DEG,COLOR1,COLOR2,COLOR3...COLOR10 +> **Note** > 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 is 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 @@ -197,8 +199,8 @@ 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`. -> Note on `hide_rank`: -> When hide_rank=`true`, the minimum card width is 270 px + the title length and padding. +> **Note** +> Note on `hide_rank`: When hide_rank=`true`, the minimum card width is 270 px + the title length and padding. #### Repo Card Exclusive Options @@ -321,7 +323,8 @@ 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)](https://github.com/anuraghazra/github-readme-stats) ``` -> Note: Please be aware that we currently only show data from Wakatime profiles that are public. +> **Note**: +> Please be aware that we currently only show data from Wakatime profiles that are public. ### Demo @@ -406,11 +409,13 @@ By default, GitHub does not lay out the cards side by side. To do that, you can #### [Check Out Step By Step Video Tutorial By @codeSTACKr](https://youtu.be/n6d4KHSKqGk?t=107) -> **NOTE**: 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 for more information). +> **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 for more information). > Since the GitHub API only allows 5k requests per hour, my `https://github-readme-stats.vercel.app/api` could possibly hit the rate limiter. If you host it on your own Vercel server, then you do not have to worry about anything. Click on the deploy button to get started! -**NOTE:** Since [#58](https://github.com/anuraghazra/github-readme-stats/pull/58), we should be able to handle more than 5k requests and have fewer issues with downtime :grin:. +> **Note** +> Since [#58](https://github.com/anuraghazra/github-readme-stats/pull/58), we should be able to handle more than 5k requests and have fewer issues with downtime :grin:. [![Deploy to Vercel](https://vercel.com/button)](https://vercel.com/import/project?template=https://github.com/anuraghazra/github-readme-stats) From 5c514dbda09999decf13b97b9576087403f216aa Mon Sep 17 00:00:00 2001 From: rickstaa Date: Fri, 7 Oct 2022 14:43:16 +0200 Subject: [PATCH 038/157] docs: improve admonition boxes --- readme.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/readme.md b/readme.md index 7dabb06b6b41e..be15bee730d76 100644 --- a/readme.md +++ b/readme.md @@ -182,7 +182,7 @@ You can provide multiple comma-separated values in the bg_color option to render &bg_color=DEG,COLOR1,COLOR2,COLOR3...COLOR10 > **Note** -> 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 is 2 hours (7200 seconds). Also, note that the cache is clamped to a minimum of 2 hours and a maximum of 24 hours. +> Repo cards have a default cache of 4 hours (14400 seconds) if the fork count & star count is less than 1k; otherwise, it is 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 @@ -200,7 +200,7 @@ You can provide multiple comma-separated values in the bg_color option to render - `disable_animations` - Disables all animations in the card _(boolean)_. Default: `false`. > **Note** -> 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 @@ -216,7 +216,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`. -> :warning: **Important:** +> **Warning** > Language names should be URI-escaped, as specified in [Percent Encoding](https://en.wikipedia.org/wiki/Percent-encoding) > (i.e: `c++` should become `c%2B%2B`, `jupyter notebook` should become `jupyter%20notebook`, etc.) You can use > [urlencoder.org](https://www.urlencoder.org/) to help you do this automatically. @@ -263,7 +263,8 @@ 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._ +> **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._ ### Usage From d7451d8288d700d9695689a8d2a3076994e29d22 Mon Sep 17 00:00:00 2001 From: rickstaa Date: Fri, 7 Oct 2022 14:53:51 +0200 Subject: [PATCH 039/157] docs: improve caching documentation --- readme.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/readme.md b/readme.md index be15bee730d76..9c35b708fb43f 100644 --- a/readme.md +++ b/readme.md @@ -172,8 +172,8 @@ You can customize the appearance of your `Stats Card` or `Repo Card` however you - `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. +> **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. ##### Gradient in bg_color @@ -181,9 +181,6 @@ You can provide multiple comma-separated values in the bg_color option to render &bg_color=DEG,COLOR1,COLOR2,COLOR3...COLOR10 -> **Note** -> Repo cards have a default cache of 4 hours (14400 seconds) if the fork count & star count is less than 1k; otherwise, it is 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)`. @@ -411,8 +408,8 @@ By default, GitHub does not lay out the cards side by side. To do that, you can #### [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 for more information). -> +> 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). + Since the GitHub API only allows 5k requests per hour, my `https://github-readme-stats.vercel.app/api` could possibly hit the rate limiter. If you host it on your own Vercel server, then you do not have to worry about anything. Click on the deploy button to get started! > **Note** From 343058cc1551e91684bd88fbe415fe6038b1eeb0 Mon Sep 17 00:00:00 2001 From: Shivam Kotak Date: Fri, 7 Oct 2022 19:52:02 +0530 Subject: [PATCH 040/157] fix: adding doc strings to files in src folder where it was missing (#2129) * fix: adding doc strings to files in src folder where it was missing * refactor: add docstrings * style: run formatter Co-authored-by: rickstaa --- src/calculateRank.js | 20 ++-- src/cards/repo-card.js | 33 +++++-- src/cards/stats-card.js | 8 +- src/cards/top-languages-card.js | 81 ++++++++++------ src/cards/wakatime-card.js | 64 +++++++------ src/common/Card.js | 18 ++-- src/common/I18n.js | 3 + src/common/createProgressNode.js | 12 +++ src/common/utils.js | 133 ++++++++++++++++---------- src/fetchers/repo-fetcher.js | 15 ++- src/fetchers/stats-fetcher.js | 43 ++++++--- src/fetchers/top-languages-fetcher.js | 15 ++- src/fetchers/wakatime-fetcher.js | 6 +- src/getStyles.js | 32 +++++-- src/translations.js | 13 +++ 15 files changed, 322 insertions(+), 174 deletions(-) diff --git a/src/calculateRank.js b/src/calculateRank.js index 6c161f3f87dd8..85d965802b5e9 100644 --- a/src/calculateRank.js +++ b/src/calculateRank.js @@ -4,9 +4,9 @@ * * @see https://stackoverflow.com/a/5263759/10629172 * - * @param {string} mean - * @param {number} sigma - * @param {number} to + * @param {string} mean The mean of the normal distribution. + * @param {number} sigma The standard deviation of the normal distribution. + * @param {number} to The value to calculate the probability for. * @returns {number} Probability. */ function normalcdf(mean, sigma, to) { @@ -29,13 +29,13 @@ function normalcdf(mean, sigma, to) { /** * Calculates the users rank. * - * @param {number} totalRepos - * @param {number} totalCommits - * @param {number} contributions - * @param {number} followers - * @param {number} prs - * @param {number} issues - * @param {number} stargazers + * @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. * @returns {{level: string, score: number}}} The users rank. */ function calculateRank({ diff --git a/src/cards/repo-card.js b/src/cards/repo-card.js index 5730ea4ff0e60..a306c1d56a561 100644 --- a/src/cards/repo-card.js +++ b/src/cards/repo-card.js @@ -14,9 +14,11 @@ import { import { repoCardLocales } from "../translations.js"; /** - * @param {string} label - * @param {string} textColor - * @returns {string} + * Retrieves the repository description and wraps it to fit the card width. + * + * @param {string} label The repository description. + * @param {string} textColor The color of the text. + * @returns {string} Wrapped repo description SVG object. */ const getBadgeSVG = (label, textColor) => ` @@ -34,9 +36,11 @@ const getBadgeSVG = (label, textColor) => ` `; /** - * @param {string} langName - * @param {string} langColor - * @returns {string} + * Creates a node to display the primary programming language of the repository. + * + * @param {string} langName Language name. + * @param {string} langColor Language color. + * @returns {string} Language display SVG object. */ const createLanguageNode = (langName, langColor) => { return ` @@ -48,6 +52,15 @@ const createLanguageNode = (langName, langColor) => { }; const ICON_SIZE = 16; + +/** + * Creates an icon with label to display repository stats like forks, stars, etc. + * + * @param {string} icon The icon to display. + * @param {number|string} label The label to display. + * @param {string} testid The testid to assign to the label. + * @returns {string} Icon with label SVG object. + */ const iconWithLabel = (icon, label, testid) => { if (label <= 0) return ""; const iconSvg = ` @@ -67,9 +80,11 @@ const iconWithLabel = (icon, label, testid) => { }; /** - * @param {import('../fetchers/types').RepositoryData} repo - * @param {Partial} options - * @returns {string} + * Renders repository card details. + * + * @param {import('../fetchers/types').RepositoryData} repo Repository data. + * @param {Partial} options Card options. + * @returns {string} Repository card SVG object. */ const renderRepoCard = (repo, options = {}) => { const { diff --git a/src/cards/stats-card.js b/src/cards/stats-card.js index f880560e93a1b..c9ab66ecf889f 100644 --- a/src/cards/stats-card.js +++ b/src/cards/stats-card.js @@ -63,9 +63,11 @@ const createTextNode = ({ }; /** - * @param {Partial} stats - * @param {Partial} options - * @returns {string} + * Renders the stats card. + * + * @param {Partial} stats The stats data. + * @param {Partial} options The card options. + * @returns {string} The stats card SVG object. */ const renderStatsCard = (stats = {}, options = { hide: [] }) => { const { diff --git a/src/cards/top-languages-card.js b/src/cards/top-languages-card.js index b837b3587a513..602d1b811b5df 100644 --- a/src/cards/top-languages-card.js +++ b/src/cards/top-languages-card.js @@ -23,7 +23,10 @@ const CARD_PADDING = 25; */ /** - * @param {Lang[]} arr + * Retrieves the programming language whose name is the longest. + * + * @param {Lang[]} arr Array of programming languages. + * @returns {Object} Longest programming language object. */ const getLongestLang = (arr) => arr.reduce( @@ -33,12 +36,15 @@ const getLongestLang = (arr) => ); /** - * @param {{ - * width: number, - * color: string, - * name: string, - * progress: string - * }} props + * 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 {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. + * @returns {string} Programming language SVG node. */ const createProgressTextNode = ({ width, color, name, progress }) => { const paddingRight = 95; @@ -60,7 +66,12 @@ const createProgressTextNode = ({ width, color, name, progress }) => { }; /** - * @param {{ lang: Lang, totalSize: number }} props + * Creates a text only node to display usage of a programming language in percentage. + * + * @param {object[]} props Function properties. + * @param {Lang} props.lang Programming language object. + * @param {number} props.totalSize Total size of all languages. + * @returns {string} Compact layout programming language SVG node. */ const createCompactLangNode = ({ lang, totalSize }) => { const percentage = ((lang.size / totalSize) * 100).toFixed(2); @@ -77,7 +88,12 @@ const createCompactLangNode = ({ lang, totalSize }) => { }; /** - * @param {{ langs: Lang[], totalSize: number }} props + * Creates compact layout of text only language nodes. + * + * @param {object[]} props Function properties. + * @param {Lang[]} props.langs Array of programming languages. + * @param {number} props.totalSize Total size of all languages. + * @returns {string} Programming languages SVG node. */ const createLanguageTextNode = ({ langs, totalSize }) => { const longestLang = getLongestLang(langs); @@ -109,10 +125,12 @@ const createLanguageTextNode = ({ langs, totalSize }) => { }; /** - * @param {Lang[]} langs - * @param {number} width - * @param {number} totalLanguageSize - * @returns {string} + * Renders layout to display user's most frequently used programming languages. + * + * @param {Lang[]} langs Array of programming languages. + * @param {number} width Card width. + * @param {number} totalLanguageSize Total size of all languages. + * @returns {string} Normal layout card SVG object. */ const renderNormalLayout = (langs, width, totalLanguageSize) => { return flexLayout({ @@ -130,10 +148,12 @@ const renderNormalLayout = (langs, width, totalLanguageSize) => { }; /** - * @param {Lang[]} langs - * @param {number} width - * @param {number} totalLanguageSize - * @returns {string} + * Renders compact layout to display user's most frequently used programming languages. + * + * @param {Lang[]} langs Array of programming languages. + * @param {number} width Card width. + * @param {number} totalLanguageSize Total size of all languages. + * @returns {string} Compact layout card SVG object. */ const renderCompactLayout = (langs, width, totalLanguageSize) => { const paddingRight = 50; @@ -181,26 +201,31 @@ const renderCompactLayout = (langs, width, totalLanguageSize) => { }; /** - * @param {number} totalLangs - * @returns {number} + * Calculates height for the compact layout. + * + * @param {number} totalLangs Total number of languages. + * @returns {number} Card height. */ const calculateCompactLayoutHeight = (totalLangs) => { return 90 + Math.round(totalLangs / 2) * 25; }; /** - * @param {number} totalLangs - * @returns {number} + * Calculates height for the normal layout. + * + * @param {number} totalLangs Total number of languages. + * @returns {number} Card height. */ const calculateNormalLayoutHeight = (totalLangs) => { return 45 + (totalLangs + 1) * 40; }; /** + * Hides languages and trims the list to show only the top N languages. * - * @param {Record} topLangs - * @param {string[]} hide - * @param {string} langs_count + * @param {Record} topLangs Top languages. + * @param {string[]} hide Languages to hide. + * @param {string} langs_count Number of languages to show. */ const useLanguages = (topLangs, hide, langs_count) => { let langs = Object.values(topLangs); @@ -229,9 +254,11 @@ const useLanguages = (topLangs, hide, langs_count) => { }; /** - * @param {import('../fetchers/types').TopLangData} topLangs - * @param {Partial} options - * @returns {string} + * Renders card to display user's most frequently used programming languages. + * + * @param {import('../fetchers/types').TopLangData} topLangs User's most frequently used programming languages. + * @param {Partial} options Card options. + * @returns {string} Language card SVG object. */ const renderTopLanguages = (topLangs, options = {}) => { const { diff --git a/src/cards/wakatime-card.js b/src/cards/wakatime-card.js index 24571e7fffe82..8b042fd2f1a69 100644 --- a/src/cards/wakatime-card.js +++ b/src/cards/wakatime-card.js @@ -23,7 +23,9 @@ const require = createRequire(import.meta.url); const languageColors = require("../common/languageColors.json"); // now works /** - * @param {{color: string, text: string}} param0 + * Creates the no coding activity SVG node. + * + * @param {{color: string, text: string}} The function prop */ const noCodingActivityNode = ({ color, text }) => { return ` @@ -32,13 +34,13 @@ const noCodingActivityNode = ({ color, text }) => { }; /** + * Create compact WakaTime layout. * - * @param {{ - * lang: import("../fetchers/types").WakaTimeLang, - * totalSize: number, - * x: number, - * y: number - * }} props + * @param {Object[]} args The function arguments. + * @param {import("../fetchers/types").WakaTimeLang[]} languages The languages array. + * @param {number} totalSize The total size of the languages. + * @param {number} x The x position of the language node. + * @param {number} y The y position of the language node. */ const createCompactLangNode = ({ lang, totalSize, x, y }) => { const color = languageColors[lang.name] || "#858585"; @@ -54,12 +56,13 @@ const createCompactLangNode = ({ lang, totalSize, x, y }) => { }; /** - * @param {{ - * langs: import("../fetchers/types").WakaTimeLang[], - * totalSize: number, - * x: number, - * y: number - * }} props + * Create WakaTime language text node item. + * + * @param {Object[]} args The function arguments. + * @param {import("../fetchers/types").WakaTimeLang} lang The language object. + * @param {number} totalSize The total size of the languages. + * @param {number} x The x position of the language node. + * @param {number} y The y position of the language node. */ const createLanguageTextNode = ({ langs, totalSize, x, y }) => { return langs.map((lang, index) => { @@ -81,17 +84,16 @@ const createLanguageTextNode = ({ langs, totalSize, x, y }) => { }; /** + * Create WakaTime text item. * - * @param {{ - * id: string; - * label: string; - * value: string; - * index: number; - * percent: number; - * hideProgress: boolean; - * progressBarColor: string; - * progressBarBackgroundColor: string - * }} props + * @param {Object[]} args The function arguments. + * @param {string} id The id of the text node item. + * @param {string} label The label of the text node item. + * @param {string} value The value of the text node item. + * @param {number} index The index of the text node item. + * @param {percent} percent Percentage of the text node item. + * @param {boolean} hideProgress Whether to hide the progress bar. + * @param {string} progressBarBackgroundColor The color of the progress bar background. */ const createTextNode = ({ id, @@ -132,11 +134,13 @@ const createTextNode = ({ }; /** - * @param {import("../fetchers/types").WakaTimeLang[]} languages + * Recalculating percentages so that, compact layout's progress bar does not break when + * hiding languages. + * + * @param {import("../fetchers/types").WakaTimeLang[]} languages The languages array. + * @return {import("../fetchers/types").WakaTimeLang[]} The recalculated languages array. */ const recalculatePercentages = (languages) => { - // recalculating percentages so that, - // compact layout's progress bar does not break when hiding languages const totalSum = languages.reduce( (totalSum, language) => totalSum + language.percent, 0, @@ -148,9 +152,11 @@ const recalculatePercentages = (languages) => { }; /** - * @param {Partial} stats - * @param {Partial} options - * @returns {string} + * Renders WakaTime card. + * + * @param {Partial} stats WakaTime stats. + * @param {Partial} options Card options. + * @returns {string} WakaTime card SVG. */ const renderWakatimeCard = (stats = {}, options = { hide: [] }) => { let { languages } = stats; diff --git a/src/common/Card.js b/src/common/Card.js index 5fd4b9f372c7c..2f1d9c29f274d 100644 --- a/src/common/Card.js +++ b/src/common/Card.js @@ -3,14 +3,16 @@ import { encodeHTML, flexLayout } from "./utils.js"; class Card { /** - * @param {object} args - * @param {number?=} args.width - * @param {number?=} args.height - * @param {number?=} args.border_radius - * @param {string?=} args.customTitle - * @param {string?=} args.defaultTitle - * @param {string?=} args.titlePrefixIcon - * @param {ReturnType?=} args.colors + * Creates a new card instance. + * + * @param {object} args Card arguments. + * @param {number?=} args.width Card width. + * @param {number?=} args.height Card height. + * @param {number?=} args.border_radius Card border radius. + * @param {string?=} args.customTitle Card custom title. + * @param {string?=} args.defaultTitle Card default title. + * @param {string?=} args.titlePrefixIcon Card title prefix icon. + * @returns {Card} Card instance. */ constructor({ width = 100, diff --git a/src/common/I18n.js b/src/common/I18n.js index 7f607cd962f0d..48242af264c95 100644 --- a/src/common/I18n.js +++ b/src/common/I18n.js @@ -1,3 +1,6 @@ +/** + * I18n translation class. + */ class I18n { constructor({ locale, translations }) { this.locale = locale; diff --git a/src/common/createProgressNode.js b/src/common/createProgressNode.js index 4cc3747686411..c36818b193b2f 100644 --- a/src/common/createProgressNode.js +++ b/src/common/createProgressNode.js @@ -1,5 +1,17 @@ import { clampValue } from "./utils.js"; +/** + * Create a node to indicate progress in percentage along a horizontal line. + * + * @param {Object} createProgressNodeParams Object that contains the createProgressNode parameters. + * @param {number} createProgressNodeParams.x X-axis position. + * @param {number} createProgressNodeParams.y Y-axis position. + * @param {number} createProgressNodeParams.width Width of progress bar. + * @param {string} createProgressNodeParams.color Progress color. + * @param {string} createProgressNodeParams.progress Progress value. + * @param {string} createProgressNodeParams.progressBarBackgroundColor Progress bar bg color. + * @returns {string} Progress node. + */ const createProgressNode = ({ x, y, diff --git a/src/common/utils.js b/src/common/utils.js index fc462d3214c9f..b41ed0cb4e2a1 100644 --- a/src/common/utils.js +++ b/src/common/utils.js @@ -5,9 +5,11 @@ import wrap from "word-wrap"; import { themes } from "../../themes/index.js"; /** - * @param {string} message - * @param {string} secondaryMessage - * @returns {string} + * Renders error message on the card. + * + * @param {string} message Main error message. + * @param {string} secondaryMessage The secondary error message. + * @returns {string} The SVG markup. */ const renderError = (message, secondaryMessage = "") => { return ` @@ -28,9 +30,12 @@ const renderError = (message, secondaryMessage = "") => { }; /** + * Encode string as HTML. + * * @see https://stackoverflow.com/a/48073476/10629172 - * @param {string} str - * @returns {string} + * + * @param {string} str String to encode. + * @returns {string} Encoded string. */ function encodeHTML(str) { return str @@ -41,7 +46,10 @@ function encodeHTML(str) { } /** - * @param {number} num + * Retrieves num with suffix k(thousands) precise to 1 decimal if greater than 999. + * + * @param {number} num The number to format. + * @returns {string|number} The formatted number. */ function kFormatter(num) { return Math.abs(num) > 999 @@ -50,8 +58,10 @@ function kFormatter(num) { } /** - * @param {string} hexColor - * @returns {boolean} + * Checks if a string is a valid hex color. + * + * @param {string} hexColor String to check. + * @returns {boolean} True if the given string is a valid hex color. */ function isValidHexColor(hexColor) { return new RegExp( @@ -60,8 +70,10 @@ function isValidHexColor(hexColor) { } /** - * @param {string} value - * @returns {boolean | string} + * 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. */ function parseBoolean(value) { if (value === "true") { @@ -102,16 +114,18 @@ function clampValue(number, min, max) { * Check if the given string is a valid gradient. * * @param {string[]} colors Array of colors. - * returns {boolean} True if the given string is a valid gradient. + * @returns {boolean} True if the given string is a valid gradient. */ function isValidGradient(colors) { return isValidHexColor(colors[1]) && isValidHexColor(colors[2]); } /** - * @param {string} color - * @param {string} fallbackColor - * @returns {string | string[]} + * Retrieves a gradient if color has more than one valid hex codes else a single color. + * + * @param {string} color The color to parse. + * @param {string} fallbackColor The fallback color. + * @returns {string | string[]} The gradient or color. */ function fallbackColor(color, fallbackColor) { let colors = color.split(","); @@ -128,8 +142,11 @@ function fallbackColor(color, fallbackColor) { } /** - * @param {import('axios').AxiosRequestConfig['data']} data - * @param {import('axios').AxiosRequestConfig['headers']} headers + * Send GraphQL request to GitHub API. + * + * @param {import('axios').AxiosRequestConfig['data']} data Request data. + * @param {import('axios').AxiosRequestConfig['headers']} headers Request headers. + * @returns {Promise} Request response. */ function request(data, headers) { // @ts-ignore @@ -142,17 +159,15 @@ function request(data, headers) { } /** - * @param {object} props - * @param {string[]} props.items - * @param {number} props.gap - * @param {number[]?=} props.sizes - * @param {"column" | "row"?=} props.direction + * Auto layout utility, allows us to layout things vertically or horizontally with + * proper gaping. * - * @returns {string[]} - * - * @description - * Auto layout utility, allows us to layout things - * vertically or horizontally with proper gaping + * @param {object} props Function properties. + * @param {string[]} props.items Array of items to layout. + * @param {number} props.gap Gap between items. + * @param {number[]?=} props.sizes Array of sizes for each item. + * @param {"column" | "row"?=} props.direction Direction to layout items. + * @returns {string[]} Array of items with proper layout. */ function flexLayout({ items, gap, direction, sizes = [] }) { let lastSize = 0; @@ -169,18 +184,17 @@ function flexLayout({ items, gap, direction, sizes = [] }) { } /** - * @typedef {object} CardColors - * @prop {string?=} title_color - * @prop {string?=} text_color - * @prop {string?=} icon_color - * @prop {string?=} bg_color - * @prop {string?=} border_color - * @prop {keyof typeof import('../../themes')?=} fallbackTheme - * @prop {keyof typeof import('../../themes')?=} theme - */ -/** - * returns theme based colors with proper overrides and defaults - * @param {CardColors} options + * Returns theme based colors with proper overrides and defaults. + * + * @param {Object[]} args Function arguments. + * @param {string} args.title_color Card title color. + * @param {string} args.text_color Card text color. + * @param {string} args.icon_color Card icon color. + * @param {string} args.bg_color Card background color. + * @param {string} args.border_color Card border color. + * @param {string} args.theme Card theme. + * @param {string} args.fallbackTheme Fallback theme. + * */ function getCardColors({ title_color, @@ -224,10 +238,12 @@ function getCardColors({ } /** - * @param {string} text - * @param {number} width - * @param {number} maxLines - * @returns {string[]} + * Split text over multiple lines based on the card width. + * + * @param {string} text Text to split. + * @param {number} width Card width. + * @param {number} maxLines Maximum number of lines. + * @returns {string[]} Array of lines. */ function wrapTextMultiline(text, width = 59, maxLines = 3) { const fullWidthComma = ","; @@ -274,10 +290,13 @@ const SECONDARY_ERROR_MESSAGES = { USER_NOT_FOUND: "Make sure the provided username is not an organization", }; +/** + * Custom error class to handle custom GRS errors. + */ class CustomError extends Error { /** - * @param {string} message - * @param {string} type + * @param {string} message Error message. + * @param {string} type Error type. */ constructor(message, type) { super(message); @@ -289,6 +308,9 @@ class CustomError extends Error { static USER_NOT_FOUND = "USER_NOT_FOUND"; } +/** + * Missing query parameter class. + */ class MissingParamError extends Error { /** * @param {string[]} missedParams @@ -305,10 +327,12 @@ class MissingParamError extends Error { } /** + * Retrieve text length. + * * @see https://stackoverflow.com/a/48172630/10629172 - * @param {string} str - * @param {number} fontSize - * @returns + * @param {string} str String to measure. + * @param {number} fontSize Font size. + * @returns {number} Text length. */ function measureText(str, fontSize = 10) { // prettier-ignore @@ -348,10 +372,12 @@ function measureText(str, fontSize = 10) { const lowercaseTrim = (name) => name.toLowerCase().trim(); /** - * @template T - * @param {Array} arr - * @param {number} perChunk - * @returns {Array} + * Split array of languages in two columns. + * + * @template T Langauge object. + * @param {Array} arr Array of languages. + * @param {number} perChunk Number of languages per column. + * @returns {Array} Array of languages split in two columns. */ function chunkArray(arr, perChunk) { return arr.reduce((resultArray, item, index) => { @@ -368,9 +394,10 @@ function chunkArray(arr, perChunk) { } /** + * Parse emoji from string. * - * @param {string} str - * @returns {string} + * @param {string} str String to parse emoji from. + * @returns {string} String with emoji parsed. */ function parseEmojis(str) { if (!str) throw new Error("[parseEmoji]: str argument not provided"); diff --git a/src/fetchers/repo-fetcher.js b/src/fetchers/repo-fetcher.js index 37bce0e7ae352..9ff907c82bae6 100644 --- a/src/fetchers/repo-fetcher.js +++ b/src/fetchers/repo-fetcher.js @@ -3,8 +3,11 @@ import { retryer } from "../common/retryer.js"; import { MissingParamError, request } from "../common/utils.js"; /** - * @param {import('Axios').AxiosRequestHeaders} variables - * @param {string} token + * Repo data fetcher. + * + * @param {import('Axios').AxiosRequestHeaders} variables Fetcher variables. + * @param {string} token Github token. + * @returns {Promise} The response. */ const fetcher = (variables, token) => { return request( @@ -51,9 +54,11 @@ const fetcher = (variables, token) => { const urlExample = "/api/pin?username=USERNAME&repo=REPO_NAME"; /** - * @param {string} username - * @param {string} reponame - * @returns {Promise} + * Fetch repository data. + * + * @param {string} username Github username. + * @param {string} reponame Github repository name. + * @returns {Promise} Repository data. */ async function fetchRepo(username, reponame) { if (!username && !reponame) { diff --git a/src/fetchers/stats-fetcher.js b/src/fetchers/stats-fetcher.js index 941c7e145a14f..6a5a6e947824d 100644 --- a/src/fetchers/stats-fetcher.js +++ b/src/fetchers/stats-fetcher.js @@ -14,8 +14,11 @@ import { dotenv.config(); /** - * @param {import('axios').AxiosRequestHeaders} variables - * @param {string} token + * Stats fetcher object. + * + * @param {import('axios').AxiosRequestHeaders} variables Fetcher variables. + * @param {string} token Github token. + * @returns {Promise} Stats fetcher response. */ const fetcher = (variables, token) => { return request( @@ -59,8 +62,11 @@ const fetcher = (variables, token) => { }; /** - * @param {import('axios').AxiosRequestHeaders} variables - * @param {string} token + * Fetch first 100 repositories for a given username. + * + * @param {import('axios').AxiosRequestHeaders} variables Fetcher variables. + * @param {string} token Github token. + * @returns {Promise} Repositories fetcher response. */ const repositoriesFetcher = (variables, token) => { return request( @@ -91,8 +97,15 @@ const repositoriesFetcher = (variables, token) => { ); }; -// https://github.com/anuraghazra/github-readme-stats/issues/92#issuecomment-661026467 -// https://github.com/anuraghazra/github-readme-stats/pull/211/ +/** + * Fetch all the commits for all the repositories of a given username. + * + * @param {*} username Github username. + * @returns {Promise} Total commits. + * + * @description Done like this because the Github API does not provide a way to fetch all the commits. See + * #92#issuecomment-661026467 and #211 for more information. + */ const totalCommitsFetcher = async (username) => { if (!githubUsernameRegex.test(username)) { logger.log("Invalid username"); @@ -127,9 +140,11 @@ const totalCommitsFetcher = async (username) => { }; /** - * Fetch all the stars for all the repositories of a given username - * @param {string} username - * @param {array} repoToHide + * 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 = []; @@ -165,10 +180,12 @@ const totalStarsFetcher = async (username, repoToHide) => { }; /** - * @param {string} username - * @param {boolean} count_private - * @param {boolean} include_all_commits - * @returns {Promise} + * Fetch stats for a given username. + * + * @param {string} username Github username. + * @param {boolean} count_private Include private contributions. + * @param {boolean} include_all_commits Include all commits. + * @returns {Promise} Stats data. */ async function fetchStats( username, diff --git a/src/fetchers/top-languages-fetcher.js b/src/fetchers/top-languages-fetcher.js index 181375d9e66bc..7684213124eb3 100644 --- a/src/fetchers/top-languages-fetcher.js +++ b/src/fetchers/top-languages-fetcher.js @@ -6,8 +6,11 @@ import { logger, MissingParamError, request } from "../common/utils.js"; dotenv.config(); /** - * @param {import('Axios').AxiosRequestHeaders} variables - * @param {string} token + * Top languages fetcher object. + * + * @param {import('Axios').AxiosRequestHeaders} variables Fetcher variables. + * @param {string} token Github token. + * @returns {Promise} Languages fetcher response. */ const fetcher = (variables, token) => { return request( @@ -42,9 +45,11 @@ const fetcher = (variables, token) => { }; /** - * @param {string} username - * @param {string[]} exclude_repo - * @returns {Promise} + * Fetch top languages for a given username. + * + * @param {string} username Github username. + * @param {string[]} exclude_repo List of repositories to exclude. + * @returns {Promise} Top languages data. */ async function fetchTopLanguages(username, exclude_repo = []) { if (!username) throw new MissingParamError(["username"]); diff --git a/src/fetchers/wakatime-fetcher.js b/src/fetchers/wakatime-fetcher.js index 97adcdc87fc83..fa1f3d890920f 100644 --- a/src/fetchers/wakatime-fetcher.js +++ b/src/fetchers/wakatime-fetcher.js @@ -2,8 +2,10 @@ import axios from "axios"; import { MissingParamError } from "../common/utils.js"; /** - * @param {{username: string, api_domain: string, range: string}} props - * @returns {Promise} + * WakaTime data fetcher. + * + * @param {{username: string, api_domain: string, range: string}} props Fetcher props. + * @returns {Promise} WakaTime data response. */ const fetchWakatimeStats = async ({ username, api_domain, range }) => { if (!username) throw new MissingParamError(["username"]); diff --git a/src/getStyles.js b/src/getStyles.js index 3c77787e7e655..79692e8579035 100644 --- a/src/getStyles.js +++ b/src/getStyles.js @@ -1,6 +1,9 @@ // @ts-check /** - * @param {number} value + * Calculates progress along the boundary of the circle i.e it's circumference. + * + * @param {number} value The rank value to calculate progress for. + * @returns {number} Progress value. */ const calculateCircleProgress = (value) => { const radius = 40; @@ -13,9 +16,11 @@ const calculateCircleProgress = (value) => { }; /** + * Retrieves the animation to display progress along the circumference of circle + * from the beginning to the given value in a clockwise direction. * - * @param {{progress: number}} param0 - * @returns + * @param {{progress: number}} progress The progress value to animate to. + * @returns {string} Progress animation css. */ const getProgressAnimation = ({ progress }) => { return ` @@ -30,6 +35,11 @@ const getProgressAnimation = ({ progress }) => { `; }; +/** + * Retrieves css animations for a card. + * + * @returns {string} Animation css. + */ const getAnimations = () => { return ` /* Animations */ @@ -53,13 +63,15 @@ const getAnimations = () => { }; /** - * @param {{ - * titleColor?: string | string[] - * textColor?: string | string[] - * iconColor?: string | string[] - * show_icons?: boolean; - * progress?: number; - * }} args + * Retrieves CSS styles for a card. + * + * @param {Object[]} colors The colors to use for the card. + * @param {string} colors.titleColor The title color. + * @param {string} colors.textColor The text color. + * @param {string} colors.iconColor The icon color. + * @param {boolean} colors.show_icons Whether to show icons. + * @param {number} colors.progress The progress value to animate to. + * @returns {string} Card CSS styles. */ const getStyles = ({ titleColor, diff --git a/src/translations.js b/src/translations.js index 3f931bc8ee585..b71d37f9d7a03 100644 --- a/src/translations.js +++ b/src/translations.js @@ -1,5 +1,12 @@ import { encodeHTML } from "./common/utils.js"; +/** + * Retrieves stat card labels in the available locales. + * + * @param {string} name The name of the locale. + * @param {string} apostrophe Whether to use apostrophe or not. + * @returns {Object} The locales object. + */ const statCardLocales = ({ name, apostrophe }) => { const encodedName = encodeHTML(name); return { @@ -354,6 +361,12 @@ const wakatimeCardLocales = { const availableLocales = Object.keys(repoCardLocales["repocard.archived"]); +/** + * Checks whether the locale is available or not. + * + * @param {string} locale The locale to check. + * @returns {boolean} Boolean specifying whether the locale is available or not. + */ function isLocaleAvailable(locale) { return availableLocales.includes(locale.toLowerCase()); } From 36a8c392d0dddd9771971f0e045f58a69f5107a4 Mon Sep 17 00:00:00 2001 From: rickstaa Date: Fri, 7 Oct 2022 17:40:26 +0200 Subject: [PATCH 041/157] fix: improve graphql error handling --- src/common/retryer.js | 2 ++ src/common/utils.js | 14 ++++++++++--- src/fetchers/stats-fetcher.js | 18 +++++++++++++++-- src/fetchers/top-languages-fetcher.js | 29 ++++++++++++++++++++++++++- 4 files changed, 57 insertions(+), 6 deletions(-) diff --git a/src/common/retryer.js b/src/common/retryer.js index 859e94b08207e..77f69d3cbbbce 100644 --- a/src/common/retryer.js +++ b/src/common/retryer.js @@ -45,6 +45,8 @@ const retryer = async (fetcher, variables, retries = 0) => { retries++; // directly return from the function return retryer(fetcher, variables, retries); + } else { + return err.response; } } }; diff --git a/src/common/utils.js b/src/common/utils.js index b41ed0cb4e2a1..33b5f03d99615 100644 --- a/src/common/utils.js +++ b/src/common/utils.js @@ -4,6 +4,9 @@ import toEmoji from "emoji-name-map"; import wrap from "word-wrap"; import { themes } from "../../themes/index.js"; +// Script parameters. +const ERROR_CARD_LENGTH = 576.5; + /** * Renders error message on the card. * @@ -13,13 +16,15 @@ import { themes } from "../../themes/index.js"; */ const renderError = (message, secondaryMessage = "") => { return ` - + - + Something went wrong! file an issue at https://tiny.one/readme-stats ${encodeHTML(message)} @@ -241,7 +246,7 @@ function getCardColors({ * Split text over multiple lines based on the card width. * * @param {string} text Text to split. - * @param {number} width Card width. + * @param {number} width Line width in number of characters. * @param {number} maxLines Maximum number of lines. * @returns {string[]} Array of lines. */ @@ -288,6 +293,7 @@ const SECONDARY_ERROR_MESSAGES = { MAX_RETRY: "Please add an env variable called PAT_1 with your github token in vercel", USER_NOT_FOUND: "Make sure the provided username is not an organization", + GRAPHQL_ERROR: "Please try again later", }; /** @@ -306,6 +312,7 @@ class CustomError extends Error { static MAX_RETRY = "MAX_RETRY"; static USER_NOT_FOUND = "USER_NOT_FOUND"; + static GRAPHQL_ERROR = "GRAPHQL_ERROR"; } /** @@ -427,4 +434,5 @@ export { lowercaseTrim, chunkArray, parseEmojis, + ERROR_CARD_LENGTH, }; diff --git a/src/fetchers/stats-fetcher.js b/src/fetchers/stats-fetcher.js index 6a5a6e947824d..d592b75857a8a 100644 --- a/src/fetchers/stats-fetcher.js +++ b/src/fetchers/stats-fetcher.js @@ -9,6 +9,7 @@ import { logger, MissingParamError, request, + wrapTextMultiline, } from "../common/utils.js"; dotenv.config(); @@ -207,11 +208,24 @@ async function fetchStats( let res = await retryer(fetcher, { login: username }); + // Catch GraphQL errors. if (res.data.errors) { logger.error(res.data.errors); + if (res.data.errors[0].type === "NOT_FOUND") { + throw new CustomError( + res.data.errors[0].message || "Could not fetch user.", + CustomError.USER_NOT_FOUND, + ); + } + if (res.data.errors[0].message) { + throw new CustomError( + wrapTextMultiline(res.data.errors[0].message, 90, 1)[0], + res.statusText, + ); + } throw new CustomError( - res.data.errors[0].message || "Could not fetch user", - CustomError.USER_NOT_FOUND, + "Something went while trying to retrieve the stats data using the GraphQL API.", + CustomError.GRAPHQL_ERROR, ); } diff --git a/src/fetchers/top-languages-fetcher.js b/src/fetchers/top-languages-fetcher.js index 7684213124eb3..ba3fc72ca7e03 100644 --- a/src/fetchers/top-languages-fetcher.js +++ b/src/fetchers/top-languages-fetcher.js @@ -1,7 +1,13 @@ // @ts-check import * as dotenv from "dotenv"; import { retryer } from "../common/retryer.js"; -import { logger, MissingParamError, request } from "../common/utils.js"; +import { + CustomError, + logger, + MissingParamError, + request, + wrapTextMultiline, +} from "../common/utils.js"; dotenv.config(); @@ -61,6 +67,27 @@ async function fetchTopLanguages(username, exclude_repo = []) { throw Error(res.data.errors[0].message || "Could not fetch user"); } + // Catch GraphQL errors. + if (res.data.errors) { + logger.error(res.data.errors); + if (res.data.errors[0].type === "NOT_FOUND") { + throw new CustomError( + res.data.errors[0].message || "Could not fetch user.", + CustomError.USER_NOT_FOUND, + ); + } + if (res.data.errors[0].message) { + throw new CustomError( + wrapTextMultiline(res.data.errors[0].message, 90, 1)[0], + res.statusText, + ); + } + throw new CustomError( + "Something went while trying to retrieve the language data using the GraphQL API.", + CustomError.GRAPHQL_ERROR, + ); + } + let repoNodes = res.data.data.user.repositories.nodes; let repoToHide = {}; From 06e3e052df417a3c0a55d56069533861123c2467 Mon Sep 17 00:00:00 2001 From: Brian Choromanski Date: Fri, 7 Oct 2022 13:20:57 -0400 Subject: [PATCH 042/157] ci: updated issue template (#2127) * Updated issue templates * style: improve template formatting * style: update formatting Co-authored-by: rickstaa --- .github/ISSUE_TEMPLATE/bug_report.md | 43 ---------------- .github/ISSUE_TEMPLATE/bug_report.yml | 58 ++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 41 --------------- .github/ISSUE_TEMPLATE/feature_request.yml | 26 ++++++++++ 4 files changed, 84 insertions(+), 84 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 5ed7d3c969ff8..0000000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: "" -labels: "" -assignees: "" ---- - - -**Describe the bug** -A clear and concise description of what the bug is. - -**Expected behaviour** -A clear and concise description of what you expected to happen. - -**Screenshots / Live demo link (paste the github-readme-stats link as markdown image)** -If applicable, add screenshots to help explain your problem. - -**Additional context** -Add any other context about the problem here. - - diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000000000..1a5a9532b3230 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,58 @@ +name: Bug report +description: Create a report to help us improve +labels: + - "bug" +body: + - type: markdown + attributes: + value: | + > **Warning** + > PLEASE FIRST READ THE FAQ [(#1770)](https://github.com/anuraghazra/github-readme-stats/discussions/1770) AND COMMON ERROR CODES [(#1772)](https://github.com/anuraghazra/github-readme-stats/issues/1772)!!! + - type: textarea + attributes: + label: Describe the bug + description: A clear and concise description of what the bug is. + - type: textarea + attributes: + label: Expected behaviour + description: + A clear and concise description of what you expected to happen. + - type: textarea + attributes: + label: Screenshots / Live demo link + description: If applicable, add screenshots to help explain your problem. + placeholder: Paste the github-readme-stats link as markdown image + - type: textarea + attributes: + label: Additional context + description: Add any other context about the problem here. + - type: markdown + attributes: + value: | + ### FAQ + + Below are some questions that are found in the FAQ. The full FAQ can be found in [#1770](https://github.com/anuraghazra/github-readme-stats/discussions/1770). + + #### Q: My card displays an error + + **Ans:** First, check the common error codes (i.e. https://github.com/anuraghazra/github-readme-stats/issues/1772) and existing issues before creating a new one. + + #### Q: How to hide jupyter Notebook? + + **Ans:** `&hide=jupyter%20notebook`. + + #### Q: I could not figure out how to deploy on my own vercel instance + + **Ans:** Please check: + - Docs: https://github.com/anuraghazra/github-readme-stats/#deploy-on-your-own-vercel-instance + - YT tutorial by codeSTACKr: https://www.youtube.com/watch?v=n6d4KHSKqGk&feature=youtu.be&t=107 + + #### Q: Language Card is incorrect + + **Ans:** Please read these issues/comments before opening any issues regarding language card stats: + - https://github.com/anuraghazra/github-readme-stats/issues/136#issuecomment-665164174 + - https://github.com/anuraghazra/github-readme-stats/issues/136#issuecomment-665172181 + + #### Q: How to count private stats? + + **Ans:** We can only count private commits & we cannot access any other private info of any users, so it's impossible. The only way is to deploy on your own instance & use your own PAT (Personal Access Token). diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 73e080a31240f..0000000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: "" -labels: "" -assignees: "" ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. - - diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000000000..20dc6a8b4c6b4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,26 @@ +name: Feature request +description: Suggest an idea for this project +labels: + - "enhancement" +body: + - type: textarea + attributes: + label: Is your feature request related to a problem? Please describe. + description: | + A clear and concise description of what the problem is. Ex. I'm always + frustrated when [...] + - type: textarea + attributes: + label: Describe the solution you'd like + description: A clear and concise description of what you want to happen. + - type: textarea + attributes: + label: Describe alternatives you've considered + description: | + A clear and concise description of any alternative solutions or features + you've considered. + - type: textarea + attributes: + label: Additional context + description: + Add any other context or screenshots about the feature request here. From 80e8233c532bdb0ce317d5da94fd55090c827915 Mon Sep 17 00:00:00 2001 From: rickstaa Date: Fri, 7 Oct 2022 19:25:36 +0200 Subject: [PATCH 043/157] style: improve templates formatting --- .github/ISSUE_TEMPLATE/bug_report.yml | 6 +++--- .github/ISSUE_TEMPLATE/feature_request.yml | 10 ++++------ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 1a5a9532b3230..8c6ec2aa0c081 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -6,8 +6,7 @@ body: - type: markdown attributes: value: | - > **Warning** - > PLEASE FIRST READ THE FAQ [(#1770)](https://github.com/anuraghazra/github-readme-stats/discussions/1770) AND COMMON ERROR CODES [(#1772)](https://github.com/anuraghazra/github-readme-stats/issues/1772)!!! + :warning: PLEASE FIRST READ THE FAQ [(#1770)](https://github.com/anuraghazra/github-readme-stats/discussions/1770) AND COMMON ERROR CODES [(#1772)](https://github.com/anuraghazra/github-readme-stats/issues/1772)!!! - type: textarea attributes: label: Describe the bug @@ -29,7 +28,8 @@ body: - type: markdown attributes: value: | - ### FAQ + --- + ### FAQ (Snippet) Below are some questions that are found in the FAQ. The full FAQ can be found in [#1770](https://github.com/anuraghazra/github-readme-stats/discussions/1770). diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 20dc6a8b4c6b4..7b377f9a651ec 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -6,9 +6,8 @@ body: - type: textarea attributes: label: Is your feature request related to a problem? Please describe. - description: | - A clear and concise description of what the problem is. Ex. I'm always - frustrated when [...] + description: + A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - type: textarea attributes: label: Describe the solution you'd like @@ -16,9 +15,8 @@ body: - type: textarea attributes: label: Describe alternatives you've considered - description: | - A clear and concise description of any alternative solutions or features - you've considered. + description: + A clear and concise description of any alternative solutions or features you've considered. - type: textarea attributes: label: Additional context From 39535db38c14cc6b50dd747504ac5577abc4ddac Mon Sep 17 00:00:00 2001 From: rickstaa Date: Fri, 7 Oct 2022 19:46:05 +0200 Subject: [PATCH 044/157] style: update formatting --- .github/ISSUE_TEMPLATE/feature_request.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 7b377f9a651ec..b015add90c020 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -7,7 +7,8 @@ body: attributes: label: Is your feature request related to a problem? Please describe. description: - A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + A clear and concise description of what the problem is. Ex. I'm always + frustrated when [...] - type: textarea attributes: label: Describe the solution you'd like @@ -16,7 +17,8 @@ body: attributes: label: Describe alternatives you've considered description: - A clear and concise description of any alternative solutions or features you've considered. + A clear and concise description of any alternative solutions or features + you've considered. - type: textarea attributes: label: Additional context From bd9865d5a2c9effda41bd5a66b7e01c02af7e2be Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Fri, 7 Oct 2022 20:01:01 +0200 Subject: [PATCH 045/157] test: burst cache in e2e tests (#2154) --- tests/e2e/e2e.test.js | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/tests/e2e/e2e.test.js b/tests/e2e/e2e.test.js index becf5c82d891f..a5ab79e61ba10 100644 --- a/tests/e2e/e2e.test.js +++ b/tests/e2e/e2e.test.js @@ -82,6 +82,7 @@ const REPOSITORY_DATA = { forkCount: 0, starCount: 1, }; +const CACHE_BURST_STRING = `v=${new Date().getTime()}`; describe("Fetch Cards", () => { let VERCEL_PREVIEW_URL; @@ -104,7 +105,7 @@ describe("Fetch Cards", () => { // Get the Vercel preview stats card response. const serverStatsSvg = await axios.get( - `${VERCEL_PREVIEW_URL}/api?username=${USER}`, + `${VERCEL_PREVIEW_URL}/api?username=${USER}&${CACHE_BURST_STRING}`, ); // Check if stats card from deployment matches the stats card from local. @@ -115,8 +116,13 @@ describe("Fetch Cards", () => { expect(VERCEL_PREVIEW_URL).toBeDefined(); // Check if the Vercel preview instance language card function is up and running. + console.log( + `${VERCEL_PREVIEW_URL}/api/top-langs/?username=${USER}&${CACHE_BURST_STRING}`, + ); await expect( - axios.get(`${VERCEL_PREVIEW_URL}/api/top-langs/?username=${USER}`), + axios.get( + `${VERCEL_PREVIEW_URL}/api/top-langs/?username=${USER}&${CACHE_BURST_STRING}`, + ), ).resolves.not.toThrow(); // Get local language card. @@ -124,7 +130,7 @@ describe("Fetch Cards", () => { // Get the Vercel preview language card response. const severLanguageSVG = await axios.get( - `${VERCEL_PREVIEW_URL}/api/top-langs/?username=${USER}`, + `${VERCEL_PREVIEW_URL}/api/top-langs/?username=${USER}&${CACHE_BURST_STRING}`, ); // Check if language card from deployment matches the local language card. @@ -144,7 +150,7 @@ describe("Fetch Cards", () => { // Get the Vercel preview WakaTime card response. const serverWakaTimeSvg = await axios.get( - `${VERCEL_PREVIEW_URL}/api/wakatime?username=${USER}`, + `${VERCEL_PREVIEW_URL}/api/wakatime?username=${USER}&${CACHE_BURST_STRING}`, ); // Check if WakaTime card from deployment matches the local WakaTime card. @@ -156,7 +162,9 @@ describe("Fetch Cards", () => { // Check if the Vercel preview instance Repo function is up and running. await expect( - axios.get(`${VERCEL_PREVIEW_URL}/api/pin/?username=${USER}&repo=${REPO}`), + axios.get( + `${VERCEL_PREVIEW_URL}/api/pin/?username=${USER}&repo=${REPO}&${CACHE_BURST_STRING}`, + ), ).resolves.not.toThrow(); // Get local repo card. @@ -164,7 +172,7 @@ describe("Fetch Cards", () => { // Get the Vercel preview repo card response. const serverRepoSvg = await axios.get( - `${VERCEL_PREVIEW_URL}/api/pin/?username=${USER}&repo=${REPO}`, + `${VERCEL_PREVIEW_URL}/api/pin/?username=${USER}&repo=${REPO}&${CACHE_BURST_STRING}`, ); // Check if Repo card from deployment matches the local Repo card. From 60012707c7eaa51fd0377ce8ae46da6ebad24342 Mon Sep 17 00:00:00 2001 From: rickstaa Date: Sat, 8 Oct 2022 15:04:49 +0200 Subject: [PATCH 046/157] test: increase stats card e2e timeout --- 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 a5ab79e61ba10..ad8086b0a2642 100644 --- a/tests/e2e/e2e.test.js +++ b/tests/e2e/e2e.test.js @@ -110,7 +110,7 @@ describe("Fetch Cards", () => { // Check if stats card from deployment matches the stats card from local. expect(serverStatsSvg.data).toEqual(localStatsCardSVG); - }); + }, 6000); test("retrieve language card", async () => { expect(VERCEL_PREVIEW_URL).toBeDefined(); From fcd05887866797ec01330aa22888066563862c57 Mon Sep 17 00:00:00 2001 From: rickstaa Date: Sun, 9 Oct 2022 15:18:11 +0200 Subject: [PATCH 047/157] test: cleanup tests --- tests/e2e/e2e.test.js | 5 ++++- tests/fetchRepo.test.js | 1 + tests/renderStatsCard.test.js | 20 +++++++++--------- tests/renderTopLanguages.test.js | 36 ++++++++++++++++---------------- 4 files changed, 33 insertions(+), 29 deletions(-) diff --git a/tests/e2e/e2e.test.js b/tests/e2e/e2e.test.js index ad8086b0a2642..aa023cbd0bc88 100644 --- a/tests/e2e/e2e.test.js +++ b/tests/e2e/e2e.test.js @@ -11,7 +11,6 @@ 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"; -// Script variables const REPO = "dummy-cra"; const USER = "grsdummy"; const STATS_DATA = { @@ -26,6 +25,7 @@ const STATS_DATA = { score: 51.01013099671447, }, }; + const LANGS_DATA = { TypeScript: { color: "#3178c6", @@ -48,6 +48,7 @@ const LANGS_DATA = { size: 671, }, }; + const WAKATIME_DATA = { human_readable_range: "last week", is_already_updating: false, @@ -64,6 +65,7 @@ const WAKATIME_DATA = { username: "grsdummy", writes_only: false, }; + const REPOSITORY_DATA = { name: "dummy-cra", nameWithOwner: "grsdummy/dummy-cra", @@ -82,6 +84,7 @@ const REPOSITORY_DATA = { forkCount: 0, starCount: 1, }; + const CACHE_BURST_STRING = `v=${new Date().getTime()}`; describe("Fetch Cards", () => { diff --git a/tests/fetchRepo.test.js b/tests/fetchRepo.test.js index 966f2d89a5487..f74a66ff0790c 100644 --- a/tests/fetchRepo.test.js +++ b/tests/fetchRepo.test.js @@ -23,6 +23,7 @@ const data_user = { organization: null, }, }; + const data_org = { data: { user: null, diff --git a/tests/renderStatsCard.test.js b/tests/renderStatsCard.test.js index d3155986d0402..69708137b334c 100644 --- a/tests/renderStatsCard.test.js +++ b/tests/renderStatsCard.test.js @@ -10,17 +10,17 @@ import "@testing-library/jest-dom"; import { themes } from "../themes/index.js"; -describe("Test renderStatsCard", () => { - const stats = { - name: "Anurag Hazra", - totalStars: 100, - totalCommits: 200, - totalIssues: 300, - totalPRs: 400, - contributedTo: 500, - rank: { level: "A+", score: 40 }, - }; +const stats = { + name: "Anurag Hazra", + totalStars: 100, + totalCommits: 200, + totalIssues: 300, + totalPRs: 400, + contributedTo: 500, + rank: { level: "A+", score: 40 }, +}; +describe("Test renderStatsCard", () => { it("should render correctly", () => { document.body.innerHTML = renderStatsCard(stats); diff --git a/tests/renderTopLanguages.test.js b/tests/renderTopLanguages.test.js index 8c6bcbef49438..8ae4bbd0c16e6 100644 --- a/tests/renderTopLanguages.test.js +++ b/tests/renderTopLanguages.test.js @@ -9,25 +9,25 @@ import "@testing-library/jest-dom"; import { themes } from "../themes/index.js"; -describe("Test renderTopLanguages", () => { - const langs = { - HTML: { - color: "#0f0", - name: "HTML", - size: 200, - }, - javascript: { - color: "#0ff", - name: "javascript", - size: 200, - }, - css: { - color: "#ff0", - name: "css", - size: 100, - }, - }; +const langs = { + HTML: { + color: "#0f0", + name: "HTML", + size: 200, + }, + javascript: { + color: "#0ff", + name: "javascript", + size: 200, + }, + css: { + color: "#ff0", + name: "css", + size: 100, + }, +}; +describe("Test renderTopLanguages", () => { it("should render correctly", () => { document.body.innerHTML = renderTopLanguages(langs); From f77e34e383ce164f39c679e988eb974f2289d435 Mon Sep 17 00:00:00 2001 From: rickstaa Date: Sun, 9 Oct 2022 17:31:24 +0200 Subject: [PATCH 048/157] ci: add question template --- .github/ISSUE_TEMPLATE/question.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/question.yml diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/ISSUE_TEMPLATE/question.yml new file mode 100644 index 0000000000000..5199511fb533b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.yml @@ -0,0 +1,9 @@ +name: Question +description: Ask a question +body: + - type: markdown + attributes: + value: | + We use the Issues tab for bug reports and feature requests. If you have a question, please start a discussion in the Discussions tab. + + [![Start New Discussion](https://dabuttonfactory.com/button.png?t=Start+New+Discussion&f=Roboto-Bold&ts=26&tc=fff&hp=45&vp=20&c=11&bgt=unicolored&bgc=238636)](https://github.com/anuraghazra/github-readme-stats/discussions/new) From 0a394a625b3244852c4975350d0861d3fc3dab4a Mon Sep 17 00:00:00 2001 From: rickstaa Date: Sun, 9 Oct 2022 17:46:11 +0200 Subject: [PATCH 049/157] ci: add issues template config and remove question template --- .github/ISSUE_TEMPLATE/config.yml | 5 +++++ .github/ISSUE_TEMPLATE/question.yml | 9 --------- 2 files changed, 5 insertions(+), 9 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/config.yml delete mode 100644 .github/ISSUE_TEMPLATE/question.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000000..f5830f64ead80 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: Question + url: https://github.com/anuraghazra/github-readme-stats/discussions + about: Please ask and answer questions here. diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/ISSUE_TEMPLATE/question.yml deleted file mode 100644 index 5199511fb533b..0000000000000 --- a/.github/ISSUE_TEMPLATE/question.yml +++ /dev/null @@ -1,9 +0,0 @@ -name: Question -description: Ask a question -body: - - type: markdown - attributes: - value: | - We use the Issues tab for bug reports and feature requests. If you have a question, please start a discussion in the Discussions tab. - - [![Start New Discussion](https://dabuttonfactory.com/button.png?t=Start+New+Discussion&f=Roboto-Bold&ts=26&tc=fff&hp=45&vp=20&c=11&bgt=unicolored&bgc=238636)](https://github.com/anuraghazra/github-readme-stats/discussions/new) From 4df8094e5266f28f7367552980f4e00b0c9421a9 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Sun, 9 Oct 2022 20:23:31 +0200 Subject: [PATCH 050/157] fix: prevent errors from being cached (#2160) --- api/index.js | 1 + api/pin.js | 1 + api/top-langs.js | 1 + api/wakatime.js | 1 + 4 files changed, 4 insertions(+) diff --git a/api/index.js b/api/index.js index 10dd48478ec6b..3b5e949d71d36 100644 --- a/api/index.js +++ b/api/index.js @@ -89,6 +89,7 @@ export default async (req, res) => { }), ); } catch (err) { + res.setHeader("Cache-Control", `no-store`); // Don't cache error responses. return res.send(renderError(err.message, err.secondaryMessage)); } }; diff --git a/api/pin.js b/api/pin.js index e83750a5f7ce4..84ca4e64c3d9c 100644 --- a/api/pin.js +++ b/api/pin.js @@ -75,6 +75,7 @@ export default async (req, res) => { }), ); } catch (err) { + res.setHeader("Cache-Control", `no-store`); // Don't cache error responses. return res.send(renderError(err.message, err.secondaryMessage)); } }; diff --git a/api/top-langs.js b/api/top-langs.js index aa29b23472dd2..a6a9d286d253e 100644 --- a/api/top-langs.js +++ b/api/top-langs.js @@ -76,6 +76,7 @@ export default async (req, res) => { }), ); } catch (err) { + res.setHeader("Cache-Control", `no-store`); // Don't cache error responses. return res.send(renderError(err.message, err.secondaryMessage)); } }; diff --git a/api/wakatime.js b/api/wakatime.js index bbfb2f2ec5dde..60d22b5c9c8dd 100644 --- a/api/wakatime.js +++ b/api/wakatime.js @@ -78,6 +78,7 @@ export default async (req, res) => { }), ); } catch (err) { + res.setHeader("Cache-Control", `no-store`); // Don't cache error responses. return res.send(renderError(err.message, err.secondaryMessage)); } }; From f0f92c2635952be5820dae162bbdcf810b068c61 Mon Sep 17 00:00:00 2001 From: rickstaa Date: Mon, 10 Oct 2022 12:48:26 +0200 Subject: [PATCH 051/157] test: add cache on error test --- tests/api.test.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/api.test.js b/tests/api.test.js index a6bb0920449e4..c05f25a63d005 100644 --- a/tests/api.test.js +++ b/tests/api.test.js @@ -174,6 +174,16 @@ describe("Test /api/", () => { ]); }); + it("should not store cache when error", async () => { + const { req, res } = faker({}, error); + await api(req, res); + + expect(res.setHeader.mock.calls).toEqual([ + ["Content-Type", "image/svg+xml"], + ["Cache-Control", `no-store`], + ]); + }); + it("should set proper cache with clamped values", async () => { { let { req, res } = faker({ cache_seconds: 200000 }, data); From c4bfacb9e0cf4df41bf01b75be72cfcd7ea207f7 Mon Sep 17 00:00:00 2001 From: rickstaa Date: Mon, 10 Oct 2022 13:48:35 +0200 Subject: [PATCH 052/157] docs: add fork update guide --- readme.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/readme.md b/readme.md index 9c35b708fb43f..aeaadf52c8a1e 100644 --- a/readme.md +++ b/readme.md @@ -92,6 +92,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) # GitHub Stats Card @@ -440,6 +441,10 @@ Since the GitHub API only allows 5k requests per hour, my `https://github-readme
+#### 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. + ## :sparkling_heart: Support the project I open-source almost everything I can and try to reply to everyone needing help using these projects. Obviously, From 166972d7e4f12ab17ee7aa2b2000d784444bd9fd Mon Sep 17 00:00:00 2001 From: rickstaa Date: Mon, 10 Oct 2022 13:49:48 +0200 Subject: [PATCH 053/157] docs: improve syntax --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index aeaadf52c8a1e..9c773ff84707c 100644 --- a/readme.md +++ b/readme.md @@ -441,7 +441,7 @@ Since the GitHub API only allows 5k requests per hour, my `https://github-readme -#### Keep your fork up to date +### 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 7eb85d3b31bc4cd45c31ca3b3748f15669348b61 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Tue, 11 Oct 2022 18:00:05 +0200 Subject: [PATCH 054/157] refactor: add extra links to issues template --- .github/ISSUE_TEMPLATE/config.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index f5830f64ead80..a1c536fd4f6e1 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -3,3 +3,9 @@ contact_links: - name: Question url: https://github.com/anuraghazra/github-readme-stats/discussions about: Please ask and answer questions here. + - name: Error + url: https://github.com/anuraghazra/github-readme-stats/issues/1772 + about: Before opening a bug report, please check the 'Common Error Codes' issue. + - name: FAQ + url: https://github.com/anuraghazra/github-readme-stats/discussions/1770 + about: Please first check the FAQ before asking a question. From 32b8daa71df159ace5acc95d6e3d87cdc06d5cc4 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Tue, 11 Oct 2022 18:02:29 +0200 Subject: [PATCH 055/157] refactor: improve issues template (#2180) --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 8c6ec2aa0c081..854c103feef8f 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,5 +1,5 @@ name: Bug report -description: Create a report to help us improve +description: Create a report to help us improve. labels: - "bug" body: From 8dd70924dabe52bdb6620ae7546f33f24d1581da Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Tue, 11 Oct 2022 18:07:36 +0200 Subject: [PATCH 056/157] refactor: improve issues template formatting --- .github/ISSUE_TEMPLATE/config.yml | 3 ++- .github/ISSUE_TEMPLATE/feature_request.yml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index a1c536fd4f6e1..5c7fb3045572c 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -5,7 +5,8 @@ contact_links: about: Please ask and answer questions here. - name: Error url: https://github.com/anuraghazra/github-readme-stats/issues/1772 - about: Before opening a bug report, please check the 'Common Error Codes' issue. + about: + Before opening a bug report, please check the 'Common Error Codes' issue. - name: FAQ url: https://github.com/anuraghazra/github-readme-stats/discussions/1770 about: Please first check the FAQ before asking a question. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index b015add90c020..239fcc9147916 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,5 +1,5 @@ name: Feature request -description: Suggest an idea for this project +description: Suggest an idea for this project. labels: - "enhancement" body: From 6fdf73f39c0e1f5f276ecc93025bc3567610f7d6 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Tue, 11 Oct 2022 18:10:44 +0200 Subject: [PATCH 057/157] test: increase e2e test timeout --- 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 aa023cbd0bc88..0a38d98002b49 100644 --- a/tests/e2e/e2e.test.js +++ b/tests/e2e/e2e.test.js @@ -113,7 +113,7 @@ describe("Fetch Cards", () => { // Check if stats card from deployment matches the stats card from local. expect(serverStatsSvg.data).toEqual(localStatsCardSVG); - }, 6000); + }, 7000); test("retrieve language card", async () => { expect(VERCEL_PREVIEW_URL).toBeDefined(); From dea583d4261f1ef865f78e7ed980ab4537353d44 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Thu, 13 Oct 2022 10:27:19 +0200 Subject: [PATCH 058/157] build: create npm package (#2151) * build: create npm package This commit makes sure that the common modules of the GRS package can be imported as an npm package. * feat: export card render functions * style: update formatting --- package.json | 18 ++++++++++++++++-- src/cards/index.js | 4 ++++ src/common/index.js | 30 ++++++++++++++++++++++++++++++ src/common/utils.js | 13 +++++++------ src/index.js | 3 +++ 5 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 src/cards/index.js create mode 100644 src/common/index.js create mode 100644 src/index.js diff --git a/package.json b/package.json index 5fc4492764901..95b1a11dad93f 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,23 @@ { "name": "github-readme-stats", "version": "1.0.0", - "description": "Dynamically generate stats for your github readmes", - "main": "index.js", + "description": "Dynamically generate stats for your GitHub readme", + "keywords": [ + "github-readme-stats", + "readme-stats", + "cards", + "card-generator" + ], + "main": "src/index.js", "type": "module", + "homepage": "https://github.com/anuraghazra/github-readme-stats", + "bugs": { + "url": "https://github.com/anuraghazra/github-readme-stats/issues" + }, + "repository": { + "type": "git", + "url": "https://github.com/anuraghazra/github-readme-stats.git" + }, "scripts": { "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --coverage", "test:watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch", diff --git a/src/cards/index.js b/src/cards/index.js new file mode 100644 index 0000000000000..f2c5fb0e3a143 --- /dev/null +++ b/src/cards/index.js @@ -0,0 +1,4 @@ +export { renderRepoCard } from "./repo-card.js"; +export { renderStatsCard } from "./stats-card.js"; +export { renderTopLanguages } from "./top-languages-card.js"; +export { renderWakatimeCard } from "./wakatime-card.js"; diff --git a/src/common/index.js b/src/common/index.js new file mode 100644 index 0000000000000..44a8db51724f2 --- /dev/null +++ b/src/common/index.js @@ -0,0 +1,30 @@ +export { blacklist } from "./blacklist.js"; +export { Card } from "./Card.js"; +export { createProgressNode } from "./createProgressNode.js"; +export { i18n } from "./i18n.js"; +export { icons } from "./icons.js"; +export { retryer } from "./retryer.js"; +export { + ERROR_CARD_LENGTH, + renderError, + encodeHTML, + kFormatter, + isValidHexColor, + parseBoolean, + parseArray, + clampValue, + isValidGradient, + fallbackColor, + request, + flexLayout, + getCardColors, + wrapTextMultiline, + logger, + CONSTANTS, + CustomError, + MissingParamError, + measureText, + lowercaseTrim, + chunkArray, + parseEmojis, +} from "./utils.js"; diff --git a/src/common/utils.js b/src/common/utils.js index 33b5f03d99615..43c7587fc2932 100644 --- a/src/common/utils.js +++ b/src/common/utils.js @@ -414,25 +414,26 @@ function parseEmojis(str) { } export { + ERROR_CARD_LENGTH, renderError, - kFormatter, encodeHTML, + kFormatter, isValidHexColor, - request, - parseArray, parseBoolean, + parseArray, + clampValue, + isValidGradient, fallbackColor, + request, flexLayout, getCardColors, - clampValue, wrapTextMultiline, - measureText, logger, CONSTANTS, CustomError, MissingParamError, + measureText, lowercaseTrim, chunkArray, parseEmojis, - ERROR_CARD_LENGTH, }; diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000000000..27577f80f58db --- /dev/null +++ b/src/index.js @@ -0,0 +1,3 @@ +export * from "./common/index.js"; +export * from "./cards/index.js"; +export { getStyles, getAnimations } from "./getStyles.js"; From f7a2b2162b62ccc77aae78d1405b58953ddc72ec Mon Sep 17 00:00:00 2001 From: rickstaa Date: Thu, 13 Oct 2022 10:50:32 +0200 Subject: [PATCH 059/157] fix: fix I18n import error --- src/common/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/index.js b/src/common/index.js index 44a8db51724f2..2e7e9cb20fe0b 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -1,7 +1,7 @@ export { blacklist } from "./blacklist.js"; export { Card } from "./Card.js"; export { createProgressNode } from "./createProgressNode.js"; -export { i18n } from "./i18n.js"; +export { I18n } from "./I18n.js"; export { icons } from "./icons.js"; export { retryer } from "./retryer.js"; export { From 65424fa90f349b3fcf8b7031759640398755c4bb Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Thu, 13 Oct 2022 11:26:13 +0200 Subject: [PATCH 060/157] fix: improve json import (#2190) --- src/cards/wakatime-card.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/cards/wakatime-card.js b/src/cards/wakatime-card.js index 8b042fd2f1a69..da16df6f8ab44 100644 --- a/src/cards/wakatime-card.js +++ b/src/cards/wakatime-card.js @@ -18,9 +18,17 @@ import { wakatimeCardLocales } from "../translations.js"; * since vercel is using v16.14.0 which does not yet support json imports without the * --experimental-json-modules flag. */ -import { createRequire } from "module"; -const require = createRequire(import.meta.url); -const languageColors = require("../common/languageColors.json"); // now works +import { readFileSync } from "fs"; +import path from "path"; +import { fileURLToPath } from "url"; +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const languageColors = JSON.parse( + readFileSync( + path.resolve(__dirname, "../common/languageColors.json"), + "utf8", + ), +); /** * Creates the no coding activity SVG node. From 54cc2919781cc96c5e728670c70444b6591120be Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Thu, 13 Oct 2022 11:55:01 +0200 Subject: [PATCH 061/157] Revert "fix: improve json import (#2190)" (#2191) This reverts commit 65424fa90f349b3fcf8b7031759640398755c4bb. --- src/cards/wakatime-card.js | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/cards/wakatime-card.js b/src/cards/wakatime-card.js index da16df6f8ab44..8b042fd2f1a69 100644 --- a/src/cards/wakatime-card.js +++ b/src/cards/wakatime-card.js @@ -18,17 +18,9 @@ import { wakatimeCardLocales } from "../translations.js"; * since vercel is using v16.14.0 which does not yet support json imports without the * --experimental-json-modules flag. */ -import { readFileSync } from "fs"; -import path from "path"; -import { fileURLToPath } from "url"; -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); -const languageColors = JSON.parse( - readFileSync( - path.resolve(__dirname, "../common/languageColors.json"), - "utf8", - ), -); +import { createRequire } from "module"; +const require = createRequire(import.meta.url); +const languageColors = require("../common/languageColors.json"); // now works /** * Creates the no coding activity SVG node. From bb56e3bb7baef64b6a537add312dbfa2cfe7829a Mon Sep 17 00:00:00 2001 From: Kurt <32745146+kurt-liao@users.noreply.github.com> Date: Sat, 15 Oct 2022 14:19:33 +0800 Subject: [PATCH 062/157] fix: text overlapped on zh-tw locale (#2192) --- src/cards/stats-card.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cards/stats-card.js b/src/cards/stats-card.js index c9ab66ecf889f..782ff069674bb 100644 --- a/src/cards/stats-card.js +++ b/src/cards/stats-card.js @@ -170,6 +170,7 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => { "pl", "de", "nl", + "zh-tw", ]; const isLongLocale = longLocales.includes(locale) === true; From 1d10912646dd12f17d2d8f86044d5341e208e690 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Sun, 16 Oct 2022 12:18:21 +0200 Subject: [PATCH 063/157] ci: fix stale closer action review sort bug (#2201) This commit makes sure the PR staleness is checked by the latest review that is done. --- scripts/close-stale-theme-prs.js | 26 +++++++++++++++++++------- scripts/helpers.js | 1 - scripts/preview-theme.js | 1 - 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/scripts/close-stale-theme-prs.js b/scripts/close-stale-theme-prs.js index 8c14c1e3ce471..fedcc3a14b667 100644 --- a/scripts/close-stale-theme-prs.js +++ b/scripts/close-stale-theme-prs.js @@ -9,19 +9,28 @@ import github from "@actions/github"; import { RequestError } from "@octokit/request-error"; import { getGithubToken, getRepoInfo } from "./helpers.js"; -// Script parameters const CLOSING_COMMENT = ` \rThis PR has been automatically closed due to inactivity. Please feel free to reopen it if you need to continue working on it.\ \rThank you for your contributions. `; +const REVIEWER = "github-actions[bot]"; + +/** + * Retrieve the review user. + * @returns {string} review user. + */ +const getReviewer = () => { + return process.env.REVIEWER ? process.env.REVIEWER : REVIEWER; +}; /** * Fetch open PRs from a given repository. * @param user The user name of the repository owner. * @param repo The name of the repository. + * @param reviewer The reviewer to filter by. * @returns The open PRs. */ -export const fetchOpenPRs = async (octokit, user, repo) => { +export const fetchOpenPRs = async (octokit, user, repo, reviewer) => { const openPRs = []; let hasNextPage = true; let endCursor; @@ -49,9 +58,9 @@ export const fetchOpenPRs = async (octokit, user, repo) => { name } } - reviews(first: 1, states: CHANGES_REQUESTED, author: "github-actions[bot]") { + reviews(first: 100, states: CHANGES_REQUESTED, author: "${reviewer}") { nodes { - updatedAt + submittedAt } } } @@ -99,11 +108,13 @@ const isStale = (pullRequest, staleDays) => { pullRequest.commits.nodes[0].commit.pushedDate, ); if (pullRequest.reviews.nodes[0]) { - const lastReviewDate = new Date(pullRequest.reviews.nodes[0].updatedAt); + const lastReviewDate = new Date( + pullRequest.reviews.nodes.sort((a, b) => (a < b ? 1 : -1))[0].submittedAt, + ); const lastUpdateDate = lastCommitDate >= lastReviewDate ? lastCommitDate : lastReviewDate; const now = new Date(); - return now - lastUpdateDate > 1000 * 60 * 60 * 24 * staleDays; + return (now - lastUpdateDate) / (1000 * 60 * 60 * 24) >= staleDays; } else { return false; } @@ -120,10 +131,11 @@ const run = async () => { debug("Creating octokit client..."); const octokit = github.getOctokit(getGithubToken()); const { owner, repo } = getRepoInfo(github.context); + const reviewer = getReviewer(); // Retrieve all theme pull requests. debug("Retrieving all theme pull requests..."); - const prs = await fetchOpenPRs(octokit, owner, repo); + const prs = await fetchOpenPRs(octokit, owner, repo, reviewer); const themePRs = pullsWithLabel(prs, "themes"); const invalidThemePRs = pullsWithLabel(themePRs, "invalid"); debug("Retrieving stale theme PRs..."); diff --git a/scripts/helpers.js b/scripts/helpers.js index 3fc5fc7d00eee..bc9621e47b72e 100644 --- a/scripts/helpers.js +++ b/scripts/helpers.js @@ -4,7 +4,6 @@ import { getInput } from "@actions/core"; -// Script variables. const OWNER = "anuraghazra"; const REPO = "github-readme-stats"; diff --git a/scripts/preview-theme.js b/scripts/preview-theme.js index 0dc3da253d22a..9fbe07c41b8c8 100644 --- a/scripts/preview-theme.js +++ b/scripts/preview-theme.js @@ -16,7 +16,6 @@ import { isValidHexColor } from "../src/common/utils.js"; import { themes } from "../themes/index.js"; import { getGithubToken, getRepoInfo } from "./helpers.js"; -// Script variables. const COMMENTER = "github-actions[bot]"; const COMMENT_TITLE = "Automated Theme Preview"; From dcc4ccd18cbd24fe1d40780516fb2db17c037c44 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Tue, 18 Oct 2022 17:15:25 +0200 Subject: [PATCH 064/157] ci: increase invalid theme close time (#2210) This commits increases the theme invalid close time to 20 days. --- .github/workflows/stale-theme-pr-closer.yaml | 2 +- scripts/close-stale-theme-prs.js | 2 +- scripts/preview-theme.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/stale-theme-pr-closer.yaml b/.github/workflows/stale-theme-pr-closer.yaml index 8b1c78b4d8694..9a6249825263e 100644 --- a/.github/workflows/stale-theme-pr-closer.yaml +++ b/.github/workflows/stale-theme-pr-closer.yaml @@ -26,5 +26,5 @@ jobs: - run: npm run close-stale-theme-prs env: - STALE_DAYS: 15 + STALE_DAYS: 20 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/scripts/close-stale-theme-prs.js b/scripts/close-stale-theme-prs.js index fedcc3a14b667..def7ef4548310 100644 --- a/scripts/close-stale-theme-prs.js +++ b/scripts/close-stale-theme-prs.js @@ -127,7 +127,7 @@ const run = async () => { try { // Create octokit client. const dryRun = process.env.DRY_RUN === "true" || false; - const staleDays = process.env.STALE_DAYS || 15; + const staleDays = process.env.STALE_DAYS || 20; debug("Creating octokit client..."); const octokit = github.getOctokit(getGithubToken()); const { owner, repo } = getRepoInfo(github.context); diff --git a/scripts/preview-theme.js b/scripts/preview-theme.js index 9fbe07c41b8c8..5f705f012177c 100644 --- a/scripts/preview-theme.js +++ b/scripts/preview-theme.js @@ -24,7 +24,7 @@ const THEME_PR_SUCCESS_TEXT = ":heavy_check_mark: Theme PR does adhere to our guidelines."; 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 15 days** if no changes are made. After this time, you must re-open the PR for it to be reviewed. + \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 = ` \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). From 98f9045f987112bb3d4f1a0160f3e0d93ef5bd52 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Tue, 18 Oct 2022 18:07:38 +0200 Subject: [PATCH 065/157] fix: improve error caching behavoir (#2211) This commit ensures that the GraphQL Pat error is not cached in any browser. See https://github.com/anuraghazra/github-readme-stats/issues/1471#issuecomment-1282630614. --- api/index.js | 2 +- api/pin.js | 2 +- api/top-langs.js | 2 +- api/wakatime.js | 2 +- tests/api.test.js | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/api/index.js b/api/index.js index 3b5e949d71d36..34824ba658a1f 100644 --- a/api/index.js +++ b/api/index.js @@ -89,7 +89,7 @@ export default async (req, res) => { }), ); } catch (err) { - res.setHeader("Cache-Control", `no-store`); // Don't cache error responses. + res.setHeader("Cache-Control", `no-cache, no-store, must-revalidate`); // Don't cache error responses. return res.send(renderError(err.message, err.secondaryMessage)); } }; diff --git a/api/pin.js b/api/pin.js index 84ca4e64c3d9c..ef149948d0ef6 100644 --- a/api/pin.js +++ b/api/pin.js @@ -75,7 +75,7 @@ export default async (req, res) => { }), ); } catch (err) { - res.setHeader("Cache-Control", `no-store`); // Don't cache error responses. + res.setHeader("Cache-Control", `no-cache, no-store, must-revalidate`); // Don't cache error responses. return res.send(renderError(err.message, err.secondaryMessage)); } }; diff --git a/api/top-langs.js b/api/top-langs.js index a6a9d286d253e..25f97c8b455b2 100644 --- a/api/top-langs.js +++ b/api/top-langs.js @@ -76,7 +76,7 @@ export default async (req, res) => { }), ); } catch (err) { - res.setHeader("Cache-Control", `no-store`); // Don't cache error responses. + res.setHeader("Cache-Control", `no-cache, no-store, must-revalidate`); // Don't cache error responses. return res.send(renderError(err.message, err.secondaryMessage)); } }; diff --git a/api/wakatime.js b/api/wakatime.js index 60d22b5c9c8dd..fb8caa51c9477 100644 --- a/api/wakatime.js +++ b/api/wakatime.js @@ -78,7 +78,7 @@ export default async (req, res) => { }), ); } catch (err) { - res.setHeader("Cache-Control", `no-store`); // Don't cache error responses. + res.setHeader("Cache-Control", `no-cache, no-store, must-revalidate`); // Don't cache error responses. return res.send(renderError(err.message, err.secondaryMessage)); } }; diff --git a/tests/api.test.js b/tests/api.test.js index c05f25a63d005..f77a7175b43d7 100644 --- a/tests/api.test.js +++ b/tests/api.test.js @@ -180,7 +180,7 @@ describe("Test /api/", () => { expect(res.setHeader.mock.calls).toEqual([ ["Content-Type", "image/svg+xml"], - ["Cache-Control", `no-store`], + ["Cache-Control", `no-cache, no-store, must-revalidate`], ]); }); From 8e3147014ca6ef63033574f12c70c1372ec26db8 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Mon, 24 Oct 2022 14:18:37 +0200 Subject: [PATCH 066/157] refactor: make issue templates required (#2226) --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 ++ .github/ISSUE_TEMPLATE/feature_request.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 854c103feef8f..198bc80ef0fe4 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -11,6 +11,8 @@ body: attributes: label: Describe the bug description: A clear and concise description of what the bug is. + validations: + required: true - type: textarea attributes: label: Expected behaviour diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 239fcc9147916..fe3a4b3411bfb 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -9,6 +9,8 @@ body: description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + validations: + required: true - type: textarea attributes: label: Describe the solution you'd like From 199870aa9f7f59afd6950e7917cb758df2f8dea4 Mon Sep 17 00:00:00 2001 From: Frieder Bluemle Date: Wed, 26 Oct 2022 07:41:59 -0700 Subject: [PATCH 067/157] refactor: fix GitHub capitalization (#2232) --- docs/readme_kr.md | 6 +++--- docs/readme_np.md | 4 ++-- docs/readme_tr.md | 14 +++++++------- readme.md | 4 ++-- scripts/helpers.js | 2 +- scripts/preview-theme.js | 2 +- scripts/push-theme-readme.sh | 2 +- src/fetchers/repo-fetcher.js | 6 +++--- src/fetchers/stats-fetcher.js | 12 ++++++------ src/fetchers/top-languages-fetcher.js | 4 ++-- src/translations.js | 2 +- 11 files changed, 29 insertions(+), 29 deletions(-) diff --git a/docs/readme_kr.md b/docs/readme_kr.md index f5dfc9f2edf19..ce0b4ad0379ee 100644 --- a/docs/readme_kr.md +++ b/docs/readme_kr.md @@ -1,7 +1,7 @@

GitHub Readme Stats

GitHub Readme Stats

-

동적으로 생성되는 Github 사용량 통계를 여러분의 README 에 추가해보세요!

+

동적으로 생성되는 GitHub 사용량 통계를 여러분의 README 에 추가해보세요!

@@ -72,7 +72,7 @@ 아래 코드를 복사해서 마크다운 파일에 붙여넣으면 끝이에요, 아주 간단해요! -`?username=` 속성의 값을 Github 계정의 사용자 명(닉네임)으로 바꿔주세요. +`?username=` 속성의 값을 GitHub 계정의 사용자 명(닉네임)으로 바꿔주세요. ```md [![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra)](https://github.com/anuraghazra/github-readme-stats) @@ -235,7 +235,7 @@ GitHub 저장소 여분 핀을 이용하면, 6개 이상의 저장소 핀을 여 # 언어 사용량 통계 -언어 사용량 통계 카드는 Github 사용자가 가장 많이 사용한 언어가 표시됩니다. +언어 사용량 통계 카드는 GitHub 사용자가 가장 많이 사용한 언어가 표시됩니다. _참고: 언어 사용량 통계는 GitHub 에서 가장 많이 사용된 언어의 표기일 뿐입니다. diff --git a/docs/readme_np.md b/docs/readme_np.md index 15bb34ba601b8..654427fbda654 100644 --- a/docs/readme_np.md +++ b/docs/readme_np.md @@ -219,7 +219,7 @@ Use [show_owner](#customization) variable to include the repo's owner username टोप भाषाकार्डले github परयोग गर्नेहरुको प्रोग्रम्मिंग भाषाहरु देखाऊने गर्दछ |. -_NOTE: टोप भाषाहरुले आफ्नो सिपलाए संकेत गरेको होईन | योचै Github Metricबाट धेरै कुन भाषा परयोग भाकोलाए संकेत गरेको हो | +_NOTE: टोप भाषाहरुले आफ्नो सिपलाए संकेत गरेको होईन | योचै GitHub Metricबाट धेरै कुन भाषा परयोग भाकोलाए संकेत गरेको हो | ### प्रयोग कोदलाए कपी- पेसेत readme मा गर्नु होला र लिंक परिवतन गर्नु होला | @@ -389,7 +389,7 @@ NOTE: Since [#58](https://github.com/anuraghazra/github-readme-stats/pull/58) we येदि तपाइले यो प्रोजेक्ट चलाउनु बाकोक्ष बने र मलाई अझै प्रसंसा गर्ने हो बने तपाइले थुप्रै तरिका ले गर्नु सक्नु हुने छ :- - यो प्रोजेक्टमा तपाइले प्रहयोग गर्दा मलाई क्रेडिट दिन सक्नु हुनेक्ष । -- तपाइले Github ReadMe Stats स्तार्रेड गर्न सक्नु हुनेक्ष :rocket: +- तपाइले GitHub ReadMe Stats स्तार्रेड गर्न सक्नु हुनेक्ष :rocket: - [![paypal.me/anuraghazra](https://ionicabizau.github.io/badges/paypal.svg)](https://www.paypal.me/anuraghazra) - तपाइले पेपाल बाट पनि सहयोग (डक्क्षिन) गर्न सक्नु हुनेक्ष | म ~~कोफी ~~ चिया . :tea: किन्न सक्क्षु । धन्याबाद! :heart: diff --git a/docs/readme_tr.md b/docs/readme_tr.md index 35f32f2f20f99..7b11cf3706f1e 100644 --- a/docs/readme_tr.md +++ b/docs/readme_tr.md @@ -73,10 +73,10 @@ Alt kısımdaki kodu Kopyalayın ve yapıştırın. İşte bu kadar. Çok basit! -`?username=` değerini kendi Github kullanıcı adınız ile değiştirin. +`?username=` değerini kendi GitHub kullanıcı adınız ile değiştirin. ```md -[![Anurag'nın Github İstatistikleri](https://github-readme-stats.vercel.app/api?username=anuraghazra)](https://github.com/anuraghazra/github-readme-stats) +[![Anurag'nın GitHub İstatistikleri](https://github-readme-stats.vercel.app/api?username=anuraghazra)](https://github.com/anuraghazra/github-readme-stats) ``` _Not: Şu sıralamalar mevcut: S+ (en üst 1%), S (en üst 25%), A++ (en üst 45%), A+ (en üst 60%), and B+ (herkes). Buradaki değerler [cumulative distribution function](https://en.wikipedia.org/wiki/Cumulative_distribution_function) ile hesaplanırken; commitler, katkılar, hatalar, yıldızlar, çekme istekleri, takipçiler ve sahip olunan depolar (repository) göz önünde bulundurulamaktadır. @@ -199,7 +199,7 @@ bg_color içerisinde birden fazla rengi gradient olarak göstermek için virgül # GitHub Ekstra Pinler -Github ekstra pinler profilinize 6'dan fazla repoyu / depoyu profilinizde pinleyebilirsiniz. +GitHub ekstra pinler profilinize 6'dan fazla repoyu / depoyu profilinizde pinleyebilirsiniz. Hey! Artık 6 pin ile kısıtlı kalmayacaksınız! @@ -225,7 +225,7 @@ Endpoint: `api/pin?username=mustafacagri&repo=github-readme-stats` En çok kullanılan diller kartı kullanıcının en çok kullandığı dilleri gösterir. -_NOTE: En çok kullanılan dillerde yer alan bilgiler sizin yeteneğinizi ve benzeri şeyleri göstermek. Bu, kodlarınızda en çok kullandığınız dilleri gösteren bir Github metriğidir. Ayrıca, github-readme-stats'ın yeni özelliğidir. +_NOTE: En çok kullanılan dillerde yer alan bilgiler sizin yeteneğinizi ve benzeri şeyleri göstermek. Bu, kodlarınızda en çok kullandığınız dilleri gösteren bir GitHub metriğidir. Ayrıca, github-readme-stats'ın yeni özelliğidir. ### Kullanım @@ -365,7 +365,7 @@ Genellikle resimleri yan yana düzenleyemezsiniz. Bunu yapmak için şu yaklaş #### [@codeSTACKr'ın Yayınladığı Video Eğitimine Göz Atın](https://youtu.be/n6d4KHSKqGk?t=107) -Github API saatte sadece 5.000 isteğe izin verdiği için `https://github-readme-stats.vercel.app/api` adresindeki API'm bu limite muhtemelen takılmış olabilir. Eğer projeyi kendi Vercel sunucunuzda yayınlarsanız, böyle bir sorun yaşamayabilirsiniz. Deploy butonuna tıkla ve deploy başlasın! +GitHub API saatte sadece 5.000 isteğe izin verdiği için `https://github-readme-stats.vercel.app/api` adresindeki API'm bu limite muhtemelen takılmış olabilir. Eğer projeyi kendi Vercel sunucunuzda yayınlarsanız, böyle bir sorun yaşamayabilirsiniz. Deploy butonuna tıkla ve deploy başlasın! NOT: [#58](https://github.com/anuraghazra/github-readme-stats/pull/58) geliştirmesi sonrasında anlamadığımız bir şekilde 5.000 istek limitine takılmıyoruz :) @@ -378,9 +378,9 @@ NOT: [#58](https://github.com/anuraghazra/github-readme-stats/pull/58) geliştir 1. [vercel.com](https://vercel.com/) adresine gidin 1. `Log in`'e tıklayın ![](https://files.catbox.moe/tct1wg.png) -1. `Continue with GitHub`'e basarak Github ile giriş yapın +1. `Continue with GitHub`'e basarak GitHub ile giriş yapın ![](https://files.catbox.moe/btd78j.jpeg) -1. Github'a giriş yapın ve eğer çıkarsa tüm repolara izin verin. +1. GitHub'a giriş yapın ve eğer çıkarsa tüm repolara izin verin. 1. Bu repoyu fork'layın 1. [Vercel dashboard](https://vercel.com/dashboard)'unuza geri dönün. 1. `Import Project`'i seçin. diff --git a/readme.md b/readme.md index 9c773ff84707c..926c52c59cf5a 100644 --- a/readme.md +++ b/readme.md @@ -150,7 +150,7 @@ Use `&theme=THEME_NAME` parameter like so : #### All inbuilt themes -Github readme stats comes with several built-in themes (e.g. `dark`, `radical`, `merko`, `gruvbox`, `tokyonight`, `onedark`, `cobalt`, `synthwave`, `highcontrast`, `dracula`). +GitHub readme stats comes with several built-in themes (e.g. `dark`, `radical`, `merko`, `gruvbox`, `tokyonight`, `onedark`, `cobalt`, `synthwave`, `highcontrast`, `dracula`). GitHub Readme Stats Themes @@ -193,7 +193,7 @@ You can provide multiple comma-separated values in the bg_color option to render - `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`. +- `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`. diff --git a/scripts/helpers.js b/scripts/helpers.js index bc9621e47b72e..6746adc92693c 100644 --- a/scripts/helpers.js +++ b/scripts/helpers.js @@ -30,7 +30,7 @@ export const getRepoInfo = (ctx) => { /** * Retrieve github token and throw error if it is not found. * - * @returns {string} Github token. + * @returns {string} GitHub token. */ export const getGithubToken = () => { const token = getInput("github_token") || process.env.GITHUB_TOKEN; diff --git a/scripts/preview-theme.js b/scripts/preview-theme.js index 5f705f012177c..38faf873ce3d5 100644 --- a/scripts/preview-theme.js +++ b/scripts/preview-theme.js @@ -92,7 +92,7 @@ const isPreviewComment = (inputs, comment) => { * @param {number} issueNumber Issue number. * @param {string} repo Repository name. * @param {string} owner Owner of the repository. - * @returns {Object} The Github comment object. + * @returns {Object} The GitHub comment object. */ const findComment = async (octokit, issueNumber, owner, repo, commenter) => { const parameters = { diff --git a/scripts/push-theme-readme.sh b/scripts/push-theme-readme.sh index 946096bd4d592..4a035db3041a0 100755 --- a/scripts/push-theme-readme.sh +++ b/scripts/push-theme-readme.sh @@ -5,7 +5,7 @@ set -e 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 user.name "GitHub Readme Stats Bot" git branch -d $BRANCH_NAME || true git checkout -b $BRANCH_NAME git add --all diff --git a/src/fetchers/repo-fetcher.js b/src/fetchers/repo-fetcher.js index 9ff907c82bae6..28dd89a7f3e4a 100644 --- a/src/fetchers/repo-fetcher.js +++ b/src/fetchers/repo-fetcher.js @@ -6,7 +6,7 @@ import { MissingParamError, request } from "../common/utils.js"; * Repo data fetcher. * * @param {import('Axios').AxiosRequestHeaders} variables Fetcher variables. - * @param {string} token Github token. + * @param {string} token GitHub token. * @returns {Promise} The response. */ const fetcher = (variables, token) => { @@ -56,8 +56,8 @@ const urlExample = "/api/pin?username=USERNAME&repo=REPO_NAME"; /** * Fetch repository data. * - * @param {string} username Github username. - * @param {string} reponame Github repository name. + * @param {string} username GitHub username. + * @param {string} reponame GitHub repository name. * @returns {Promise} Repository data. */ async function fetchRepo(username, reponame) { diff --git a/src/fetchers/stats-fetcher.js b/src/fetchers/stats-fetcher.js index d592b75857a8a..c236b5882b42f 100644 --- a/src/fetchers/stats-fetcher.js +++ b/src/fetchers/stats-fetcher.js @@ -18,7 +18,7 @@ dotenv.config(); * Stats fetcher object. * * @param {import('axios').AxiosRequestHeaders} variables Fetcher variables. - * @param {string} token Github token. + * @param {string} token GitHub token. * @returns {Promise} Stats fetcher response. */ const fetcher = (variables, token) => { @@ -66,7 +66,7 @@ const fetcher = (variables, token) => { * Fetch first 100 repositories for a given username. * * @param {import('axios').AxiosRequestHeaders} variables Fetcher variables. - * @param {string} token Github token. + * @param {string} token GitHub token. * @returns {Promise} Repositories fetcher response. */ const repositoriesFetcher = (variables, token) => { @@ -101,10 +101,10 @@ const repositoriesFetcher = (variables, token) => { /** * Fetch all the commits for all the repositories of a given username. * - * @param {*} username Github username. + * @param {*} username GitHub username. * @returns {Promise} Total commits. * - * @description Done like this because the Github API does not provide a way to fetch all the commits. See + * @description Done like this because the GitHub API does not provide a way to fetch all the commits. See * #92#issuecomment-661026467 and #211 for more information. */ const totalCommitsFetcher = async (username) => { @@ -143,7 +143,7 @@ const totalCommitsFetcher = async (username) => { /** * Fetch all the stars for all the repositories of a given username. * - * @param {string} username Github username. + * @param {string} username GitHub username. * @param {array} repoToHide Repositories to hide. * @returns {Promise} Total stars. */ @@ -183,7 +183,7 @@ const totalStarsFetcher = async (username, repoToHide) => { /** * Fetch stats for a given username. * - * @param {string} username Github username. + * @param {string} username GitHub username. * @param {boolean} count_private Include private contributions. * @param {boolean} include_all_commits Include all commits. * @returns {Promise} Stats data. diff --git a/src/fetchers/top-languages-fetcher.js b/src/fetchers/top-languages-fetcher.js index ba3fc72ca7e03..109fa06bd2207 100644 --- a/src/fetchers/top-languages-fetcher.js +++ b/src/fetchers/top-languages-fetcher.js @@ -15,7 +15,7 @@ dotenv.config(); * Top languages fetcher object. * * @param {import('Axios').AxiosRequestHeaders} variables Fetcher variables. - * @param {string} token Github token. + * @param {string} token GitHub token. * @returns {Promise} Languages fetcher response. */ const fetcher = (variables, token) => { @@ -53,7 +53,7 @@ const fetcher = (variables, token) => { /** * Fetch top languages for a given username. * - * @param {string} username Github username. + * @param {string} username GitHub username. * @param {string[]} exclude_repo List of repositories to exclude. * @returns {Promise} Top languages data. */ diff --git a/src/translations.js b/src/translations.js index b71d37f9d7a03..904da37d8f1ba 100644 --- a/src/translations.js +++ b/src/translations.js @@ -37,7 +37,7 @@ const statCardLocales = ({ name, apostrophe }) => { sk: `GitHub štatistiky používateľa ${encodedName}`, tr: `${encodedName} Hesabının GitHub Yıldızları`, pl: `Statystyki GitHub użytkownika ${encodedName}`, - uz: `${encodedName}ning Github'dagi statistikasi`, + uz: `${encodedName}ning GitHub'dagi statistikasi`, vi: `Thống Kê GitHub ${encodedName}`, se: `GitHubstatistik för ${encodedName}`, }, From 45f434f0830b9ef06067469d69183103e0079127 Mon Sep 17 00:00:00 2001 From: Falguni Sarkar Date: Fri, 28 Oct 2022 13:13:17 +0530 Subject: [PATCH 068/157] docs: document auto theme change #2074 (#2229) * Document auto theme change in README #2074 * Document auto theme change in README Document auto theme change in README #2074 (update-1) * Document auto theme change updates #2074 * docs: improve dynamic theme documentation Co-authored-by: rickstaa --- readme.md | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/readme.md b/readme.md index 926c52c59cf5a..7b81c37e0547e 100644 --- a/readme.md +++ b/readme.md @@ -85,6 +85,7 @@ Visit and make a small donation to hel - [Top Languages Card](#top-languages-card) - [Wakatime Week Stats](#wakatime-week-stats) - [Themes](#themes) + - [Responsive Card Theme](#responsive-card-theme) - [Customization](#customization) - [Common Options](#common-options) - [Stats Card Exclusive Options](#stats-card-exclusive-options) @@ -156,6 +157,95 @@ GitHub readme stats comes with several built-in themes (e.g. `dark`, `radical`, You can look at a preview for [all available themes](./themes/README.md) or checkout the [theme config file](./themes/index.js) & **you can also contribute new themes** if you like :D +#### Responsive Card Theme + +[![Anurag's GitHub stats-Dark](https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&theme=dark#gh-dark-mode-only)](https://github.com/anuraghazra/github-readme-stats#gh-dark-mode-only) +[![Anurag's GitHub stats-Light](https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&theme=default#gh-light-mode-only)](https://github.com/anuraghazra/github-readme-stats#gh-light-mode-only) + +Since GitHub will re-upload the cards and serve them from their [CDN](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/about-anonymized-urls), we can not infer the browser/GitHub theme on the server side. There are, however, four methods you can use to create dynamics themes on the client side: + +##### Use the transparent theme + +We have included a `transparent` theme that has a transparent background. This theme is optimized to look good on GitHub's dark and light default themes. You can enable this theme using the `&theme=transparent` parameter like so: + +```md +![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&theme=transparent) +``` + +

+:eyes: Show example + +![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&theme=transparent) + +
+ +##### 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`): + +```md +![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&bg_color=00000000) +``` + +
+:eyes: Show example + +![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&bg_color=00000000) + +
+ +##### Use GitHub's theme context tag + +You can use [GitHub's theme context](https://github.blog/changelog/2021-11-24-specify-theme-context-for-images-in-markdown/) tags to switch the theme based on the user GitHub theme automatically. This is done by appending `#gh-dark-mode-only` or `#gh-light-mode-only` to the end of an image URL. This tag will define whether the image specified in the markdown is only shown to viewers using a light or a dark GitHub theme: + +```md +[![Anurag's GitHub stats-Dark](https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&theme=dark#gh-dark-mode-only)](https://github.com/anuraghazra/github-readme-stats#gh-dark-mode-only) +[![Anurag's GitHub stats-Light](https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&theme=default#gh-light-mode-only)](https://github.com/anuraghazra/github-readme-stats#gh-light-mode-only) +``` + +
+:eyes: Show example + +[![Anurag's GitHub stats-Dark](https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&theme=dark#gh-dark-mode-only)](https://github.com/anuraghazra/github-readme-stats#gh-dark-mode-only) +[![Anurag's GitHub stats-Light](https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&theme=default#gh-light-mode-only)](https://github.com/anuraghazra/github-readme-stats#gh-light-mode-only) + +
+ +##### 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 + + + + + +``` + +
+:eyes: Show example + + + + + + + +
+ ### Customization You can customize the appearance of your `Stats Card` or `Repo Card` however you wish with URL parameters. From f993f213796c0aadeefeefae12286db2762edaad Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Fri, 28 Oct 2022 10:03:11 +0200 Subject: [PATCH 069/157] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 7b81c37e0547e..e18efc80f73b9 100644 --- a/readme.md +++ b/readme.md @@ -162,7 +162,7 @@ You can look at a preview for [all available themes](./themes/README.md) or chec [![Anurag's GitHub stats-Dark](https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&theme=dark#gh-dark-mode-only)](https://github.com/anuraghazra/github-readme-stats#gh-dark-mode-only) [![Anurag's GitHub stats-Light](https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&theme=default#gh-light-mode-only)](https://github.com/anuraghazra/github-readme-stats#gh-light-mode-only) -Since GitHub will re-upload the cards and serve them from their [CDN](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/about-anonymized-urls), we can not infer the browser/GitHub theme on the server side. There are, however, four methods you can use to create dynamics themes on the client side: +Since GitHub will re-upload the cards and serve them from their [CDN](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/about-anonymized-urls), we can not infer the browser/GitHub theme on the server side. There are, however, four methods you can use to create dynamics themes on the client side. ##### Use the transparent theme From c0d7493c3f0c1af7b5294e045f5688f914d930b5 Mon Sep 17 00:00:00 2001 From: Ray Chan Date: Sat, 29 Oct 2022 02:47:09 +0800 Subject: [PATCH 070/157] Fix truncation of compact wakatime progress bar when langs_count is set (#2228) * refactor: use default value for languages * fix: truncated compact progress bar * test: add test for truncated compact progress bar with langs_count set --- src/cards/wakatime-card.js | 18 +- .../renderWakatimeCard.test.js.snap | 164 +++++++++++++++++- tests/renderWakatimeCard.test.js | 9 + 3 files changed, 180 insertions(+), 11 deletions(-) diff --git a/src/cards/wakatime-card.js b/src/cards/wakatime-card.js index 8b042fd2f1a69..e7af1df710f9c 100644 --- a/src/cards/wakatime-card.js +++ b/src/cards/wakatime-card.js @@ -159,7 +159,7 @@ const recalculatePercentages = (languages) => { * @returns {string} WakaTime card SVG. */ const renderWakatimeCard = (stats = {}, options = { hide: [] }) => { - let { languages } = stats; + let { languages = [] } = stats; const { hide_title = false, hide_border = false, @@ -174,20 +174,24 @@ const renderWakatimeCard = (stats = {}, options = { hide: [] }) => { custom_title, locale, layout, - langs_count = languages ? languages.length : 0, + langs_count = languages.length, border_radius, border_color, } = options; const shouldHideLangs = Array.isArray(hide) && hide.length > 0; - if (shouldHideLangs && languages !== undefined) { + if (shouldHideLangs) { const languagesToHide = new Set(hide.map((lang) => lowercaseTrim(lang))); languages = languages.filter( (lang) => !languagesToHide.has(lowercaseTrim(lang.name)), ); - recalculatePercentages(languages); } + // Since the percentages are sorted in descending order, we can just + // slice from the beginning without sorting. + languages = languages.slice(0, langs_count); + recalculatePercentages(languages); + const i18n = new I18n({ locale, translations: wakatimeCardLocales, @@ -209,10 +213,8 @@ const renderWakatimeCard = (stats = {}, options = { hide: [] }) => { }); const filteredLanguages = languages - ? languages - .filter((language) => language.hours || language.minutes) - .slice(0, langsCount) - : []; + .filter((language) => language.hours || language.minutes) + .slice(0, langsCount); // Calculate the card height depending on how many items there are // but if rank circle is visible clamp the minimum height to `150` diff --git a/tests/__snapshots__/renderWakatimeCard.test.js.snap b/tests/__snapshots__/renderWakatimeCard.test.js.snap index dd9ffd318a61a..416ead953e459 100644 --- a/tests/__snapshots__/renderWakatimeCard.test.js.snap +++ b/tests/__snapshots__/renderWakatimeCard.test.js.snap @@ -122,7 +122,7 @@ exports[`Test Render Wakatime Card should render correctly with compact layout 1 data-testid="lang-progress" x="0" y="0" - width="6.6495" + width="415.61699999999996" height="8" fill="#858585" /> @@ -130,9 +130,167 @@ exports[`Test Render Wakatime Card should render correctly with compact layout 1 + + + + + + Other - 19 mins + + + + + + + TypeScript - 1 min + + + + + + + + + " +`; + +exports[`Test Render Wakatime Card should render correctly with compact layout when langs_count is set 1`] = ` +" + + + + + + + + + + + + + Wakatime Stats + + + + + + + + + + + + + + + diff --git a/tests/renderWakatimeCard.test.js b/tests/renderWakatimeCard.test.js index 098e9f7ee6193..67969bef50063 100644 --- a/tests/renderWakatimeCard.test.js +++ b/tests/renderWakatimeCard.test.js @@ -16,6 +16,15 @@ describe("Test Render Wakatime Card", () => { expect(card).toMatchSnapshot(); }); + it("should render correctly with compact layout when langs_count is set", () => { + const card = renderWakatimeCard(wakaTimeData.data, { + layout: "compact", + langs_count: 2, + }); + + expect(card).toMatchSnapshot(); + }); + it("should hide languages when hide is passed", () => { document.body.innerHTML = renderWakatimeCard(wakaTimeData.data, { hide: ["YAML", "Other"], From f9e95b166dd347104047392316409015be6a2201 Mon Sep 17 00:00:00 2001 From: Tymoteusz Marzec <59064153+InfoTCube@users.noreply.github.com> Date: Sat, 29 Oct 2022 15:41:04 +0200 Subject: [PATCH 071/157] Corrections of Polish expressions in translations.js (#2240) --- src/translations.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/translations.js b/src/translations.js index 904da37d8f1ba..65fc231f59b4e 100644 --- a/src/translations.js +++ b/src/translations.js @@ -67,7 +67,7 @@ const statCardLocales = ({ name, apostrophe }) => { my: "Jumlah Bintang", sk: "Hviezdy", tr: "Toplam Yıldız", - pl: "Liczba Gwiazdek dostanych", + pl: "Liczba otrzymanych gwiazdek", uz: "Yulduzchalar", vi: "Tổng Số Sao", se: "Antal intjänade stjärnor", @@ -160,7 +160,7 @@ const statCardLocales = ({ name, apostrophe }) => { my: "Jumlah Isu Dilaporkan", sk: "Všetky problémy", tr: "Toplam Hata", - pl: "Wszystkie Issues", + pl: "Wszystkie problemy", uz: "'Issue'lar", vi: "Tổng Số Vấn Đề", se: "Total antal issues", @@ -322,7 +322,7 @@ const wakatimeCardLocales = { my: "Statistik Wakatime", sk: "Wakatime štatistika", tr: "Waketime İstatistikler", - pl: "statystyki Wakatime", + pl: "Statystyki Wakatime", vi: "Thống Kê Wakatime", se: "Wakatime statistik", }, From 56aa307094923c02be37fa52e797c705bf72041d Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Fri, 18 Nov 2022 11:05:10 +0100 Subject: [PATCH 072/157] ci: update theme stale close message --- scripts/close-stale-theme-prs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/close-stale-theme-prs.js b/scripts/close-stale-theme-prs.js index def7ef4548310..484351c123c3a 100644 --- a/scripts/close-stale-theme-prs.js +++ b/scripts/close-stale-theme-prs.js @@ -10,7 +10,7 @@ import { RequestError } from "@octokit/request-error"; import { getGithubToken, getRepoInfo } from "./helpers.js"; const CLOSING_COMMENT = ` - \rThis PR has been automatically closed due to inactivity. Please feel free to reopen it if you need to continue working on it.\ + \rThis theme PR has been automatically closed due to inactivity. Please reopen it if you need to continue working on it.\ \rThank you for your contributions. `; const REVIEWER = "github-actions[bot]"; From 1a4e5a69551c249a2eeaeb31f066718b2b104b82 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Fri, 18 Nov 2022 11:06:24 +0100 Subject: [PATCH 073/157] ci: update theme stale close message --- scripts/close-stale-theme-prs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/close-stale-theme-prs.js b/scripts/close-stale-theme-prs.js index 484351c123c3a..7db66f9775adb 100644 --- a/scripts/close-stale-theme-prs.js +++ b/scripts/close-stale-theme-prs.js @@ -10,7 +10,7 @@ import { RequestError } from "@octokit/request-error"; import { getGithubToken, getRepoInfo } from "./helpers.js"; const CLOSING_COMMENT = ` - \rThis theme PR has been automatically closed due to inactivity. Please reopen it if you need to continue working on it.\ + \rThis theme PR has been automatically closed due to inactivity. Please reopen it if you want to continue working on it.\ \rThank you for your contributions. `; const REVIEWER = "github-actions[bot]"; From 26cde6bfe9461096aa63f8475a5c7c73382e7d15 Mon Sep 17 00:00:00 2001 From: Fabian Joswig Date: Fri, 18 Nov 2022 14:19:04 +0000 Subject: [PATCH 074/157] Missing term in calculation of TOTAL_VALUES. (#2116) * fix: added missing term in calculation of TOTAL_VALUES. * fix: fix rank test * refactor: update code formatting * refactor: update code formatting Co-authored-by: rickstaa --- src/calculateRank.js | 6 +++++- tests/calculateRank.test.js | 2 +- tests/e2e/e2e.test.js | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/calculateRank.js b/src/calculateRank.js index 85d965802b5e9..23d61dba35ddb 100644 --- a/src/calculateRank.js +++ b/src/calculateRank.js @@ -70,7 +70,11 @@ function calculateRank({ const RANK_B_VALUE = 100; const TOTAL_VALUES = - RANK_S_VALUE + RANK_A2_VALUE + RANK_A3_VALUE + RANK_B_VALUE; + RANK_S_VALUE + + RANK_DOUBLE_A_VALUE + + RANK_A2_VALUE + + RANK_A3_VALUE + + RANK_B_VALUE; // prettier-ignore const score = ( diff --git a/tests/calculateRank.test.js b/tests/calculateRank.test.js index 5cc19a02aa73b..235b1b5f20b04 100644 --- a/tests/calculateRank.test.js +++ b/tests/calculateRank.test.js @@ -13,6 +13,6 @@ describe("Test calculateRank", () => { prs: 300, issues: 200, }), - ).toStrictEqual({ level: "A+", score: 49.16605417270399 }); + ).toStrictEqual({ level: "A+", score: 49.25629684876535 }); }); }); diff --git a/tests/e2e/e2e.test.js b/tests/e2e/e2e.test.js index 0a38d98002b49..48bf16a0e083a 100644 --- a/tests/e2e/e2e.test.js +++ b/tests/e2e/e2e.test.js @@ -22,7 +22,7 @@ const STATS_DATA = { contributedTo: 2, rank: { level: "A+", - score: 51.01013099671447, + score: 50.900829325065935, }, }; From 0c829e94885dd869720e1b4e4f428ffcbb58fcf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dtalo=20Sousa?= Date: Fri, 18 Nov 2022 11:49:38 -0300 Subject: [PATCH 075/157] Updates the brazilian readme (#2245) --- docs/readme_pt-BR.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/readme_pt-BR.md b/docs/readme_pt-BR.md index 7f4814cec669b..62c23dc55c7e2 100644 --- a/docs/readme_pt-BR.md +++ b/docs/readme_pt-BR.md @@ -53,6 +53,8 @@ Nederlands . नेपाली + . + Türkçe

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!

- Give india logo + Give india logo 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.