Skip to content

vamsi876/gitbar

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gitbar

Multi-repo Git dashboard in your macOS menubar

Monitor PRs, issues, CI failures, and local repo health — all at a glance.

PyPI Python macOS License


What You Get

┌──────────────────────────────────────────┐
│  GP  2❗ • 1✖ • 5                        │  ← menubar with live counts
└──────────────────────────────────────────┘

┌──────────────────────────────────────────┐
│  GitPulse                                │
│──────────────────────────────────────────│
│  👀  NEEDS YOUR REVIEW  (2)             │
│    ✅  #142  Fix auth timeout  — api     │
│    ⏳  #138  Add rate limiting — core    │
│──────────────────────────────────────────│
│  🔁  OPEN PULL REQUESTS  (5)            │
│    ✅  #201  Upgrade deps  — frontend    │
│    ❌  #199  New dashboard — backend     │
│    •   #195  Update README — docs        │
│──────────────────────────────────────────│
│  📋  MY ISSUES  (3)                     │
│    #89  Fix login redirect • bug — app   │
│    #72  Add dark mode • feature — ui     │
│──────────────────────────────────────────│
│  ❌  CI FAILURES  (1)                   │
│    ●  deploy  →  main — backend          │
│──────────────────────────────────────────│
│  💻  LOCAL REPOS                         │
│    myapp      [main]    ● modified • ↑2  │
│    backend    [dev]     ✓ clean          │
│──────────────────────────────────────────│
│  🔓  ACCOUNTS                            │
│    ✅  GitHub connected                  │
│    Connect GitLab...                     │
│    Connect Bitbucket...                  │
│──────────────────────────────────────────│
│  Updated 45s ago                         │
│  ↻  Refresh Now                     ⌘R  │
│  ⚙  Open Config                     ⌘,  │
│  Quit GitPulse                       ⌘Q  │
└──────────────────────────────────────────┘

Quick Start

# 1. Install
pip install gitbar

# 2. Launch
gitbar

# 3. Connect (click GP in menubar → Connect GitHub...)

That's it. GitBar auto-detects your gh CLI login or walks you through a token setup. Your repos are discovered automatically.


Features

Feature Description
Pull Requests See all open PRs across every repo, with CI status indicators
Review Requests PRs waiting for your review, highlighted at the top
Issues Issues assigned to you across all repos
CI Failures Failed GitHub Actions / GitLab pipelines at a glance
Local Repos Dirty files, ahead/behind counts, current branch
Click to Open Click any PR, issue, or CI run to open it in your browser
Notifications Native macOS alerts for new PRs, review requests, CI failures
Multi-Provider GitHub + GitLab + Bitbucket in one view
Secure Tokens stored in macOS Keychain, never in plain text
Keyboard Shortcuts R refresh, , config, Q quit

Architecture

graph TB
    subgraph Menubar["macOS Menubar (PyObjC)"]
        SI["Status Item: GP"]
        Menu["NSMenu + NSMenuDelegate"]
    end

    subgraph Polling["Background Polling"]
        Timer["NSTimer (configurable interval)"]
        Pool["ThreadPoolExecutor (3 workers)"]
    end

    subgraph Providers["API Providers"]
        GH["GitHub REST API v3"]
        GL["GitLab REST API v4"]
        BB["Bitbucket REST API v2"]
    end

    subgraph Data["Data Collected Per Poll"]
        PRs["Open PRs + CI Status"]
        Issues["Assigned Issues"]
        CI["Failed CI Runs"]
        Activity["Recent Activity"]
    end

    subgraph Local["Local Git"]
        Checker["LocalRepoChecker"]
        Git["git subprocess calls"]
    end

    subgraph Storage["Persistence"]
        Config["~/.gitpulse/config.yaml"]
        State["~/.gitpulse/state.json"]
        Keychain["macOS Keychain"]
    end

    subgraph Notify["Notifications"]
        Notifier["Notifier (dedup via StateStore)"]
        macOS["macOS Notification Center"]
    end

    SI --> Menu
    Timer --> Pool
    Pool --> GH & GL & BB
    GH & GL & BB --> PRs & Issues & CI & Activity
    Timer --> Checker
    Checker --> Git
    PRs & Issues & CI & Activity --> Menu
    Activity --> Notifier --> macOS
    Config --> Providers
    Keychain --> Providers
    Notifier --> State
Loading

Connection Flow

flowchart TD
    A["Click 'Connect GitHub...'"] --> B{gh CLI token cached?}
    B -->|Yes| C["Show: 'Found gh CLI as username.\nUse this account?'"]
    C -->|Yes, Connect| D["Background thread"]
    C -->|Enter Token Manually| E
    B -->|No| E["Show PAT dialog"]
    E --> F["Open github.com/settings/tokens"]
    F --> G["User pastes token"]
    G --> D
    D --> H["Validate token via API"]
    H -->|Invalid| I["Notification: Invalid token"]
    H -->|Valid| J["Discover all user repos"]
    J --> K["Store token in macOS Keychain"]
    K --> L["Save repos to config.yaml"]
    L --> M["Start polling"]
    M --> N["Menu shows: GitHub ✅"]

    style A fill:#4a9eff,color:#fff
    style N fill:#22c55e,color:#fff
    style I fill:#ef4444,color:#fff
Loading

Polling Pipeline

sequenceDiagram
    participant T as NSTimer
    participant P as ThreadPool
    participant GH as GitHub API
    participant LC as LocalRepoChecker
    participant S as StateStore
    participant M as Menu
    participant N as Notifier

    T->>P: poll_once()
    par For each provider
        P->>GH: fetch_open_prs()
        P->>GH: fetch_assigned_issues()
        P->>GH: fetch_ci_runs()
        P->>GH: fetch_recent_activity()
    end
    T->>LC: check_all()
    LC-->>T: LocalRepoStatus[]

    GH-->>P: PollResult (PRs, Issues, CI, Activity)
    P->>S: mark_seen(activity)
    P->>N: maybe_notify(new_pr)
    N-->>N: macOS notification (if new)

    Note over M: User clicks GP icon
    M->>M: menuNeedsUpdate_()
    M->>M: Build sections from cached data
Loading

Supported Providers

Feature GitHub GitLab Bitbucket
Open Pull Requests
Review Requests
CI/CD Status ✅ Actions ✅ Pipelines
Assigned Issues
Failed CI Runs
Repo Discovery
Wildcard Repos (org/*)
Keychain Storage
gh CLI Auto-detect
Enterprise / Self-hosted

Configuration

Config is auto-created at ~/.gitpulse/config.yaml when you connect an account. You can also edit it manually:

# How often to poll APIs (seconds, minimum 60)
poll_interval: 300

# Play sound with notifications
notification_sound: true

# Git providers (auto-managed via Connect flow)
providers:
  github:
    token: keychain              # "keychain" = stored in macOS Keychain
    # api_url: https://github.example.com/api/v3   # GitHub Enterprise
    repos:
      - owner/repo1
      - owner/repo2
      - org-name/*               # wildcard: all repos in an org

  gitlab:
    token: keychain
    # api_url: https://gitlab.example.com           # self-hosted
    repos:
      - group/project1
      - group/*

  bitbucket:
    token: keychain
    username: your_username      # required for Bitbucket
    repos:
      - workspace/repo1
      - workspace/*

# Local git repos to monitor
local_repos:
  - ~/code/project-a
  - ~/code/project-b

# Toggle individual notification types
notify:
  new_pr: true
  review_requested: true
  ci_failure: true
  pr_merged: true

How It Works

┌─────────────────────────────────────────────────────────┐
│                    macOS Menubar                         │
│                                                         │
│  PyObjC NSStatusBar → NSMenu with NSMenuDelegate        │
│  Menu rebuilds dynamically every time you click GP      │
│  No timer-based menu updates (avoids macOS UI bugs)     │
└──────────────┬──────────────────────────┬───────────────┘
               │                          │
     ┌─────────▼─────────┐    ┌──────────▼──────────┐
     │  Background Poll   │    │  Local Git Check    │
     │                    │    │                     │
     │  NSTimer fires     │    │  subprocess.run()   │
     │  every N seconds   │    │  git status/log     │
     │  ThreadPoolExec    │    │  per configured     │
     │  (3 workers max)   │    │  repo path          │
     └─────────┬──────────┘    └──────────┬──────────┘
               │                          │
     ┌─────────▼──────────────────────────▼───────────┐
     │              Shared State (thread-safe)         │
     │                                                 │
     │  _current_prs[]    _current_issues[]           │
     │  _current_ci_runs[]  _local_statuses[]         │
     │  Protected by threading.Lock()                  │
     └─────────┬──────────────────────────┬───────────┘
               │                          │
     ┌─────────▼─────────┐    ┌──────────▼──────────┐
     │  Notifier          │    │  StateStore         │
     │  Dedup via seen IDs│    │  JSON persistence   │
     │  macOS native      │    │  LRU (5000 max)     │
     │  notifications     │    │  Debounced flush    │
     └───────────────────┘    └─────────────────────┘

Key design decisions:

  • PyObjC instead of rumps — rumps has compatibility issues on macOS 26+. Native PyObjC gives full control.
  • NSMenuDelegate pattern — Menu content rebuilds on every open (menuNeedsUpdate_), so it's always fresh without timer-based UI updates.
  • All dialogs in main thread — NSAlert/NSTextField only from menu action callbacks, never from timers or background threads.
  • Background work via threading — API calls and git checks run in daemon threads; only notify() is called from background (via osascript, which is thread-safe).
  • macOS Keychain for tokens — Uses the security CLI tool. Config stores token: keychain as a sentinel.

Development

# Clone
git clone https://github.com/vamsi876/gitbar.git
cd gitbar

# Install in dev mode
pip install -e .

# Run
gitbar
# or
python run.py

Project Structure

gitbar/
├── gitpulse/                  # main package
│   ├── app.py                 # PyObjC menubar app + menu building
│   ├── auth.py                # GitHub/GitLab/Bitbucket auth + keychain
│   ├── config.py              # YAML config loader/saver
│   ├── models.py              # Dataclasses: PullRequest, Issue, CIRun, etc.
│   ├── ui.py                  # Native macOS dialogs (NSAlert, notifications)
│   ├── poller.py              # Concurrent polling scheduler
│   ├── notifier.py            # Notification dedup + delivery
│   ├── state.py               # Persistent state (seen events, last poll)
│   ├── localrepo.py           # Local git repo status checker
│   └── providers/
│       ├── base.py            # Abstract provider with rate-limit handling
│       ├── github.py          # GitHub REST API v3
│       ├── gitlab.py          # GitLab REST API v4
│       └── bitbucket.py       # Bitbucket REST API v2
├── run.py                     # Dev entry point
├── config.example.yaml        # Config template
├── pyproject.toml             # Package config (PyPI name: gitbar)
├── requirements.txt
├── LICENSE
└── README.md

Requirements

  • macOS 13+ (Ventura or later)
  • Python 3.10+

License

MIT — see LICENSE

About

macOS menubar Git dashboard aggregating PRs, issues & CI/CD across GitHub, GitLab, Bitbucket — published on PyPI

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages