Skip to content

Commit a450f68

Browse files
authored
✨ GitHub Private Repos
1 parent 28a03cc commit a450f68

12 files changed

+946
-52
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ browsr ~/Downloads/
8181
browsr github://juftin:browsr
8282
```
8383

84+
```
85+
export GITHUB_TOKEN="ghp_1234567890"
86+
browsr github://juftin:browsr-private@main
87+
```
88+
8489
### Cloud
8590

8691
```shell

browsr/_base.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,16 @@ def path(self) -> pathlib.Path:
4343
"""
4444
Resolve `file_path` to a upath.UPath object
4545
"""
46+
if "github" in str(self.file_path).lower():
47+
file_path = str(self.file_path)
48+
file_path = file_path.lstrip("https://")
49+
file_path = file_path.lstrip("http://")
50+
file_path = file_path.lstrip("www.")
51+
file_path = file_path.rstrip(".git")
52+
file_path = handle_github_url(url=str(file_path))
53+
self.file_path = file_path
4654
if str(self.file_path).endswith("/"):
4755
self.file_path = str(self.file_path)[:-1]
48-
if "github" in str(self.file_path):
49-
self.file_path = handle_github_url(url=str(self.file_path))
5056
return (
5157
upath.UPath(self.file_path).resolve()
5258
if self.file_path

browsr/_cli.py

Lines changed: 67 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -72,30 +72,73 @@ def browsr(
7272
7373
## Usage Examples
7474
75-
- Load your current working directory
76-
```shell
77-
browsr
78-
```
79-
- Load a local directory
80-
```shell
81-
browsr/path/to/directory
82-
```
83-
- Load an S3 bucket
84-
```shell
85-
browsr s3://bucket-name
86-
```
87-
- Load a GCS bucket
88-
```shell
89-
browsr gs://bucket-name
90-
```
91-
- Load a GitHub repository
92-
```shell
93-
browsr github://juftin:browsr
94-
```
95-
- Load a GitHub repository branch
96-
```shell
97-
browsr github://juftin:browsr@main
98-
```
75+
### Local
76+
77+
#### Browse your current working directory
78+
79+
```shell
80+
browsr
81+
```
82+
83+
#### Browse a local directory
84+
85+
```shell
86+
browsr/path/to/directory
87+
```
88+
89+
### Cloud Storage
90+
91+
#### Browse an S3 bucket
92+
93+
```shell
94+
browsr s3://bucket-name
95+
```
96+
97+
#### Browse a GCS bucket
98+
99+
```shell
100+
browsr gs://bucket-name
101+
```
102+
103+
#### Browse Azure Services
104+
105+
```shell
106+
browsr adl://bucket-name
107+
browsr az://bucket-name
108+
```
109+
110+
### GitHub
111+
112+
#### Browse a GitHub repository
113+
114+
```shell
115+
browsr github://juftin:browsr
116+
```
117+
118+
#### Browse a GitHub Repository Branch
119+
120+
```shell
121+
browsr github://juftin:browsr@main
122+
```
123+
124+
#### Browse a Private GitHub Repository
125+
126+
```shell
127+
export GITHUB_TOKEN="ghp_1234567890"
128+
browsr github://juftin:browsr-private@main
129+
```
130+
131+
#### Browse a GitHub Repository Subdirectory
132+
133+
```shell
134+
browsr github://juftin:browsr@main/tests
135+
```
136+
137+
#### Browse a GitHub URL
138+
139+
```shell
140+
browsr https://github.com/juftin/browsr
141+
```
99142
100143
## Key Bindings
101144
- **`Q`** - Quit the application

browsr/_utils.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,16 @@ def handle_github_url(url: str) -> str:
140140
org, repo = user_password.split(":")
141141
elif "github://" in url and "@" in url:
142142
return url
143-
elif "github.com" in url and "https" in url:
144-
_, url = url.split("://")
143+
elif "github.com" in url.lower():
145144
_, org, repo, *args = url.split("/")
145+
else:
146+
raise ValueError(f"Invalid GitHub URL: {url}")
147+
token = os.getenv("GITHUB_TOKEN")
148+
auth = {"auth": ("Bearer", token)} if token is not None else {}
146149
resp = requests.get(
147150
f"https://api.github.com/repos/{org}/{repo}",
148151
headers={"Accept": "application/vnd.github.v3+json"},
152+
**auth, # type: ignore[arg-type]
149153
)
150154
resp.raise_for_status()
151155
default_branch = resp.json()["default_branch"]

browsr/browsr.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import json
99
import pathlib
1010
import shutil
11+
from os import getenv
1112
from textwrap import dedent
1213
from typing import TYPE_CHECKING, Any, Iterable, Optional, Union
1314

@@ -356,7 +357,9 @@ def action_download_file(self) -> None:
356357
self.confirmation_window.display = True
357358

358359

359-
app = Browsr(config_object=TextualAppContext(file_path=None, debug=True))
360+
app = Browsr(
361+
config_object=TextualAppContext(file_path=getenv("BROWSR_PATH"), debug=True)
362+
)
360363

361364
if __name__ == "__main__":
362365
app.run()

browsr/universal_directory_tree.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from __future__ import annotations
66

77
from dataclasses import dataclass
8+
from os import getenv
89
from typing import Any, ClassVar, Iterable, Optional
910

1011
import upath
@@ -158,6 +159,15 @@ class GitHubPath(upath.core.UPath):
158159
the Universal Directory Tree
159160
"""
160161

162+
def __new__(cls, *args, **kwargs) -> "GitHubPath": # type: ignore[no-untyped-def]
163+
"""
164+
Attempt to set the username and token from the environment
165+
"""
166+
token = getenv("GITHUB_TOKEN")
167+
kwargs.update({"username": "Bearer", "token": token})
168+
github_path = super().__new__(cls, *args, **kwargs)
169+
return github_path
170+
161171
@property
162172
def path(self) -> str:
163173
"""

docs/index.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,11 @@ browsr ~/Downloads/
124124
browsr github://juftin:browsr
125125
```
126126

127+
```
128+
export GITHUB_TOKEN="ghp_1234567890"
129+
browsr github://juftin:browsr-private@main
130+
```
131+
127132
### Cloud
128133

129134
```shell

pyproject.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ features = ["all"]
9494
pre-install-commands = ["pip install -U --no-deps -r requirements/requirements-dev.txt"]
9595
python = "3.10"
9696

97+
[tool.hatch.envs.default.env-vars]
98+
GITHUB_TOKEN = "{env:GITHUB_TOKEN:placeholder}"
99+
97100
[tool.hatch.envs.default.scripts]
98101
_pip_compile = "pip-compile --resolver=backtracking --generate-hashes requirements.in"
99102
all = ["format", "lint", "check", "test"]
@@ -151,7 +154,8 @@ module = [
151154

152155
[tool.ruff]
153156
ignore = [
154-
"E501" # line too long, handled by black
157+
"E501", # line too long, handled by black
158+
"B005" # Using `.strip()` with multi-character strings is misleading the reader
155159
]
156160
select = [
157161
"E", # pycodestyle errors

tests/cassettes/test_github_screenshot.yaml

Lines changed: 109 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,11 @@ interactions:
4949
Content-Type:
5050
- application/json; charset=utf-8
5151
Date:
52-
- Wed, 17 May 2023 21:30:44 GMT
52+
- Thu, 18 May 2023 01:01:44 GMT
5353
ETag:
5454
- W/"91ee3d202828b3c28fcd9be69924424a4f792f5f17ff608d6d4ac2b1e19e5fcd"
5555
Last-Modified:
56-
- Wed, 17 May 2023 21:16:30 GMT
56+
- Wed, 17 May 2023 23:39:58 GMT
5757
Referrer-Policy:
5858
- origin-when-cross-origin, strict-origin-when-cross-origin
5959
Server:
@@ -69,17 +69,112 @@ interactions:
6969
X-GitHub-Media-Type:
7070
- github.v3; format=json
7171
X-GitHub-Request-Id:
72-
- CEAA:5DE3:FF9051:20DD28A:64654784
72+
- C66F:5F92:13EA1B3:28FFF1A:646578F8
7373
X-RateLimit-Limit:
7474
- "60"
7575
X-RateLimit-Remaining:
76-
- "42"
76+
- "53"
7777
X-RateLimit-Reset:
78-
- "1684359062"
78+
- "1684374609"
7979
X-RateLimit-Resource:
8080
- core
8181
X-RateLimit-Used:
82-
- "18"
82+
- "7"
83+
X-XSS-Protection:
84+
- "0"
85+
x-github-api-version-selected:
86+
- "2022-11-28"
87+
status:
88+
code: 200
89+
message: OK
90+
- request:
91+
body: null
92+
headers:
93+
Accept:
94+
- "*/*"
95+
Accept-Encoding:
96+
- gzip, deflate
97+
Connection:
98+
- keep-alive
99+
User-Agent:
100+
- python-requests/2.28.2
101+
authorization:
102+
- XXXXXXXXXX
103+
method: GET
104+
uri: https://api.github.com/repos/juftin/browsr/git/trees/v1.6.0
105+
response:
106+
body:
107+
string: !!binary |
108+
H4sIAAAAAAAAA6WWTW/bOBCG/4vOqcXh5zC3YjeHBdoetsdiDzPkMHHWtlxJxiIt8t9LbYJavRRs
109+
5YNtQiYeP+TwHX7tpgfqbjtGJQTRBBe0siBaMqItJkOIECkYbVmh4u6mu4yHOuFhns/Tbd/Teb+7
110+
388PF96l4diPch6m/vFS5v2p53H4bxr7+rifR5Gp/wXKMqG7/fS1O9P8UHmvkMo/Drk+6ZRV9VXH
111+
89N5Gf8/4eZVh6ICkhw92yBJSpbiuRhnFDqvvKPgS4kFt+k0U55vfvDY35+GcfmzryqglLf2qsKH
112+
YVnol50JorLN1ikyjmIwkl0dgwgHG9FDKexRUlkm7L/UldCo7G/u0gKe+mbiWus8yptaAMf9XD9O
113+
ZX+/e6LjodGRYsagLGFCByCerFHKaEnag0smlypbGJclenEEE+Imx2bi2nGUg9AkY9o9To1mAYQ5
114+
m2riIDjkEsVQ8gxJW48KqcSsMdLVzIWNu9dKXJm9++uPuw8f7xqdTAEAnzmmRExogApnG5zVhJml
115+
QBLWgPHqBGrbbjUTV05/37398/3d7pgbrYCD1kEjCFCKiqPySTlCnSR6ZJ+dGACbrues/nhTDTYT
116+
V1YvkXpV+mkK5myLYvJoEDnVdw1asTdIYG0MTCWbaN3GUG+mrDTykFYn6OcSddlzzQWyYAoWnXKu
117+
LckoXSOcKDmJRkpKS7Vt6Ey5lbKSOP67aPxKzmUHrgZ2AetAAaRMNRdsMsE6ASehxkEItRdcawzQ
118+
/KbXS5Y3E1de56fzODxKmnfz0BzhEVm8AsQl5GxKBTIVCk7FXKtPqDZeEySH72rW2m3Hp5m4Uhvl
119+
82U/ylFOc2v9GVbW5kIpJ1Y159jkyLU5GV8vR8Ylh9GKheUmsqH+mikrmVmmZotaZw6xGIGYtBLx
120+
aGtGOweZgzeO61c2qWw8Rc2U53/qvW28nBLNkrvbQodJnr8BMK8OzowKAAA=
121+
headers:
122+
Access-Control-Allow-Origin:
123+
- "*"
124+
Access-Control-Expose-Headers:
125+
- ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining,
126+
X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes,
127+
X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO,
128+
X-GitHub-Request-Id, Deprecation, Sunset
129+
Cache-Control:
130+
- private, max-age=60, s-maxage=60
131+
Content-Encoding:
132+
- gzip
133+
Content-Security-Policy:
134+
- default-src 'none'
135+
Content-Type:
136+
- application/json; charset=utf-8
137+
Date:
138+
- Thu, 18 May 2023 01:01:44 GMT
139+
ETag:
140+
- W/"020b9c645dc6800fbd32a722b2d8f51d3a58cc017d63e5da3554a56489b157ec"
141+
Last-Modified:
142+
- Wed, 17 May 2023 23:39:58 GMT
143+
Referrer-Policy:
144+
- origin-when-cross-origin, strict-origin-when-cross-origin
145+
Server:
146+
- github.com
147+
Strict-Transport-Security:
148+
- max-age=31536000; includeSubdomains; preload
149+
Transfer-Encoding:
150+
- chunked
151+
Vary:
152+
- Accept, Authorization, Cookie, X-GitHub-OTP
153+
- Accept-Encoding, Accept, X-Requested-With
154+
X-Accepted-OAuth-Scopes:
155+
- ""
156+
X-Content-Type-Options:
157+
- nosniff
158+
X-Frame-Options:
159+
- deny
160+
X-GitHub-Media-Type:
161+
- github.v3; format=json
162+
X-GitHub-Request-Id:
163+
- C670:14FC:14A1CE8:2A6CA7E:646578F8
164+
X-OAuth-Scopes:
165+
- admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook,
166+
admin:ssh_signing_key, audit_log, codespace, delete:packages, gist, notifications,
167+
project, read:enterprise, repo, user, workflow, write:discussion, write:packages
168+
X-RateLimit-Limit:
169+
- "5000"
170+
X-RateLimit-Remaining:
171+
- "4981"
172+
X-RateLimit-Reset:
173+
- "1684373394"
174+
X-RateLimit-Resource:
175+
- core
176+
X-RateLimit-Used:
177+
- "19"
83178
X-XSS-Protection:
84179
- "0"
85180
x-github-api-version-selected:
@@ -141,11 +236,11 @@ interactions:
141236
Content-Type:
142237
- text/plain; charset=utf-8
143238
Date:
144-
- Wed, 17 May 2023 21:30:44 GMT
239+
- Thu, 18 May 2023 01:01:44 GMT
145240
ETag:
146241
- W/"e3f73ab855fd90588244244759492697dae0221aaa9e819693338d2cd1ad119e"
147242
Expires:
148-
- Wed, 17 May 2023 21:35:44 GMT
243+
- Thu, 18 May 2023 01:06:44 GMT
149244
Source-Age:
150245
- "0"
151246
Strict-Transport-Security:
@@ -155,21 +250,21 @@ interactions:
155250
Via:
156251
- 1.1 varnish
157252
X-Cache:
158-
- HIT
253+
- MISS
159254
X-Cache-Hits:
160-
- "1"
255+
- "0"
161256
X-Content-Type-Options:
162257
- nosniff
163258
X-Fastly-Request-ID:
164-
- 8db268a9faffcad81d0b18decbadb968a115ce12
259+
- 7459b3f705b11601e933e9db121561cfa0dae324
165260
X-Frame-Options:
166261
- deny
167262
X-GitHub-Request-Id:
168-
- 5E1C:093A:1CF866C:221F6FC:646545DF
263+
- F40E:6E4E:3A21014:443B1B9:646578F8
169264
X-Served-By:
170-
- cache-den8228-DEN
265+
- cache-den8272-DEN
171266
X-Timer:
172-
- S1684359045.859318,VS0,VE120
267+
- S1684371705.820747,VS0,VE131
173268
X-XSS-Protection:
174269
- 1; mode=block
175270
status:

0 commit comments

Comments
 (0)