From 403693dd17c6edfad5cdb4eb21aa18362400ed6d Mon Sep 17 00:00:00 2001 From: Bear_03 <64696287+Bear-03@users.noreply.github.com> Date: Sun, 5 Oct 2025 22:49:17 +0200 Subject: [PATCH] feat: add support for EXCLUDE_REPO env variable (#1299) * Add support for EXCLUDE_REPO env variable * review * docs * refactor --------- Co-authored-by: Alexandr --- backend/readme.md | 1 + backend/src/common/excludeRepo.js | 6 ++++++ backend/src/fetchers/stats.js | 5 ++++- backend/src/fetchers/top-languages.js | 7 +++++-- 4 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 backend/src/common/excludeRepo.js diff --git a/backend/readme.md b/backend/readme.md index 303268e8..693bdcf9 100644 --- a/backend/readme.md +++ b/backend/readme.md @@ -922,6 +922,7 @@ GitHub Readme Stats provides several environment variables that can be used to c * `CACHE_SECONDS`: This takes precedence over our cache minimum and maximum values and can circumvent these values for self-hosted instances. * `WHITELIST`: A comma-separated list of GitHub usernames that are allowed to access your instance. If this variable is not set, all usernames are allowed. * `GIST_WHITELIST`: A comma-separated list of GitHub gist IDs that are allowed to be accessed on your instance. If this variable is not set, all gist IDs are allowed. +* `EXCLUDE_REPO`: A comma-separated list of repositories that will be excluded from stats and top languages cards on your instance. This allows repository exclusion without exposing repository names in public URLs. This enhances privacy for self-hosted instances that include private repositories in stats cards. See [the Vercel documentation](https://vercel.com/docs/concepts/projects/environment-variables) on adding these environment variables to your Vercel instance. diff --git a/backend/src/common/excludeRepo.js b/backend/src/common/excludeRepo.js new file mode 100644 index 00000000..4e42ff8a --- /dev/null +++ b/backend/src/common/excludeRepo.js @@ -0,0 +1,6 @@ +const excludeRepositories = process.env.EXCLUDE_REPO + ? process.env.EXCLUDE_REPO.split(",") + : []; + +export { excludeRepositories }; +export default excludeRepositories; diff --git a/backend/src/fetchers/stats.js b/backend/src/fetchers/stats.js index 2e642dc6..c87e2ecb 100644 --- a/backend/src/fetchers/stats.js +++ b/backend/src/fetchers/stats.js @@ -1,4 +1,5 @@ // @ts-check + import axios from "axios"; import * as dotenv from "dotenv"; import githubUsernameRegex from "github-username-regex"; @@ -13,6 +14,7 @@ import { wrapTextMultiline, parseOwnerAffiliations, } from "../common/utils.js"; +import excludeRepositories from "../common/excludeRepo.js"; dotenv.config(); @@ -423,7 +425,8 @@ const fetchStats = async ( stats.contributedTo = user.repositoriesContributedTo.totalCount; // Retrieve stars while filtering out repositories to be hidden. - let repoToHide = new Set(exclude_repo); + const allExcludedRepos = [...exclude_repo, ...excludeRepositories]; + let repoToHide = new Set(allExcludedRepos); stats.totalStars = user.repositories.nodes .filter((data) => { diff --git a/backend/src/fetchers/top-languages.js b/backend/src/fetchers/top-languages.js index 816c63a2..685b80df 100644 --- a/backend/src/fetchers/top-languages.js +++ b/backend/src/fetchers/top-languages.js @@ -1,4 +1,5 @@ // @ts-check + import { retryer } from "../common/retryer.js"; import { CustomError, @@ -8,6 +9,7 @@ import { wrapTextMultiline, parseOwnerAffiliations, } from "../common/utils.js"; +import excludeRepositories from "../common/excludeRepo.js"; /** * @typedef {import("axios").AxiosRequestHeaders} AxiosRequestHeaders Axios request headers. @@ -103,11 +105,12 @@ const fetchTopLanguages = async ( let repoNodes = res.data.data.user.repositories.nodes; let repoToHide = {}; + const allExcludedRepos = [...exclude_repo, ...excludeRepositories]; // populate repoToHide map for quick lookup // while filtering out - if (exclude_repo) { - exclude_repo.forEach((repoName) => { + if (allExcludedRepos) { + allExcludedRepos.forEach((repoName) => { repoToHide[repoName] = true; }); }