git-glimpse-cli 0.1.0__tar.gz → 0.1.2__tar.gz
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.
- {git_glimpse_cli-0.1.0 → git_glimpse_cli-0.1.2}/PKG-INFO +18 -7
- {git_glimpse_cli-0.1.0 → git_glimpse_cli-0.1.2}/README.md +12 -6
- {git_glimpse_cli-0.1.0 → git_glimpse_cli-0.1.2}/git_glimpse_cli.egg-info/PKG-INFO +18 -7
- {git_glimpse_cli-0.1.0 → git_glimpse_cli-0.1.2}/glimpsecli/api.py +1 -2
- git_glimpse_cli-0.1.2/glimpsecli/config.py +126 -0
- {git_glimpse_cli-0.1.0 → git_glimpse_cli-0.1.2}/glimpsecli/helpers.py +9 -11
- {git_glimpse_cli-0.1.0 → git_glimpse_cli-0.1.2}/glimpsecli/main.py +65 -40
- {git_glimpse_cli-0.1.0 → git_glimpse_cli-0.1.2}/pyproject.toml +14 -2
- git_glimpse_cli-0.1.0/glimpsecli/config.py +0 -116
- {git_glimpse_cli-0.1.0 → git_glimpse_cli-0.1.2}/LICENSE +0 -0
- {git_glimpse_cli-0.1.0 → git_glimpse_cli-0.1.2}/git_glimpse_cli.egg-info/SOURCES.txt +0 -0
- {git_glimpse_cli-0.1.0 → git_glimpse_cli-0.1.2}/git_glimpse_cli.egg-info/dependency_links.txt +0 -0
- {git_glimpse_cli-0.1.0 → git_glimpse_cli-0.1.2}/git_glimpse_cli.egg-info/entry_points.txt +0 -0
- {git_glimpse_cli-0.1.0 → git_glimpse_cli-0.1.2}/git_glimpse_cli.egg-info/requires.txt +0 -0
- {git_glimpse_cli-0.1.0 → git_glimpse_cli-0.1.2}/git_glimpse_cli.egg-info/top_level.txt +0 -0
- {git_glimpse_cli-0.1.0 → git_glimpse_cli-0.1.2}/glimpsecli/__init__.py +0 -0
- {git_glimpse_cli-0.1.0 → git_glimpse_cli-0.1.2}/glimpsecli/utils.py +0 -0
- {git_glimpse_cli-0.1.0 → git_glimpse_cli-0.1.2}/setup.cfg +0 -0
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: git-glimpse-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: CLI tool to manage and update shared GitHub repos with GitGlimpse.
|
|
5
|
+
Author-email: sutaC <contact@sutac.pl>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/sutaC/git-glimpse-cli
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
5
10
|
Requires-Python: >=3.10
|
|
6
11
|
Description-Content-Type: text/markdown
|
|
7
12
|
License-File: LICENSE
|
|
@@ -60,12 +65,18 @@ pip install git-glimpse-cli
|
|
|
60
65
|
|
|
61
66
|
GitGlimpse CLI uses holds your configuration at `~/.config/glimpsecli/config.json`, and local repository settings are stored at `./.shared-repo.json`.
|
|
62
67
|
|
|
68
|
+
Configuration hierarchy:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
Most important -> Local repo config -> Global cli config
|
|
72
|
+
```
|
|
73
|
+
|
|
63
74
|
### Advanced Settings
|
|
64
75
|
|
|
65
|
-
| Command
|
|
66
|
-
|
|
|
67
|
-
| `glimpse config debug`
|
|
68
|
-
| `glimpse config
|
|
76
|
+
| Command | Description |
|
|
77
|
+
| ---------------------- | --------------------------------------------------------------------------- |
|
|
78
|
+
| `glimpse config debug` | Enables verbose debug mode, printing stack traces. |
|
|
79
|
+
| `glimpse config url` | Overrides the default production server with a custom backend or localhost. |
|
|
69
80
|
|
|
70
81
|
## Development
|
|
71
82
|
|
|
@@ -77,7 +88,7 @@ GitGlimpse CLI uses holds your configuration at `~/.config/glimpsecli/config.jso
|
|
|
77
88
|
source .venv/bin/activate
|
|
78
89
|
pip install -e .
|
|
79
90
|
```
|
|
80
|
-
2. Point the CLI to your local development server:
|
|
91
|
+
2. Point the CLI to your local development server (use `--local` to not propagate over your real global config):
|
|
81
92
|
```bash
|
|
82
|
-
glimpse config
|
|
93
|
+
glimpse config url http://localhost:5000 --local
|
|
83
94
|
```
|
|
@@ -48,12 +48,18 @@ pip install git-glimpse-cli
|
|
|
48
48
|
|
|
49
49
|
GitGlimpse CLI uses holds your configuration at `~/.config/glimpsecli/config.json`, and local repository settings are stored at `./.shared-repo.json`.
|
|
50
50
|
|
|
51
|
+
Configuration hierarchy:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
Most important -> Local repo config -> Global cli config
|
|
55
|
+
```
|
|
56
|
+
|
|
51
57
|
### Advanced Settings
|
|
52
58
|
|
|
53
|
-
| Command
|
|
54
|
-
|
|
|
55
|
-
| `glimpse config debug`
|
|
56
|
-
| `glimpse config
|
|
59
|
+
| Command | Description |
|
|
60
|
+
| ---------------------- | --------------------------------------------------------------------------- |
|
|
61
|
+
| `glimpse config debug` | Enables verbose debug mode, printing stack traces. |
|
|
62
|
+
| `glimpse config url` | Overrides the default production server with a custom backend or localhost. |
|
|
57
63
|
|
|
58
64
|
## Development
|
|
59
65
|
|
|
@@ -65,7 +71,7 @@ GitGlimpse CLI uses holds your configuration at `~/.config/glimpsecli/config.jso
|
|
|
65
71
|
source .venv/bin/activate
|
|
66
72
|
pip install -e .
|
|
67
73
|
```
|
|
68
|
-
2. Point the CLI to your local development server:
|
|
74
|
+
2. Point the CLI to your local development server (use `--local` to not propagate over your real global config):
|
|
69
75
|
```bash
|
|
70
|
-
glimpse config
|
|
76
|
+
glimpse config url http://localhost:5000 --local
|
|
71
77
|
```
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: git-glimpse-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: CLI tool to manage and update shared GitHub repos with GitGlimpse.
|
|
5
|
+
Author-email: sutaC <contact@sutac.pl>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/sutaC/git-glimpse-cli
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
5
10
|
Requires-Python: >=3.10
|
|
6
11
|
Description-Content-Type: text/markdown
|
|
7
12
|
License-File: LICENSE
|
|
@@ -60,12 +65,18 @@ pip install git-glimpse-cli
|
|
|
60
65
|
|
|
61
66
|
GitGlimpse CLI uses holds your configuration at `~/.config/glimpsecli/config.json`, and local repository settings are stored at `./.shared-repo.json`.
|
|
62
67
|
|
|
68
|
+
Configuration hierarchy:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
Most important -> Local repo config -> Global cli config
|
|
72
|
+
```
|
|
73
|
+
|
|
63
74
|
### Advanced Settings
|
|
64
75
|
|
|
65
|
-
| Command
|
|
66
|
-
|
|
|
67
|
-
| `glimpse config debug`
|
|
68
|
-
| `glimpse config
|
|
76
|
+
| Command | Description |
|
|
77
|
+
| ---------------------- | --------------------------------------------------------------------------- |
|
|
78
|
+
| `glimpse config debug` | Enables verbose debug mode, printing stack traces. |
|
|
79
|
+
| `glimpse config url` | Overrides the default production server with a custom backend or localhost. |
|
|
69
80
|
|
|
70
81
|
## Development
|
|
71
82
|
|
|
@@ -77,7 +88,7 @@ GitGlimpse CLI uses holds your configuration at `~/.config/glimpsecli/config.jso
|
|
|
77
88
|
source .venv/bin/activate
|
|
78
89
|
pip install -e .
|
|
79
90
|
```
|
|
80
|
-
2. Point the CLI to your local development server:
|
|
91
|
+
2. Point the CLI to your local development server (use `--local` to not propagate over your real global config):
|
|
81
92
|
```bash
|
|
82
|
-
glimpse config
|
|
93
|
+
glimpse config url http://localhost:5000 --local
|
|
83
94
|
```
|
|
@@ -28,7 +28,7 @@ def request_api(
|
|
|
28
28
|
Response from api.
|
|
29
29
|
"""
|
|
30
30
|
if not token:
|
|
31
|
-
token = helpers.
|
|
31
|
+
token = helpers.fget_token()
|
|
32
32
|
url = f"{config.get_api_url()}{endpoint}"
|
|
33
33
|
with Progress(SpinnerColumn(), TextColumn("[progress.description]{task.description}"), transient=True) if not quiet else nullcontext() as progress:
|
|
34
34
|
if progress:
|
|
@@ -52,7 +52,6 @@ def request_api(
|
|
|
52
52
|
error = response.json().get("error")
|
|
53
53
|
if error: print(f"[dim]Error reason: {error}[/dim]")
|
|
54
54
|
except JSONDecodeError: pass
|
|
55
|
-
config.cliconf_save(token="")
|
|
56
55
|
print("[yellow]Your session has expired. Please run 'glimpse login' again [/yellow].")
|
|
57
56
|
raise typer.Exit(1)
|
|
58
57
|
elif response.status_code == 403:
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
from functools import partial
|
|
2
|
+
from typing import TypedDict
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
import json
|
|
5
|
+
|
|
6
|
+
CLI_CONFIG_DIR = Path.home() / ".config" / "glimpsecli"
|
|
7
|
+
CLI_CONFIG_FILE = CLI_CONFIG_DIR / "config.json"
|
|
8
|
+
CONFIG_FILENAME = ".shared-repo.json"
|
|
9
|
+
DEFAULT_API_URL = "https://gitglimpse.sutac.pl"
|
|
10
|
+
|
|
11
|
+
class CliConfig(TypedDict, total=False):
|
|
12
|
+
token: str
|
|
13
|
+
api_url: str
|
|
14
|
+
debug: bool
|
|
15
|
+
|
|
16
|
+
class RepoConfig(CliConfig, total=False):
|
|
17
|
+
repo_id: str
|
|
18
|
+
|
|
19
|
+
# --- repository config
|
|
20
|
+
def _repoconf_load() -> RepoConfig | None:
|
|
21
|
+
"""Loads repository config from file.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
path: Path to directory holding config file.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
RepoConfig if avaliable, else None.
|
|
28
|
+
"""
|
|
29
|
+
config_path = Path(".") / CONFIG_FILENAME
|
|
30
|
+
if not config_path.exists():
|
|
31
|
+
return None
|
|
32
|
+
try:
|
|
33
|
+
with open(config_path, "r") as f:
|
|
34
|
+
return json.load(f)
|
|
35
|
+
except Exception:
|
|
36
|
+
return None
|
|
37
|
+
|
|
38
|
+
def repoconf_remove() -> None:
|
|
39
|
+
"""Removes repository config file if exists.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
path: Path to directory holding config file.
|
|
43
|
+
"""
|
|
44
|
+
config_path = Path(".") / CONFIG_FILENAME
|
|
45
|
+
config_path.unlink(missing_ok=True)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# --- cli config
|
|
49
|
+
def _cliconf_load() -> CliConfig | None:
|
|
50
|
+
"""Loads cli configfrom file.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
CliConfig if avaliable, else None.
|
|
54
|
+
"""
|
|
55
|
+
if not CLI_CONFIG_FILE.exists():
|
|
56
|
+
return None
|
|
57
|
+
try:
|
|
58
|
+
with open(CLI_CONFIG_FILE, "r") as f:
|
|
59
|
+
return json.load(f)
|
|
60
|
+
except Exception:
|
|
61
|
+
return None
|
|
62
|
+
|
|
63
|
+
def cliconf_remove() -> None:
|
|
64
|
+
"""Removes cli config file."""
|
|
65
|
+
CLI_CONFIG_FILE.unlink(missing_ok=True)
|
|
66
|
+
|
|
67
|
+
# --- conf update
|
|
68
|
+
def conf_save(
|
|
69
|
+
new_conf: CliConfig | RepoConfig | dict,
|
|
70
|
+
local = False
|
|
71
|
+
) -> None:
|
|
72
|
+
"""Save configuration in ethier local or global context.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
local: If True saves config to local context, else saves in global context.
|
|
76
|
+
"""
|
|
77
|
+
if local:
|
|
78
|
+
conf = _repoconf_load() or {}
|
|
79
|
+
conf_file = Path(".") / CONFIG_FILENAME
|
|
80
|
+
else:
|
|
81
|
+
CLI_CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
|
82
|
+
conf = _cliconf_load() or {}
|
|
83
|
+
conf_file = CLI_CONFIG_FILE
|
|
84
|
+
for key, val in new_conf.items():
|
|
85
|
+
if val is not None:
|
|
86
|
+
conf[key] = val
|
|
87
|
+
elif key in conf:
|
|
88
|
+
conf.pop(key)
|
|
89
|
+
with open(conf_file, "w") as f:
|
|
90
|
+
json.dump(conf, f, indent=2)
|
|
91
|
+
|
|
92
|
+
# --- config getters
|
|
93
|
+
def get_api_url() -> str:
|
|
94
|
+
"""Returns active api url."""
|
|
95
|
+
if conf := _repoconf_load():
|
|
96
|
+
if user_url := conf.get("api_url"):
|
|
97
|
+
return user_url.rstrip("/")
|
|
98
|
+
if conf := _cliconf_load():
|
|
99
|
+
if user_url := conf.get("api_url"):
|
|
100
|
+
return user_url.rstrip("/")
|
|
101
|
+
return DEFAULT_API_URL
|
|
102
|
+
|
|
103
|
+
def get_debug_mode() -> bool:
|
|
104
|
+
"""Returns True if debug is enabled in user config, else False."""
|
|
105
|
+
if conf := _repoconf_load():
|
|
106
|
+
if debug := conf.get("debug") is not None:
|
|
107
|
+
return debug
|
|
108
|
+
if conf := _cliconf_load():
|
|
109
|
+
return conf.get("debug", False)
|
|
110
|
+
return False
|
|
111
|
+
|
|
112
|
+
def get_repo_id() -> str | None:
|
|
113
|
+
"""Returns current repo_id."""
|
|
114
|
+
if conf := _repoconf_load():
|
|
115
|
+
return conf.get("repo_id")
|
|
116
|
+
return None
|
|
117
|
+
|
|
118
|
+
def get_token() -> str | None:
|
|
119
|
+
"""Returns current user cli token."""
|
|
120
|
+
if conf := _repoconf_load():
|
|
121
|
+
if token := conf.get("token"):
|
|
122
|
+
return token
|
|
123
|
+
if conf := _cliconf_load():
|
|
124
|
+
if token := conf.get("token"):
|
|
125
|
+
return token
|
|
126
|
+
return None
|
|
@@ -5,7 +5,6 @@ from rich import print
|
|
|
5
5
|
import typer
|
|
6
6
|
import time
|
|
7
7
|
|
|
8
|
-
|
|
9
8
|
def get_or_prompt_url(url: str | None = None, detect: bool = True) -> str:
|
|
10
9
|
"""Helper to get GitHub repository url.
|
|
11
10
|
|
|
@@ -38,7 +37,7 @@ def finalize_init(repo_id: str) -> None:
|
|
|
38
37
|
repo_id: Repository GitGlimpse id.
|
|
39
38
|
"""
|
|
40
39
|
# Add repo id to local file
|
|
41
|
-
config.
|
|
40
|
+
config.conf_save({"repo_id": repo_id}, local=True)
|
|
42
41
|
print("[dim]Created local .shared-repo.json configuration file for this repository.[/dim]")
|
|
43
42
|
# Auto-add to .gitignore
|
|
44
43
|
gitignore = Path(".gitignore")
|
|
@@ -65,7 +64,7 @@ def poll_build_status(token: str, repo_id: str) -> None:
|
|
|
65
64
|
task_id = progress.add_task(description="Connecting to server...", total=None)
|
|
66
65
|
last_status = None
|
|
67
66
|
while True:
|
|
68
|
-
poll_response = api.request_api(f"/repos/build/{repo_id}/status", token=token, quiet=True)
|
|
67
|
+
poll_response = api.request_api(f"/cli/repos/build/{repo_id}/status", token=token, quiet=True)
|
|
69
68
|
status = poll_response.json().get("status")
|
|
70
69
|
if status != last_status:
|
|
71
70
|
progress.update(task_id, description=f"Build status: {utils.enrich_status(status)}")
|
|
@@ -79,19 +78,18 @@ def poll_build_status(token: str, repo_id: str) -> None:
|
|
|
79
78
|
print(f"Build has finished with status: {utils.enrich_status(status)}")
|
|
80
79
|
print(f"View details at: {config.get_api_url()}/repos/details/{repo_id}")
|
|
81
80
|
|
|
82
|
-
def
|
|
81
|
+
def fget_repo_id() -> str:
|
|
83
82
|
"""Helper for getting repository config."""
|
|
84
|
-
|
|
85
|
-
if not
|
|
83
|
+
repo_id = config.get_repo_id()
|
|
84
|
+
if not repo_id:
|
|
86
85
|
print("[yellow]Not initialised. Run 'glimpse init' first.[/yellow]")
|
|
87
86
|
raise typer.Exit(1)
|
|
88
|
-
return
|
|
87
|
+
return repo_id
|
|
89
88
|
|
|
90
|
-
def
|
|
89
|
+
def fget_token() -> str:
|
|
91
90
|
"""Helper for getting api token."""
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if not conf or not token:
|
|
91
|
+
token = config.get_token()
|
|
92
|
+
if not token:
|
|
95
93
|
print("[yellow]Not logged in. Run 'glimpse login' first.[/yellow]")
|
|
96
94
|
raise typer.Exit(code=1)
|
|
97
95
|
return token
|
|
@@ -33,17 +33,19 @@ def login(
|
|
|
33
33
|
prompt="Enter your CLI token",
|
|
34
34
|
hide_input=True,
|
|
35
35
|
help="Your personal access cli token from dashboard."),
|
|
36
|
-
|
|
36
|
+
force: bool = typer.Option(False, "--force", "-f", help="Overwrite existing session without prompting."),
|
|
37
|
+
local: bool = typer.Option(False, "--local", "-l", help="Save config to local repository only.")
|
|
37
38
|
):
|
|
38
39
|
"""Authenticate cli with server."""
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
if local: old_token = (config._repoconf_load() or {}).get("token")
|
|
41
|
+
else: old_token = (config._cliconf_load() or {}).get("token")
|
|
42
|
+
if not force and old_token:
|
|
41
43
|
print("[yellow]You are already logged in.[/yellow]")
|
|
42
44
|
if not typer.confirm("Do you want to overwrite your existing session?"):
|
|
43
45
|
print("[dim]Login cancelled.[/dim]")
|
|
44
46
|
raise typer.Exit(0)
|
|
45
47
|
response = api.request_api("/cli/user", token=token)
|
|
46
|
-
config.
|
|
48
|
+
config.conf_save({"token": token}, local)
|
|
47
49
|
username = response.json().get("username")
|
|
48
50
|
print(f"[bold green]Success![/bold green] Authenticated as [cyan]{username}[/cyan].")
|
|
49
51
|
|
|
@@ -57,13 +59,16 @@ def whoami():
|
|
|
57
59
|
|
|
58
60
|
# --- logout
|
|
59
61
|
@app.command()
|
|
60
|
-
def logout(
|
|
62
|
+
def logout(
|
|
63
|
+
local: bool = typer.Option(False, "--local", "-l", help="Alter config in local repository only.")
|
|
64
|
+
):
|
|
61
65
|
"""Clear stored local credentials."""
|
|
62
|
-
|
|
63
|
-
|
|
66
|
+
if local: token = (config._repoconf_load() or {}).get("token")
|
|
67
|
+
else: token = (config._cliconf_load() or {}).get("token")
|
|
68
|
+
if not token:
|
|
64
69
|
print("[yellow]You are not currently logged in.[/yellow]")
|
|
65
70
|
raise typer.Exit(0)
|
|
66
|
-
config.
|
|
71
|
+
config.conf_save({"token": None})
|
|
67
72
|
print("[bold green]Logged out successfully.[/bold green]\nStored credentials removed.")
|
|
68
73
|
|
|
69
74
|
# --- init
|
|
@@ -76,8 +81,8 @@ def init_link(
|
|
|
76
81
|
detect: bool = typer.Option(True, help="Do you want to detect repository url automatically.")
|
|
77
82
|
):
|
|
78
83
|
"""Link current Git repository to existing one on GitGlimpse."""
|
|
79
|
-
token = helpers.
|
|
80
|
-
if config.
|
|
84
|
+
token = helpers.fget_token()
|
|
85
|
+
if config.get_repo_id():
|
|
81
86
|
print("Shared repository already initialised.")
|
|
82
87
|
raise typer.Exit(0)
|
|
83
88
|
url = helpers.get_or_prompt_url(url, detect)
|
|
@@ -100,8 +105,8 @@ def init_new(
|
|
|
100
105
|
detect: bool = typer.Option(True, help="Do you want to detect repository url automatically.")
|
|
101
106
|
):
|
|
102
107
|
"""Upload and register current Git repository to GitGlimpse."""
|
|
103
|
-
token = helpers.
|
|
104
|
-
if config.
|
|
108
|
+
token = helpers.fget_token()
|
|
109
|
+
if config.get_repo_id():
|
|
105
110
|
print("Shared repository already initialised.")
|
|
106
111
|
raise typer.Exit(0)
|
|
107
112
|
url = helpers.get_or_prompt_url(url, detect)
|
|
@@ -172,14 +177,14 @@ def limits():
|
|
|
172
177
|
@app.command()
|
|
173
178
|
def status():
|
|
174
179
|
"""Display status info of current repository."""
|
|
175
|
-
token = helpers.
|
|
176
|
-
|
|
177
|
-
response = api.request_api(f"/cli/repos/build/{
|
|
180
|
+
token = helpers.fget_token()
|
|
181
|
+
repo_id = helpers.fget_repo_id()
|
|
182
|
+
response = api.request_api(f"/cli/repos/build/{repo_id}/status", token=token)
|
|
178
183
|
data = response.json()
|
|
179
184
|
build_status = data.get("status", "")
|
|
180
|
-
print(f"Repository id: [dark_cyan]{
|
|
185
|
+
print(f"Repository id: [dark_cyan]{repo_id}[/dark_cyan]")
|
|
181
186
|
print(f"Build status: {utils.enrich_status(build_status)}")
|
|
182
|
-
print(f"Repository details: {config.get_api_url()}/repos/details/{
|
|
187
|
+
print(f"Repository details: {config.get_api_url()}/repos/details/{repo_id}")
|
|
183
188
|
|
|
184
189
|
# --- remove
|
|
185
190
|
@app.command()
|
|
@@ -187,11 +192,11 @@ def remove(
|
|
|
187
192
|
force: bool = typer.Option(False, "--force", "-f", help="Remove without prompting.")
|
|
188
193
|
):
|
|
189
194
|
"""Remove current repository from GitGlimpse."""
|
|
190
|
-
token = helpers.
|
|
191
|
-
|
|
192
|
-
print(f"[dim]Current repository id: '{
|
|
195
|
+
token = helpers.fget_token()
|
|
196
|
+
repo_id = helpers.fget_repo_id()
|
|
197
|
+
print(f"[dim]Current repository id: '{repo_id}'[/dim]")
|
|
193
198
|
if not force: typer.confirm(f"Are you sure, you want to remove this repository from GitGlimpse?", abort=True)
|
|
194
|
-
api.request_api(f"/cli/repos/remove/{
|
|
199
|
+
api.request_api(f"/cli/repos/remove/{repo_id}", method="POST", token=token, handle_codes=[204])
|
|
195
200
|
config.repoconf_remove()
|
|
196
201
|
print("Removed repository from GitGlimpse.")
|
|
197
202
|
|
|
@@ -201,13 +206,13 @@ def build(
|
|
|
201
206
|
force: bool = typer.Option(False, "--force", "-f", help="Schedule without prompting.")
|
|
202
207
|
):
|
|
203
208
|
"""Schedule a build for current repository."""
|
|
204
|
-
token = helpers.
|
|
205
|
-
|
|
209
|
+
token = helpers.fget_token()
|
|
210
|
+
repo_id = helpers.fget_repo_id()
|
|
206
211
|
if not force:
|
|
207
212
|
print("Ensure that you pushed recent changes to GitHub.")
|
|
208
213
|
typer.confirm("Continue?", abort=True)
|
|
209
|
-
print(f"[dim]Scheduling a build for current repository (id: '{
|
|
210
|
-
response = api.request_api(f"/cli/repos/build/{
|
|
214
|
+
print(f"[dim]Scheduling a build for current repository (id: '{repo_id}')[/dim]")
|
|
215
|
+
response = api.request_api(f"/cli/repos/build/{repo_id}", method="POST", token=token, handle_codes=[202, 420, 425])
|
|
211
216
|
if response.status_code == 420:
|
|
212
217
|
print(f"[yellow]You have reached your usage limits.[/yellow]")
|
|
213
218
|
try:
|
|
@@ -219,36 +224,56 @@ def build(
|
|
|
219
224
|
print(f"[yellow]This repository already has a pending build.[/yellow]")
|
|
220
225
|
raise typer.Exit(1)
|
|
221
226
|
# response.status_code == 202
|
|
222
|
-
helpers.poll_build_status(token,
|
|
227
|
+
helpers.poll_build_status(token, repo_id)
|
|
223
228
|
|
|
224
229
|
# --- config
|
|
225
230
|
config_app = typer.Typer(help="Configure your cli.", no_args_is_help=True)
|
|
226
231
|
app.add_typer(config_app, name="config")
|
|
227
232
|
|
|
228
|
-
@config_app.command("
|
|
229
|
-
def
|
|
230
|
-
|
|
233
|
+
@config_app.command("list")
|
|
234
|
+
def config_list(
|
|
235
|
+
sensitive: bool = typer.Option(False, "--show-sensitive", help="Display sensitive data."),
|
|
236
|
+
local: bool = typer.Option(None, "--local/--global", help="Display only local or global config.")
|
|
237
|
+
):
|
|
238
|
+
"""Get current cli config."""
|
|
239
|
+
sensitive_keys = ["token", "repo_id"]
|
|
240
|
+
lconf = config._repoconf_load() or {}
|
|
241
|
+
gconf = config._cliconf_load() or {}
|
|
242
|
+
if local is None:
|
|
243
|
+
print("[bold]Current cli config[/bold]")
|
|
244
|
+
elif local:
|
|
245
|
+
print("[bold]Current LOCAL cli config[/bold]")
|
|
246
|
+
else:
|
|
247
|
+
print("[bold]Current GLOBAL cli config[/bold]")
|
|
248
|
+
if local != False:
|
|
249
|
+
for key, val in lconf.items():
|
|
250
|
+
val = f"[dim][{key.upper()}][/dim]" if not sensitive and key in sensitive_keys else val
|
|
251
|
+
print(f"{key}: {val}")
|
|
252
|
+
if local != True:
|
|
253
|
+
for key, val in gconf.items():
|
|
254
|
+
if local is None and key in lconf: continue
|
|
255
|
+
val = f"[dim][{key.upper()}][/dim]" if not sensitive and key in sensitive_keys else val
|
|
256
|
+
print(f"{key}: {val}")
|
|
257
|
+
|
|
258
|
+
@config_app.command("url")
|
|
259
|
+
def config_url(
|
|
260
|
+
url: str = typer.Argument(..., help="Api base url (e.g., http://localhost:8000 or https://gitglimpse.sutac.pl)"),
|
|
261
|
+
local: bool = typer.Option(False, "--local", "-l", help="Save config to local repository only.")
|
|
231
262
|
):
|
|
232
263
|
"""Set the active api server url."""
|
|
233
|
-
config.
|
|
264
|
+
config.conf_save({"api_url": (url if url else None)}, local)
|
|
234
265
|
if url:
|
|
235
266
|
print(f"Api url updated to: {url}")
|
|
236
267
|
else:
|
|
237
268
|
print("Api url unset.")
|
|
238
269
|
|
|
239
|
-
@config_app.command("get-url")
|
|
240
|
-
def config_get_url():
|
|
241
|
-
"""Get the active api server url."""
|
|
242
|
-
conf = config.cliconf_load() or {}
|
|
243
|
-
url = conf.get("api_url")
|
|
244
|
-
if url: print(url)
|
|
245
|
-
|
|
246
270
|
@config_app.command("debug")
|
|
247
271
|
def config_debug(
|
|
248
|
-
|
|
249
|
-
)
|
|
272
|
+
enabled: bool = typer.Argument(..., help="True to enable debug mode, False to disable."),
|
|
273
|
+
local: bool = typer.Option(False, "--local", "-l", help="Save config to local repository only.")
|
|
274
|
+
):
|
|
250
275
|
"""Enable or disable verbose debug output and full crash stack traces."""
|
|
251
|
-
config.
|
|
276
|
+
config.conf_save({"debug": enabled}, local)
|
|
252
277
|
status = "[bold green]enabled[/bold green]" if enabled else "[bold yellow]disabled[/bold yellow]"
|
|
253
278
|
print(f"Debug mode {status}.")
|
|
254
279
|
|
|
@@ -4,15 +4,27 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "git-glimpse-cli"
|
|
7
|
-
|
|
7
|
+
authors = [
|
|
8
|
+
{ name="sutaC", email="contact@sutac.pl" },
|
|
9
|
+
]
|
|
10
|
+
version = "0.1.2"
|
|
8
11
|
description = "CLI tool to manage and update shared GitHub repos with GitGlimpse."
|
|
9
12
|
readme = "README.md"
|
|
10
13
|
requires-python = ">=3.10"
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Operating System :: OS Independent",
|
|
17
|
+
]
|
|
11
18
|
dependencies = [
|
|
12
19
|
"httpx>=0.28.1",
|
|
13
20
|
"rich>=15.0.0",
|
|
14
21
|
"typer>=0.27.2"
|
|
15
22
|
]
|
|
23
|
+
license = "MIT"
|
|
24
|
+
license-files = ["LICEN[CS]E*"]
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
Homepage = "https://github.com/sutaC/git-glimpse-cli"
|
|
16
28
|
|
|
17
29
|
[project.scripts]
|
|
18
|
-
glimpse = "glimpsecli.main:cli"
|
|
30
|
+
glimpse = "glimpsecli.main:cli"
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
from typing import TypedDict
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
import json
|
|
4
|
-
import os
|
|
5
|
-
|
|
6
|
-
CLI_CONFIG_DIR = Path.home() / ".config" / "glimpsecli"
|
|
7
|
-
CLI_CONFIG_FILE = CLI_CONFIG_DIR / "config.json"
|
|
8
|
-
CONFIG_FILENAME = ".shared-repo.json"
|
|
9
|
-
DEFAULT_API_URL = "https://gitglimpse.sutac.pl"
|
|
10
|
-
|
|
11
|
-
# --- repository config
|
|
12
|
-
class RepoConfig(TypedDict):
|
|
13
|
-
repo_id: str
|
|
14
|
-
|
|
15
|
-
def repoconf_save(repo_id: str, path: Path = Path(".")) -> None:
|
|
16
|
-
"""Saves repository config to file.
|
|
17
|
-
|
|
18
|
-
Args:
|
|
19
|
-
repo_id: Repository GitGlimpse id.
|
|
20
|
-
path: Path to directory holding config file.
|
|
21
|
-
"""
|
|
22
|
-
config_path = path / CONFIG_FILENAME
|
|
23
|
-
conf: RepoConfig = {"repo_id": repo_id}
|
|
24
|
-
with open(config_path, "w") as f:
|
|
25
|
-
json.dump(conf, f, indent=2)
|
|
26
|
-
|
|
27
|
-
def repoconf_load(path: Path = Path(".")) -> RepoConfig | None:
|
|
28
|
-
"""Loads repository config from file.
|
|
29
|
-
|
|
30
|
-
Args:
|
|
31
|
-
path: Path to directory holding config file.
|
|
32
|
-
|
|
33
|
-
Returns:
|
|
34
|
-
RepoConfig if avaliable, else None.
|
|
35
|
-
"""
|
|
36
|
-
config_path = path / CONFIG_FILENAME
|
|
37
|
-
if not config_path.exists():
|
|
38
|
-
return None
|
|
39
|
-
try:
|
|
40
|
-
with open(config_path, "r") as f:
|
|
41
|
-
return json.load(f)
|
|
42
|
-
except Exception:
|
|
43
|
-
return None
|
|
44
|
-
|
|
45
|
-
def repoconf_remove(path: Path = Path(".")) -> None:
|
|
46
|
-
"""Removes repository config file if exists.
|
|
47
|
-
|
|
48
|
-
Args:
|
|
49
|
-
path: Path to directory holding config file.
|
|
50
|
-
"""
|
|
51
|
-
config_path = path / CONFIG_FILENAME
|
|
52
|
-
config_path.unlink(missing_ok=True)
|
|
53
|
-
|
|
54
|
-
# --- cli config
|
|
55
|
-
class CliConfig(TypedDict, total=False):
|
|
56
|
-
token: str
|
|
57
|
-
api_url: str
|
|
58
|
-
debug: bool
|
|
59
|
-
|
|
60
|
-
def cliconf_save(
|
|
61
|
-
token: str | None = None,
|
|
62
|
-
api_url: str | None = None,
|
|
63
|
-
debug: bool | None = None
|
|
64
|
-
) -> None:
|
|
65
|
-
"""Saves or updates cli config safely.
|
|
66
|
-
|
|
67
|
-
Args:
|
|
68
|
-
token: GitGlimpse api token.
|
|
69
|
-
"""
|
|
70
|
-
CLI_CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
|
71
|
-
conf = cliconf_load() or {}
|
|
72
|
-
if token is not None:
|
|
73
|
-
if token: conf["token"] = token
|
|
74
|
-
elif "token" in conf: conf.pop("token")
|
|
75
|
-
if api_url is not None:
|
|
76
|
-
if api_url: conf["api_url"] = api_url.rstrip("/")
|
|
77
|
-
elif "api_url" in conf: conf.pop("api_url")
|
|
78
|
-
if debug is not None:
|
|
79
|
-
conf["debug"] = debug
|
|
80
|
-
with open(CLI_CONFIG_FILE, "w") as f:
|
|
81
|
-
json.dump(conf, f, indent=2)
|
|
82
|
-
|
|
83
|
-
def cliconf_load() -> CliConfig | None:
|
|
84
|
-
"""Loads cli configfrom file.
|
|
85
|
-
|
|
86
|
-
Returns:
|
|
87
|
-
CliConfig if avaliable, else None.
|
|
88
|
-
"""
|
|
89
|
-
if not CLI_CONFIG_FILE.exists():
|
|
90
|
-
return None
|
|
91
|
-
try:
|
|
92
|
-
with open(CLI_CONFIG_FILE, "r") as f:
|
|
93
|
-
return json.load(f)
|
|
94
|
-
except Exception:
|
|
95
|
-
return None
|
|
96
|
-
|
|
97
|
-
def cliconf_remove() -> None:
|
|
98
|
-
"""Removes cli config file."""
|
|
99
|
-
CLI_CONFIG_FILE.unlink(missing_ok=True)
|
|
100
|
-
|
|
101
|
-
def get_api_url() -> str:
|
|
102
|
-
"""Resolves active api url
|
|
103
|
-
|
|
104
|
-
Returns:
|
|
105
|
-
Active api url.
|
|
106
|
-
"""
|
|
107
|
-
if conf := cliconf_load():
|
|
108
|
-
if user_url := conf.get("api_url"):
|
|
109
|
-
return user_url.rstrip("/")
|
|
110
|
-
return DEFAULT_API_URL
|
|
111
|
-
|
|
112
|
-
def get_debug_mode() -> bool:
|
|
113
|
-
"""Returns True if debug is enabled in user config, else False."""
|
|
114
|
-
if conf := cliconf_load():
|
|
115
|
-
return conf.get("debug", False)
|
|
116
|
-
return False
|
|
File without changes
|
|
File without changes
|
{git_glimpse_cli-0.1.0 → git_glimpse_cli-0.1.2}/git_glimpse_cli.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|