{"id":51246942,"url":"https://github.com/ihassan8/badgeshield","last_synced_at":"2026-06-29T05:01:46.803Z","repository":{"id":351673948,"uuid":"1182203347","full_name":"ihassan8/badgeshield","owner":"ihassan8","description":"Python package for generating customizable SVG badges. It supports rectangular, circle, and framed-circle templates with 51 predefined colors, logo embedding, batch processing, and both a programmatic API and CLI.","archived":false,"fork":false,"pushed_at":"2026-05-30T04:07:07.000Z","size":3175,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-18T13:13:44.638Z","etag":null,"topics":["badges","desgin","gitlab","svg"],"latest_commit_sha":null,"homepage":"https://ihassan8.github.io/badgeshield/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ihassan8.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-15T07:19:46.000Z","updated_at":"2026-05-30T03:40:59.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ihassan8/badgeshield","commit_stats":null,"previous_names":["vertex-ai-automations/badgeshield","ihassan8/badgeshield"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/ihassan8/badgeshield","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ihassan8%2Fbadgeshield","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ihassan8%2Fbadgeshield/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ihassan8%2Fbadgeshield/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ihassan8%2Fbadgeshield/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ihassan8","download_url":"https://codeload.github.com/ihassan8/badgeshield/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ihassan8%2Fbadgeshield/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34913586,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-29T02:00:05.398Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["badges","desgin","gitlab","svg"],"created_at":"2026-06-29T05:01:45.800Z","updated_at":"2026-06-29T05:01:46.783Z","avatar_url":"https://github.com/ihassan8.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ca name=\"readme-top\"\u003e\u003c/a\u003e\n\n\u003cdiv align=\"center\"\u003e\n\u003cimg src=\"https://github.com/ihassan8/badgeshield/raw/main/docs/img/badgeshield.png\" alt=\"BadgeShield Logo\" width=\"400\"\u003e\n\n\u003cbr/\u003e\n\n[![PyPI version](https://img.shields.io/pypi/v/badgeshield?color=673ab7\u0026logo=pypi\u0026logoColor=white)](https://pypi.org/project/badgeshield/)\n[![Python versions](https://img.shields.io/pypi/pyversions/badgeshield?color=673ab7\u0026logo=python\u0026logoColor=white)](https://pypi.org/project/badgeshield/)\n[![License: MIT](https://img.shields.io/badge/license-MIT-673ab7.svg)](https://github.com/ihassan8/badgeshield/blob/main/LICENSE.txt)\n[![Downloads](https://img.shields.io/pypi/dm/badgeshield?color=673ab7)](https://pypi.org/project/badgeshield/)\n[![CI](https://img.shields.io/github/actions/workflow/status/ihassan8/badgeshield/ci.yml?branch=main\u0026label=CI\u0026logo=github)](https://github.com/ihassan8/badgeshield/actions/workflows/ci.yml)\n[![Docs](https://img.shields.io/badge/docs-online-673ab7?logo=readthedocs\u0026logoColor=white)](https://ihassan8.github.io/badgeshield)\n\n\u003cbr/\u003e\n\n\u003cp\u003e\n\u003ca href=\"https://ihassan8.github.io/badgeshield\"\u003e\u003cstrong\u003e📃 Documentation\u003c/strong\u003e\u003c/a\u003e\n\u0026nbsp;·\u0026nbsp;\n\u003ca href=\"https://github.com/ihassan8/badgeshield/issues/new\"\u003e🔧 Report Bug\u003c/a\u003e\n\u003c/p\u003e\n\n\u003c/div\u003e\n\n---\n\n## Why badgeshield instead of shields.io?\n\nshields.io is great — but it makes an HTTP call to an external server on every CI run.\n\n**badgeshield generates badges entirely offline:**\n\n- **No network calls** — works in air-gapped CI, behind corporate proxies, and offline laptops\n- **No rate limits** — generate thousands of badges in a single run\n- **No data sent externally** — your version numbers, branch names, and repo stats stay local\n- **Reproducible** — same inputs always produce the same SVG, no caching surprises\n\n```bash\n# Generate every standard badge for your Python project in one command\nbadgeshield preset --all --output_path ./badges/ --format markdown\n```\n\nDrop the output straight into your README. No account needed, no tokens, no network.\n\n---\n\n## 📋 Table of Contents\n\n- [Why badgeshield?](#why-badgeshield-instead-of-shieldsio)\n- [Overview](#-overview)\n- [Features](#-features)\n- [Badge Showcase](#-badge-showcase)\n- [Installation](#-installation)\n- [Quick Start](#-quick-start)\n- [Coverage Badge](#-coverage-badge)\n- [CLI Usage](#%EF%B8%8F-cli-usage)\n- [Batch Generation](#-batch-generation)\n- [Contributing](#-contributing)\n\n---\n\n## 📣 Overview\n\n**BadgeShield** generates customizable SVG badges for GitLab, GitHub, and anywhere you can embed SVG. Five badge templates, four visual styles, 51 built-in colors, Pillow-powered font metrics, logo embedding with color tinting, automatic coverage badges from `coverage.xml`, and a Typer CLI with Rich progress bars and an SVG audit subcommand.\n\n---\n\n## 💡 Features\n\n- **5 templates** — `DEFAULT` (two-part rectangular), `PILL` (fully rounded), `CIRCLE`, `CIRCLE_FRAME` with 11 PNG overlay frames, and `BANNER` (icon-zone + text).\n- **4 visual styles** — `FLAT`, `ROUNDED`, `GRADIENT`, and `SHADOWED` via `BadgeStyle` enum or `--style` CLI flag.\n- **51 built-in colors** — `BadgeColor` enum or any `#RRGGBB` hex string.\n- **Accurate text sizing** — font widths measured via Pillow (DejaVuSans) with a fallback estimator when Pillow is absent.\n- **Logo support** — embed PNG/JPEG logos with optional color tinting.\n- **Coverage badge** — read `coverage.xml` and auto-generate a correctly-colored badge in one command.\n- **Concurrent batch** — generate hundreds of badges in parallel from a JSON config; per-entry `style` overrides the CLI flag.\n- **Modern CLI** — Typer + Rich: progress bar, error panels, summary table, and `audit` subcommand.\n- **Python API** — import and generate from any script or CI job.\n\n---\n\n## 🏅 Badge Showcase\n\nThese badges are generated by badgeshield itself — no shields.io, no network calls.\n\n### Project badges\n\n| Badge | Preset |\n|---|---|\n| ![version](https://raw.githubusercontent.com/ihassan8/badgeshield/main/docs/badges/version.svg) | `badgeshield preset version` |\n| ![python](https://raw.githubusercontent.com/ihassan8/badgeshield/main/docs/badges/python.svg) | `badgeshield preset python` |\n| ![branch](https://raw.githubusercontent.com/ihassan8/badgeshield/main/docs/badges/branch.svg) | `badgeshield preset branch` |\n| ![ruff](https://raw.githubusercontent.com/ihassan8/badgeshield/main/docs/badges/ruff.svg) | `badgeshield preset ruff` |\n| ![mypy](https://raw.githubusercontent.com/ihassan8/badgeshield/main/docs/badges/mypy.svg) | `badgeshield preset mypy` |\n| ![maintained](https://raw.githubusercontent.com/ihassan8/badgeshield/main/docs/badges/maintained.svg) | `badgeshield preset maintained` |\n| ![library](https://raw.githubusercontent.com/ihassan8/badgeshield/main/docs/badges/library.svg) | `badgeshield preset library` |\n| ![cross-platform](https://raw.githubusercontent.com/ihassan8/badgeshield/main/docs/badges/cross-platform.svg) | `badgeshield preset cross-platform` |\n\n### Templates\n\n| Template | Preview |\n|---|---|\n| `DEFAULT` | ![default](https://raw.githubusercontent.com/ihassan8/badgeshield/main/docs/badges/template-default.svg) |\n| `PILL` | ![pill](https://raw.githubusercontent.com/ihassan8/badgeshield/main/docs/badges/template-pill.svg) |\n| `CIRCLE` | ![circle](https://raw.githubusercontent.com/ihassan8/badgeshield/main/docs/badges/template-circle.svg) |\n| `BANNER` | ![banner](https://raw.githubusercontent.com/ihassan8/badgeshield/main/docs/badges/template-banner.svg) |\n\n### Styles (DEFAULT template)\n\n| Style | Preview |\n|---|---|\n| `FLAT` | ![flat](https://raw.githubusercontent.com/ihassan8/badgeshield/main/docs/badges/showcase-flat.svg) |\n| `ROUNDED` | ![rounded](https://raw.githubusercontent.com/ihassan8/badgeshield/main/docs/badges/showcase-rounded.svg) |\n| `GRADIENT` | ![gradient](https://raw.githubusercontent.com/ihassan8/badgeshield/main/docs/badges/showcase-gradient.svg) |\n| `SHADOWED` | ![shadowed](https://raw.githubusercontent.com/ihassan8/badgeshield/main/docs/badges/showcase-shadowed.svg) |\n\n---\n\n## 📌 Installation\n\n```bash\npip install badgeshield\n```\n\nWith logo tinting support (requires Pillow):\n\n```bash\npip install \"badgeshield[image]\"\n```\n\nUpgrade:\n\n```bash\npip install --upgrade badgeshield\n```\n\n---\n\n## 🚀 Quick Start\n\n### Python API — DEFAULT template\n\n```python\nfrom badgeshield import BadgeGenerator, BadgeStyle, BadgeTemplate\n\ngenerator = BadgeGenerator(template=BadgeTemplate.DEFAULT, style=BadgeStyle.GRADIENT)\ngenerator.generate_badge(\n    left_text=\"build\",\n    left_color=\"#555555\",\n    right_text=\"passing\",\n    right_color=\"#44cc11\",\n    badge_name=\"build.svg\",\n    output_path=\"./badges\",\n)\n```\n\n`style` is set at generator construction time and applies to all badges that instance generates. Options: `FLAT` (default), `ROUNDED`, `GRADIENT`, `SHADOWED`.\n\n### PILL template\n\n```python\nfrom badgeshield import BadgeGenerator, BadgeTemplate\n\ngenerator = BadgeGenerator(template=BadgeTemplate.PILL)\ngenerator.generate_badge(\n    left_text=\"build\",\n    left_color=\"#555555\",\n    right_text=\"passing\",\n    right_color=\"#44cc11\",\n    badge_name=\"build-pill.svg\",\n)\n```\n\n### CIRCLE template\n\n```python\nfrom badgeshield import BadgeGenerator, BadgeTemplate\n\ngenerator = BadgeGenerator(template=BadgeTemplate.CIRCLE)\ngenerator.generate_badge(\n    left_text=\"v2.1\",\n    left_color=\"#673ab7\",\n    badge_name=\"version.svg\",\n)\n```\n\n### CIRCLE_FRAME template\n\n```python\nfrom badgeshield import BadgeGenerator, BadgeTemplate, FrameType\n\ngenerator = BadgeGenerator(template=BadgeTemplate.CIRCLE_FRAME)\ngenerator.generate_badge(\n    left_text=\"MH\",\n    left_color=\"#FF0000\",\n    badge_name=\"initials.svg\",\n    frame=FrameType.FRAME1,\n    logo=\"path/to/avatar.png\",\n    logo_tint=\"#ffffff\",\n)\n```\n\n### BANNER template\n\n```python\nfrom badgeshield import BadgeGenerator, BadgeTemplate\n\ngenerator = BadgeGenerator(template=BadgeTemplate.BANNER)\ngenerator.generate_badge(\n    left_text=\"badgeshield\",\n    left_color=\"#1a1a2e\",\n    right_text=\"v1.0\",\n    right_color=\"#16213e\",\n    badge_name=\"banner.svg\",\n)\n```\n\n---\n\n## 📊 Coverage Badge\n\nGenerate a correctly-colored badge directly from a `coverage.xml` report — no manual color selection needed.\n\n### CLI\n\n```bash\nbadgeshield coverage coverage.xml \\\n  --badge-name coverage.svg \\\n  --output-path ./badges\n```\n\nThe color is chosen automatically based on these thresholds:\n\n| Coverage | Color |\n|----------|-------|\n| ≥ 90% | ![#44cc11](https://img.shields.io/badge/-44cc11-44cc11) green |\n| ≥ 80% | ![#97ca00](https://img.shields.io/badge/-97ca00-97ca00) yellow-green |\n| ≥ 70% | ![#a4a61d](https://img.shields.io/badge/-a4a61d-a4a61d) yellow |\n| ≥ 60% | ![#dfb317](https://img.shields.io/badge/-dfb317-dfb317) orange |\n| \u003c 60%  | ![#e05d44](https://img.shields.io/badge/-e05d44-e05d44) red |\n\nUse `--metric branch` to badge on branch coverage instead of line coverage.\n\n### Python API\n\n```python\nfrom badgeshield import parse_coverage_xml, coverage_color\nfrom badgeshield import BadgeGenerator, BadgeTemplate\n\npct = parse_coverage_xml(\"coverage.xml\")          # e.g. 94.3\ncolor = coverage_color(pct)                        # \"#44cc11\"\n\ngen = BadgeGenerator(template=BadgeTemplate.DEFAULT)\ngen.generate_badge(\n    left_text=\"coverage\",\n    left_color=\"#555555\",\n    right_text=f\"{pct:.0f}%\",\n    right_color=color,\n    badge_name=\"coverage.svg\",\n    output_path=\"./badges\",\n)\n```\n\n---\n\n## 🖥️ CLI Usage\n\n### Coverage badge\n\n```bash\nbadgeshield coverage coverage.xml --badge-name coverage.svg --output-path ./badges\n```\n\nUse `--metric branch` for branch coverage, `--left-text` to change the label.\n\n### Single badge\n\n```bash\nbadgeshield single \\\n  --left-text \"coverage\" \\\n  --left-color \"#555555\" \\\n  --right-text \"94%\" \\\n  --right-color \"#44cc11\" \\\n  --style gradient \\\n  --badge-name coverage.svg \\\n  --output-path ./badges\n```\n\n`--style` accepts `flat` (default), `rounded`, `gradient`, or `shadowed` (case-insensitive).\n\nWith a logo and links:\n\n```bash\nbadgeshield single \\\n  --left-text \"build\" \\\n  --left-color \"DARK_GREEN\" \\\n  --right-text \"passing\" \\\n  --right-color \"#44cc11\" \\\n  --logo path/to/logo.png \\\n  --logo-tint \"#ffffff\" \\\n  --left-link \"https://example.com/pipeline\" \\\n  --badge-name build.svg\n```\n\nFramed circle:\n\n```bash\nbadgeshield single \\\n  --left-text \"MH\" \\\n  --left-color \"#673ab7\" \\\n  --template CIRCLE_FRAME \\\n  --frame FRAME1 \\\n  --badge-name initials.svg\n```\n\n### SVG audit\n\nVerify that a generated SVG contains no external resource references:\n\n```bash\nbadgeshield audit badges/build.svg          # exits 0 if clean, 1 if violations found\nbadgeshield audit badges/build.svg --json   # machine-readable JSON output\n```\n\n---\n\n## ⚡ Batch Generation\n\n### CLI\n\n```bash\nbadgeshield batch badges.json --output-path ./badges --max-workers 8\n```\n\n### JSON config (`badges.json`)\n\n```json\n[\n  {\n    \"badge_name\": \"build.svg\",\n    \"left_text\": \"build\",\n    \"left_color\": \"GREEN\"\n  },\n  {\n    \"badge_name\": \"coverage.svg\",\n    \"left_text\": \"coverage\",\n    \"left_color\": \"#555555\",\n    \"right_text\": \"94%\",\n    \"right_color\": \"#44cc11\",\n    \"style\": \"gradient\"\n  },\n  {\n    \"badge_name\": \"version.svg\",\n    \"left_text\": \"v2.1.0\",\n    \"left_color\": \"#673ab7\"\n  }\n]\n```\n\nA per-entry `\"style\"` key overrides the CLI `--style` flag for that badge.\n\nAfter the run, a Rich summary table shows which badges succeeded or failed.\n\n### Python API\n\n```python\nfrom badgeshield import BadgeBatchGenerator, BadgeStyle, BadgeTemplate\n\nbatch = BadgeBatchGenerator(max_workers=4)\nbadges = [\n    {\"badge_name\": \"build.svg\",    \"left_text\": \"build\",    \"left_color\": \"GREEN\", \"output_path\": \"./out\", \"template\": BadgeTemplate.DEFAULT, \"style\": BadgeStyle.FLAT},\n    {\"badge_name\": \"coverage.svg\", \"left_text\": \"coverage\", \"left_color\": \"#555\",  \"right_text\": \"94%\", \"right_color\": \"#44cc11\", \"output_path\": \"./out\", \"template\": BadgeTemplate.DEFAULT, \"style\": BadgeStyle.GRADIENT},\n]\n\ntry:\n    batch.generate_batch(badges, progress_callback=lambda name: print(f\"✓ {name}\"))\nexcept RuntimeError:\n    for badge_name, error in batch._failures:\n        print(f\"✗ {badge_name}: {error}\")\n```\n\n---\n\n## CI Pipeline\n\nEvery push to `main` and every pull request runs automatically via [shared-workflows](https://github.com/ihassan8/shared-workflows):\n\n| Job | What it checks |\n|-----|----------------|\n| **Test** | pytest on Python 3.9–3.12 x Ubuntu + Windows |\n| **Lint** | `ruff check` + `ruff format --check` |\n| **Type Check** | `mypy src/` |\n| **Audit** | `pip-audit` — all dependencies scanned for known CVEs |\n| **Coverage** | `pytest-cov` — report posted to the Actions job summary |\n## 👪 Contributing\n\nAll contributions are welcome. Fork the repo, make your changes, and open a pull request. You can also open an issue with the label `enhancement`.\n\nDon't forget to ⭐ star the project!\n\n🔶 [View all contributors](https://github.com/ihassan8/badgeshield/graphs/contributors)\n\n---\n\n📃 [Full Docs](https://ihassan8.github.io/badgeshield) \u0026nbsp;·\u0026nbsp; 🔧 [Report a Bug](https://github.com/ihassan8/badgeshield/issues/new)\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fihassan8%2Fbadgeshield","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fihassan8%2Fbadgeshield","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fihassan8%2Fbadgeshield/lists"}