This directory contains a standalone script that:
- Lists the repositories assigned to a GitHub team.
- Lists the projects available in Sonar.
- Reports whether each GitHub repository appears to exist in Sonar.
- Marks repositories as excluded when they have neither a root
pom.xmlnor a rootpackage.json.
- Python 3.9+
- Node.js on
PATHfor Excel export - Either:
- a GitHub token with access to read the target organization/team
- or GitHub CLI (
gh) installed and authenticated withgh auth login
- A Sonar token with permission to browse projects
The script reads its credentials from CLI flags or environment variables. For GitHub auth it uses this order:
--github-tokenGITHUB_TOKENgh auth token
It also auto-loads a local .env file from the current directory before reading environment variables.
For teammates, start from .env.example and create a local .env with your own credentials and exclusions.
If you want to rely on GitHub CLI instead of exporting GITHUB_TOKEN, log in once:
gh auth loginTo create a Sonar token:
- Log in to your Sonar instance
- Open your profile menu
- Go to
My Account - Open
Security - Generate a new token
- Copy it immediately, because Sonar only shows it once
Then set the rest:
export GITHUB_ORG="your-org"
export GITHUB_TEAM_SLUG="your-team-slug"
export SONAR_URL="https://sonar.example.com"
export SONAR_TOKEN="sonar_token"Or copy .env.example to .env and fill in your own values.
Optional:
export GITHUB_API_URL="https://api.github.com"
export GITHUB_REPO_PREFIXES="analytics-,shared-"
export GITHUB_REPO_IGNORE_LIST="analytics-wrong-match"
export GITHUB_REPO_OBSOLETE_LIST="analytics-sunset-service"
export GITHUB_REPO_NO_PRODUCTIVE_CODE_LIST="shared-docs-only"
export GITHUB_REPO_FORKED_LIBRARIES_LIST="analytics-forked-lib"
export XLSX_OUTPUT_PATH=""GITHUB_REPO_PREFIXES is a comma-separated allowlist on GitHub repository names. Only repositories whose names start with one of those prefixes are included in the report. Set it to an empty string to disable prefix filtering.
The exclusion lists are comma-separated and each entry can be either a repo name such as analytics-legacy or a full repo name such as mapp-digital/analytics-legacy.
For JavaScript submodules under packages/, exclusions can also target the submodule using one of these forms:
submodule-namepackages/submodule-namerepo-name/packages/submodule-nameorg/repo-name/packages/submodule-name
Use the most specific form when possible. org/repo-name/packages/submodule-name is the safest choice.
GITHUB_REPO_IGNORE_LIST: wrong match, completely omitted from the script outputGITHUB_REPO_OBSOLETE_LIST: sunset projects not being integrated to SonarGITHUB_REPO_NO_PRODUCTIVE_CODE_LIST: projects that do not make sense in SonarGITHUB_REPO_FORKED_LIBRARIES_LIST: forked libraries that should be excluded from Sonar tracking
XLSX_OUTPUT_PATH controls where the script writes the Excel workbook. If unset or empty, the script generates a timestamped filename in outputs/ so each run creates a new workbook. Set it to an empty string only if you want the default timestamped behavior.
If node is not on PATH, you can override the binary with NODE_BINARY=/absolute/path/to/node.
Default table output:
python3 check_team_repos_against_sonar.pyThe script writes progress logs to stderr while it runs, so long GitHub and Sonar scans stay visible without changing the table/JSON output on stdout.
It also writes an Excel workbook to a timestamped file in outputs/ by default.
Only list repositories missing from Sonar:
python3 check_team_repos_against_sonar.py --only-missing--only-missing excludes repositories that were marked as excluded.
JSON output:
python3 check_team_repos_against_sonar.py --format jsonStrict mode only accepts exact matches against Sonar project key:
python3 check_team_repos_against_sonar.py --strict-exactOverride any setting from the command line:
python3 check_team_repos_against_sonar.py \
--github-org your-org \
--github-team your-team-slug \
--github-repo-prefixes "analytics-,shared-" \
--github-repo-ignore-list "analytics-wrong-match" \
--github-repo-obsolete-list "analytics-sunset-service" \
--github-repo-no-productive-code-list "shared-docs-only" \
--github-repo-forked-libraries-list "analytics-forked-lib" \
--xlsx-output "outputs/sonar_status_report_20260421_113500.xlsx" \
--sonar-url "https://sonar.example.com" \
--sonar-token "$SONAR_TOKEN"By default the script tries these checks in order:
- If a repository has a root
pom.xml, the script reads it from GitHub and tries to derive a Maven-style Sonar key asgroupId:artifactId - If a repository has a root
package.json, the script reads it from GitHub and, for JavaScript matching, treats the repository folder name as the expected Sonar key and the packagenameas the expected Sonar name - Exact match against Sonar project key using the derived Maven key, or the JavaScript key/name pair
- Exact match against Sonar project key using deterministic repository-based fallbacks such as
full_name,name, and the prefix-stripped name likeanalytics-foo -> foo - For JavaScript repositories with a root
package.json, if the repository is still missing, the script inspectspackages/*/package.jsonand checks each subpackage withsubpackage folder -> Sonar keyandpackage.json name -> Sonar name. If every subpackage is present, the parent repository is marked as present andsonar_namecontains a comma-separated list of the matched submodules. - Normalized versions of the same candidates are used as a fallback, unless
--strict-exactis enabled
Outside the JavaScript key/name pair checks, the script does not use Sonar project name as a standalone match target.
If the normalized key lookup matches more than one Sonar project, the script reports the repository as ambiguous instead of guessing.
Before matching, the script filters GitHub repositories by name prefix. By default it includes only repositories whose names start with analytics- or shared-, and this can be changed with GITHUB_REPO_PREFIXES or --github-repo-prefixes.
After prefix filtering, repositories can be marked Excluded for one of these reasons:
ObsoleteNo Productive CodeForked Libraries
Repositories with neither a root pom.xml nor a root package.json automatically get the reason No Productive Code.
Repositories in GITHUB_REPO_IGNORE_LIST are not shown at all in the results table or summary.
Excluded repositories stay in the main results table, the present_in_sonar column shows Yes, Missing, or Excluded, and the reason column is filled when a repository is excluded.