gitbar 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,408 @@
1
+ Metadata-Version: 2.4
2
+ Name: gitbar
3
+ Version: 0.1.0
4
+ Summary: Multi-repo Git dashboard in your macOS menubar — PRs, issues, CI status, and local repo health at a glance.
5
+ Author: Vamsi Krishna Kollipara
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/vamsi876/gitbar
8
+ Project-URL: Issues, https://github.com/vamsi876/gitbar/issues
9
+ Keywords: git,github,gitlab,bitbucket,menubar,macos,dashboard,pull-request
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: MacOS X
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: MacOS
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Software Development :: Version Control :: Git
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: requests>=2.31.0
24
+ Requires-Dist: pyyaml>=6.0
25
+ Requires-Dist: pyobjc-framework-Cocoa>=10.0
26
+ Dynamic: license-file
27
+
28
+ <p align="center">
29
+ <h1 align="center">gitbar</h1>
30
+ <p align="center">
31
+ <strong>Multi-repo Git dashboard in your macOS menubar</strong>
32
+ </p>
33
+ <p align="center">
34
+ Monitor PRs, issues, CI failures, and local repo health — all at a glance.
35
+ </p>
36
+ <p align="center">
37
+ <a href="https://pypi.org/project/gitbar/"><img src="https://img.shields.io/pypi/v/gitbar?color=blue" alt="PyPI"></a>
38
+ <a href="https://pypi.org/project/gitbar/"><img src="https://img.shields.io/pypi/pyversions/gitbar" alt="Python"></a>
39
+ <img src="https://img.shields.io/badge/platform-macOS-lightgrey" alt="macOS">
40
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green" alt="License"></a>
41
+ </p>
42
+ </p>
43
+
44
+ ---
45
+
46
+ ## What You Get
47
+
48
+ ```
49
+ ┌──────────────────────────────────────────┐
50
+ │ GP 2❗ • 1✖ • 5 │ ← menubar with live counts
51
+ └──────────────────────────────────────────┘
52
+
53
+ ┌──────────────────────────────────────────┐
54
+ │ GitPulse │
55
+ │──────────────────────────────────────────│
56
+ │ 👀 NEEDS YOUR REVIEW (2) │
57
+ │ ✅ #142 Fix auth timeout — api │
58
+ │ ⏳ #138 Add rate limiting — core │
59
+ │──────────────────────────────────────────│
60
+ │ 🔁 OPEN PULL REQUESTS (5) │
61
+ │ ✅ #201 Upgrade deps — frontend │
62
+ │ ❌ #199 New dashboard — backend │
63
+ │ • #195 Update README — docs │
64
+ │──────────────────────────────────────────│
65
+ │ 📋 MY ISSUES (3) │
66
+ │ #89 Fix login redirect • bug — app │
67
+ │ #72 Add dark mode • feature — ui │
68
+ │──────────────────────────────────────────│
69
+ │ ❌ CI FAILURES (1) │
70
+ │ ● deploy → main — backend │
71
+ │──────────────────────────────────────────│
72
+ │ 💻 LOCAL REPOS │
73
+ │ myapp [main] ● modified • ↑2 │
74
+ │ backend [dev] ✓ clean │
75
+ │──────────────────────────────────────────│
76
+ │ 🔓 ACCOUNTS │
77
+ │ ✅ GitHub connected │
78
+ │ Connect GitLab... │
79
+ │ Connect Bitbucket... │
80
+ │──────────────────────────────────────────│
81
+ │ Updated 45s ago │
82
+ │ ↻ Refresh Now ⌘R │
83
+ │ ⚙ Open Config ⌘, │
84
+ │ Quit GitPulse ⌘Q │
85
+ └──────────────────────────────────────────┘
86
+ ```
87
+
88
+ ---
89
+
90
+ ## Quick Start
91
+
92
+ ```bash
93
+ # 1. Install
94
+ pip install gitbar
95
+
96
+ # 2. Launch
97
+ gitbar
98
+
99
+ # 3. Connect (click GP in menubar → Connect GitHub...)
100
+ ```
101
+
102
+ That's it. GitBar auto-detects your `gh` CLI login or walks you through a token setup. Your repos are discovered automatically.
103
+
104
+ ---
105
+
106
+ ## Features
107
+
108
+ | Feature | Description |
109
+ |---------|-------------|
110
+ | **Pull Requests** | See all open PRs across every repo, with CI status indicators |
111
+ | **Review Requests** | PRs waiting for *your* review, highlighted at the top |
112
+ | **Issues** | Issues assigned to you across all repos |
113
+ | **CI Failures** | Failed GitHub Actions / GitLab pipelines at a glance |
114
+ | **Local Repos** | Dirty files, ahead/behind counts, current branch |
115
+ | **Click to Open** | Click any PR, issue, or CI run to open it in your browser |
116
+ | **Notifications** | Native macOS alerts for new PRs, review requests, CI failures |
117
+ | **Multi-Provider** | GitHub + GitLab + Bitbucket in one view |
118
+ | **Secure** | Tokens stored in macOS Keychain, never in plain text |
119
+ | **Keyboard Shortcuts** | `R` refresh, `,` config, `Q` quit |
120
+
121
+ ---
122
+
123
+ ## Architecture
124
+
125
+ ```mermaid
126
+ graph TB
127
+ subgraph Menubar["macOS Menubar (PyObjC)"]
128
+ SI["Status Item: GP"]
129
+ Menu["NSMenu + NSMenuDelegate"]
130
+ end
131
+
132
+ subgraph Polling["Background Polling"]
133
+ Timer["NSTimer (configurable interval)"]
134
+ Pool["ThreadPoolExecutor (3 workers)"]
135
+ end
136
+
137
+ subgraph Providers["API Providers"]
138
+ GH["GitHub REST API v3"]
139
+ GL["GitLab REST API v4"]
140
+ BB["Bitbucket REST API v2"]
141
+ end
142
+
143
+ subgraph Data["Data Collected Per Poll"]
144
+ PRs["Open PRs + CI Status"]
145
+ Issues["Assigned Issues"]
146
+ CI["Failed CI Runs"]
147
+ Activity["Recent Activity"]
148
+ end
149
+
150
+ subgraph Local["Local Git"]
151
+ Checker["LocalRepoChecker"]
152
+ Git["git subprocess calls"]
153
+ end
154
+
155
+ subgraph Storage["Persistence"]
156
+ Config["~/.gitpulse/config.yaml"]
157
+ State["~/.gitpulse/state.json"]
158
+ Keychain["macOS Keychain"]
159
+ end
160
+
161
+ subgraph Notify["Notifications"]
162
+ Notifier["Notifier (dedup via StateStore)"]
163
+ macOS["macOS Notification Center"]
164
+ end
165
+
166
+ SI --> Menu
167
+ Timer --> Pool
168
+ Pool --> GH & GL & BB
169
+ GH & GL & BB --> PRs & Issues & CI & Activity
170
+ Timer --> Checker
171
+ Checker --> Git
172
+ PRs & Issues & CI & Activity --> Menu
173
+ Activity --> Notifier --> macOS
174
+ Config --> Providers
175
+ Keychain --> Providers
176
+ Notifier --> State
177
+ ```
178
+
179
+ ---
180
+
181
+ ## Connection Flow
182
+
183
+ ```mermaid
184
+ flowchart TD
185
+ A["Click 'Connect GitHub...'"] --> B{gh CLI token cached?}
186
+ B -->|Yes| C["Show: 'Found gh CLI as username.\nUse this account?'"]
187
+ C -->|Yes, Connect| D["Background thread"]
188
+ C -->|Enter Token Manually| E
189
+ B -->|No| E["Show PAT dialog"]
190
+ E --> F["Open github.com/settings/tokens"]
191
+ F --> G["User pastes token"]
192
+ G --> D
193
+ D --> H["Validate token via API"]
194
+ H -->|Invalid| I["Notification: Invalid token"]
195
+ H -->|Valid| J["Discover all user repos"]
196
+ J --> K["Store token in macOS Keychain"]
197
+ K --> L["Save repos to config.yaml"]
198
+ L --> M["Start polling"]
199
+ M --> N["Menu shows: GitHub ✅"]
200
+
201
+ style A fill:#4a9eff,color:#fff
202
+ style N fill:#22c55e,color:#fff
203
+ style I fill:#ef4444,color:#fff
204
+ ```
205
+
206
+ ---
207
+
208
+ ## Polling Pipeline
209
+
210
+ ```mermaid
211
+ sequenceDiagram
212
+ participant T as NSTimer
213
+ participant P as ThreadPool
214
+ participant GH as GitHub API
215
+ participant LC as LocalRepoChecker
216
+ participant S as StateStore
217
+ participant M as Menu
218
+ participant N as Notifier
219
+
220
+ T->>P: poll_once()
221
+ par For each provider
222
+ P->>GH: fetch_open_prs()
223
+ P->>GH: fetch_assigned_issues()
224
+ P->>GH: fetch_ci_runs()
225
+ P->>GH: fetch_recent_activity()
226
+ end
227
+ T->>LC: check_all()
228
+ LC-->>T: LocalRepoStatus[]
229
+
230
+ GH-->>P: PollResult (PRs, Issues, CI, Activity)
231
+ P->>S: mark_seen(activity)
232
+ P->>N: maybe_notify(new_pr)
233
+ N-->>N: macOS notification (if new)
234
+
235
+ Note over M: User clicks GP icon
236
+ M->>M: menuNeedsUpdate_()
237
+ M->>M: Build sections from cached data
238
+ ```
239
+
240
+ ---
241
+
242
+ ## Supported Providers
243
+
244
+ | Feature | GitHub | GitLab | Bitbucket |
245
+ |---------|:------:|:------:|:---------:|
246
+ | Open Pull Requests | ✅ | ✅ | ✅ |
247
+ | Review Requests | ✅ | ✅ | ✅ |
248
+ | CI/CD Status | ✅ Actions | ✅ Pipelines | — |
249
+ | Assigned Issues | ✅ | — | — |
250
+ | Failed CI Runs | ✅ | — | — |
251
+ | Repo Discovery | ✅ | ✅ | ✅ |
252
+ | Wildcard Repos (`org/*`) | ✅ | ✅ | ✅ |
253
+ | Keychain Storage | ✅ | ✅ | ✅ |
254
+ | `gh` CLI Auto-detect | ✅ | — | — |
255
+ | Enterprise / Self-hosted | ✅ | ✅ | — |
256
+
257
+ ---
258
+
259
+ ## Configuration
260
+
261
+ Config is auto-created at `~/.gitpulse/config.yaml` when you connect an account. You can also edit it manually:
262
+
263
+ ```yaml
264
+ # How often to poll APIs (seconds, minimum 60)
265
+ poll_interval: 300
266
+
267
+ # Play sound with notifications
268
+ notification_sound: true
269
+
270
+ # Git providers (auto-managed via Connect flow)
271
+ providers:
272
+ github:
273
+ token: keychain # "keychain" = stored in macOS Keychain
274
+ # api_url: https://github.example.com/api/v3 # GitHub Enterprise
275
+ repos:
276
+ - owner/repo1
277
+ - owner/repo2
278
+ - org-name/* # wildcard: all repos in an org
279
+
280
+ gitlab:
281
+ token: keychain
282
+ # api_url: https://gitlab.example.com # self-hosted
283
+ repos:
284
+ - group/project1
285
+ - group/*
286
+
287
+ bitbucket:
288
+ token: keychain
289
+ username: your_username # required for Bitbucket
290
+ repos:
291
+ - workspace/repo1
292
+ - workspace/*
293
+
294
+ # Local git repos to monitor
295
+ local_repos:
296
+ - ~/code/project-a
297
+ - ~/code/project-b
298
+
299
+ # Toggle individual notification types
300
+ notify:
301
+ new_pr: true
302
+ review_requested: true
303
+ ci_failure: true
304
+ pr_merged: true
305
+ ```
306
+
307
+ ---
308
+
309
+ ## How It Works
310
+
311
+ ```
312
+ ┌─────────────────────────────────────────────────────────┐
313
+ │ macOS Menubar │
314
+ │ │
315
+ │ PyObjC NSStatusBar → NSMenu with NSMenuDelegate │
316
+ │ Menu rebuilds dynamically every time you click GP │
317
+ │ No timer-based menu updates (avoids macOS UI bugs) │
318
+ └──────────────┬──────────────────────────┬───────────────┘
319
+ │ │
320
+ ┌─────────▼─────────┐ ┌──────────▼──────────┐
321
+ │ Background Poll │ │ Local Git Check │
322
+ │ │ │ │
323
+ │ NSTimer fires │ │ subprocess.run() │
324
+ │ every N seconds │ │ git status/log │
325
+ │ ThreadPoolExec │ │ per configured │
326
+ │ (3 workers max) │ │ repo path │
327
+ └─────────┬──────────┘ └──────────┬──────────┘
328
+ │ │
329
+ ┌─────────▼──────────────────────────▼───────────┐
330
+ │ Shared State (thread-safe) │
331
+ │ │
332
+ │ _current_prs[] _current_issues[] │
333
+ │ _current_ci_runs[] _local_statuses[] │
334
+ │ Protected by threading.Lock() │
335
+ └─────────┬──────────────────────────┬───────────┘
336
+ │ │
337
+ ┌─────────▼─────────┐ ┌──────────▼──────────┐
338
+ │ Notifier │ │ StateStore │
339
+ │ Dedup via seen IDs│ │ JSON persistence │
340
+ │ macOS native │ │ LRU (5000 max) │
341
+ │ notifications │ │ Debounced flush │
342
+ └───────────────────┘ └─────────────────────┘
343
+ ```
344
+
345
+ **Key design decisions:**
346
+ - **PyObjC instead of rumps** — rumps has compatibility issues on macOS 26+. Native PyObjC gives full control.
347
+ - **NSMenuDelegate pattern** — Menu content rebuilds on every open (`menuNeedsUpdate_`), so it's always fresh without timer-based UI updates.
348
+ - **All dialogs in main thread** — NSAlert/NSTextField only from menu action callbacks, never from timers or background threads.
349
+ - **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).
350
+ - **macOS Keychain for tokens** — Uses the `security` CLI tool. Config stores `token: keychain` as a sentinel.
351
+
352
+ ---
353
+
354
+ ## Development
355
+
356
+ ```bash
357
+ # Clone
358
+ git clone https://github.com/vamsi876/gitbar.git
359
+ cd gitbar
360
+
361
+ # Install in dev mode
362
+ pip install -e .
363
+
364
+ # Run
365
+ gitbar
366
+ # or
367
+ python run.py
368
+ ```
369
+
370
+ ### Project Structure
371
+
372
+ ```
373
+ gitbar/
374
+ ├── gitpulse/ # main package
375
+ │ ├── app.py # PyObjC menubar app + menu building
376
+ │ ├── auth.py # GitHub/GitLab/Bitbucket auth + keychain
377
+ │ ├── config.py # YAML config loader/saver
378
+ │ ├── models.py # Dataclasses: PullRequest, Issue, CIRun, etc.
379
+ │ ├── ui.py # Native macOS dialogs (NSAlert, notifications)
380
+ │ ├── poller.py # Concurrent polling scheduler
381
+ │ ├── notifier.py # Notification dedup + delivery
382
+ │ ├── state.py # Persistent state (seen events, last poll)
383
+ │ ├── localrepo.py # Local git repo status checker
384
+ │ └── providers/
385
+ │ ├── base.py # Abstract provider with rate-limit handling
386
+ │ ├── github.py # GitHub REST API v3
387
+ │ ├── gitlab.py # GitLab REST API v4
388
+ │ └── bitbucket.py # Bitbucket REST API v2
389
+ ├── run.py # Dev entry point
390
+ ├── config.example.yaml # Config template
391
+ ├── pyproject.toml # Package config (PyPI name: gitbar)
392
+ ├── requirements.txt
393
+ ├── LICENSE
394
+ └── README.md
395
+ ```
396
+
397
+ ---
398
+
399
+ ## Requirements
400
+
401
+ - **macOS** 13+ (Ventura or later)
402
+ - **Python** 3.10+
403
+
404
+ ---
405
+
406
+ ## License
407
+
408
+ MIT &mdash; see [LICENSE](LICENSE)
@@ -0,0 +1,21 @@
1
+ gitbar-0.1.0.dist-info/licenses/LICENSE,sha256=Z8XyzNwaJVpuXfMorAIWMwErgHpZL_WRludkikrEH7g,1080
2
+ gitpulse/__init__.py,sha256=kUR5RAFc7HCeiqdlX36dZOHkUI5wI6V_43RpEcD8b-0,22
3
+ gitpulse/app.py,sha256=E1wZYTFrOITwqUSrrZyYL_vkrOeGKhf5bww4FVg_CRQ,22477
4
+ gitpulse/auth.py,sha256=51Clz51Vxvb000zHtNsdyfJGly1YPP8AmAF0qBBSQMo,6246
5
+ gitpulse/config.py,sha256=C7tDGIw1mKDnpauEXCIVIBVdzKVhRSjNKvUCkHCQsbw,4102
6
+ gitpulse/localrepo.py,sha256=QgO7U3QJcqOyp0IGz8qoYfaZu3WUke7XApY9ClPMbY8,2272
7
+ gitpulse/models.py,sha256=k9OLRvE-HccRJrU0yOnoosttTMvKZBL8dxfJf0pXBKo,2678
8
+ gitpulse/notifier.py,sha256=P9fQryEp-c-LuyJ4xbj3cW8i6yKEK1sWnDIv9n5ub9E,2048
9
+ gitpulse/poller.py,sha256=ypcj2AT-xawmIKs020yFMnJDxsNuGIv-nqSHsGBHAb8,3892
10
+ gitpulse/state.py,sha256=lo5dIf4WuiHCFgtJDqA8POTlkyroD_j1PSJK6kwCkww,2222
11
+ gitpulse/ui.py,sha256=-mp_X0vF8hggI5MyfR2h-1xOspRnpu2m-sCTPAJ66tA,2649
12
+ gitpulse/providers/__init__.py,sha256=p1NOkMIrVTlqz-V0Pdup14_rhJL4asN7HPy-ooTImW4,180
13
+ gitpulse/providers/base.py,sha256=dmrC4V1L-SnHxVhDBl0XClAL7Oi1GzkIRR0EZFAYw5E,2816
14
+ gitpulse/providers/bitbucket.py,sha256=Yi2ppSoBlA51NkksQr0Xbphe92uNuWnPrwy976lMpKk,5068
15
+ gitpulse/providers/github.py,sha256=pK3tt6tXQpKoFqCR61XXiwG8f3PO541kcQXJV7RzhmI,9534
16
+ gitpulse/providers/gitlab.py,sha256=Fx4OBnI9zua3Kt3nCa1jLZDACCh-CsbEeh1vSdJ_tEs,5991
17
+ gitbar-0.1.0.dist-info/METADATA,sha256=vIqh9GI9mo0esZtRIJJrCa74_r6gSqG1IEAi6T6tYUI,15328
18
+ gitbar-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
19
+ gitbar-0.1.0.dist-info/entry_points.txt,sha256=IT1jtAF4mmgxj5PukgAC9Nw5mZ45kJoHvGt1ecIsEpc,48
20
+ gitbar-0.1.0.dist-info/top_level.txt,sha256=0x5i8Ky8Tjsh9daTBEMs79J9ahVc7Ny3zchI4Do3VKI,9
21
+ gitbar-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ gitbar = gitpulse.app:run_app
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vamsi Krishna Kollipara
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ gitpulse
gitpulse/__init__.py ADDED
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"