git-glimpse-cli 0.1.1__tar.gz → 0.1.3__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.1 → git_glimpse_cli-0.1.3}/PKG-INFO +13 -7
- {git_glimpse_cli-0.1.1 → git_glimpse_cli-0.1.3}/README.md +12 -6
- {git_glimpse_cli-0.1.1 → git_glimpse_cli-0.1.3}/git_glimpse_cli.egg-info/PKG-INFO +13 -7
- {git_glimpse_cli-0.1.1 → git_glimpse_cli-0.1.3}/glimpsecli/api.py +10 -2
- git_glimpse_cli-0.1.3/glimpsecli/config.py +126 -0
- {git_glimpse_cli-0.1.1 → git_glimpse_cli-0.1.3}/glimpsecli/helpers.py +8 -10
- {git_glimpse_cli-0.1.1 → git_glimpse_cli-0.1.3}/glimpsecli/main.py +70 -43
- {git_glimpse_cli-0.1.1 → git_glimpse_cli-0.1.3}/pyproject.toml +1 -1
- git_glimpse_cli-0.1.1/glimpsecli/config.py +0 -116
- {git_glimpse_cli-0.1.1 → git_glimpse_cli-0.1.3}/LICENSE +0 -0
- {git_glimpse_cli-0.1.1 → git_glimpse_cli-0.1.3}/git_glimpse_cli.egg-info/SOURCES.txt +0 -0
- {git_glimpse_cli-0.1.1 → git_glimpse_cli-0.1.3}/git_glimpse_cli.egg-info/dependency_links.txt +0 -0
- {git_glimpse_cli-0.1.1 → git_glimpse_cli-0.1.3}/git_glimpse_cli.egg-info/entry_points.txt +0 -0
- {git_glimpse_cli-0.1.1 → git_glimpse_cli-0.1.3}/git_glimpse_cli.egg-info/requires.txt +0 -0
- {git_glimpse_cli-0.1.1 → git_glimpse_cli-0.1.3}/git_glimpse_cli.egg-info/top_level.txt +0 -0
- {git_glimpse_cli-0.1.1 → git_glimpse_cli-0.1.3}/glimpsecli/__init__.py +0 -0
- {git_glimpse_cli-0.1.1 → git_glimpse_cli-0.1.3}/glimpsecli/utils.py +0 -0
- {git_glimpse_cli-0.1.1 → git_glimpse_cli-0.1.3}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: git-glimpse-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: CLI tool to manage and update shared GitHub repos with GitGlimpse.
|
|
5
5
|
Author-email: sutaC <contact@sutac.pl>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -65,12 +65,18 @@ pip install git-glimpse-cli
|
|
|
65
65
|
|
|
66
66
|
GitGlimpse CLI uses holds your configuration at `~/.config/glimpsecli/config.json`, and local repository settings are stored at `./.shared-repo.json`.
|
|
67
67
|
|
|
68
|
+
Configuration hierarchy:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
Most important -> Local repo config -> Global cli config
|
|
72
|
+
```
|
|
73
|
+
|
|
68
74
|
### Advanced Settings
|
|
69
75
|
|
|
70
|
-
| Command
|
|
71
|
-
|
|
|
72
|
-
| `glimpse config debug`
|
|
73
|
-
| `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. |
|
|
74
80
|
|
|
75
81
|
## Development
|
|
76
82
|
|
|
@@ -82,7 +88,7 @@ GitGlimpse CLI uses holds your configuration at `~/.config/glimpsecli/config.jso
|
|
|
82
88
|
source .venv/bin/activate
|
|
83
89
|
pip install -e .
|
|
84
90
|
```
|
|
85
|
-
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):
|
|
86
92
|
```bash
|
|
87
|
-
glimpse config
|
|
93
|
+
glimpse config url http://localhost:5000 --local
|
|
88
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,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: git-glimpse-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: CLI tool to manage and update shared GitHub repos with GitGlimpse.
|
|
5
5
|
Author-email: sutaC <contact@sutac.pl>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -65,12 +65,18 @@ pip install git-glimpse-cli
|
|
|
65
65
|
|
|
66
66
|
GitGlimpse CLI uses holds your configuration at `~/.config/glimpsecli/config.json`, and local repository settings are stored at `./.shared-repo.json`.
|
|
67
67
|
|
|
68
|
+
Configuration hierarchy:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
Most important -> Local repo config -> Global cli config
|
|
72
|
+
```
|
|
73
|
+
|
|
68
74
|
### Advanced Settings
|
|
69
75
|
|
|
70
|
-
| Command
|
|
71
|
-
|
|
|
72
|
-
| `glimpse config debug`
|
|
73
|
-
| `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. |
|
|
74
80
|
|
|
75
81
|
## Development
|
|
76
82
|
|
|
@@ -82,7 +88,7 @@ GitGlimpse CLI uses holds your configuration at `~/.config/glimpsecli/config.jso
|
|
|
82
88
|
source .venv/bin/activate
|
|
83
89
|
pip install -e .
|
|
84
90
|
```
|
|
85
|
-
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):
|
|
86
92
|
```bash
|
|
87
|
-
glimpse config
|
|
93
|
+
glimpse config url http://localhost:5000 --local
|
|
88
94
|
```
|
|
@@ -2,10 +2,19 @@ from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
|
2
2
|
from glimpsecli import config, helpers
|
|
3
3
|
from contextlib import nullcontext
|
|
4
4
|
from json import JSONDecodeError
|
|
5
|
+
from typing import TypedDict
|
|
5
6
|
from rich import print
|
|
6
7
|
import typer
|
|
7
8
|
import httpx
|
|
8
9
|
|
|
10
|
+
# --- Responses
|
|
11
|
+
class StatusResponse(TypedDict):
|
|
12
|
+
status: str
|
|
13
|
+
timestamp: str
|
|
14
|
+
code: str | None
|
|
15
|
+
size: str
|
|
16
|
+
|
|
17
|
+
# --- Regests
|
|
9
18
|
def request_api(
|
|
10
19
|
endpoint: str,
|
|
11
20
|
method: str = "GET",
|
|
@@ -28,7 +37,7 @@ def request_api(
|
|
|
28
37
|
Response from api.
|
|
29
38
|
"""
|
|
30
39
|
if not token:
|
|
31
|
-
token = helpers.
|
|
40
|
+
token = helpers.fget_token()
|
|
32
41
|
url = f"{config.get_api_url()}{endpoint}"
|
|
33
42
|
with Progress(SpinnerColumn(), TextColumn("[progress.description]{task.description}"), transient=True) if not quiet else nullcontext() as progress:
|
|
34
43
|
if progress:
|
|
@@ -52,7 +61,6 @@ def request_api(
|
|
|
52
61
|
error = response.json().get("error")
|
|
53
62
|
if error: print(f"[dim]Error reason: {error}[/dim]")
|
|
54
63
|
except JSONDecodeError: pass
|
|
55
|
-
config.cliconf_save(token="")
|
|
56
64
|
print("[yellow]Your session has expired. Please run 'glimpse login' again [/yellow].")
|
|
57
65
|
raise typer.Exit(1)
|
|
58
66
|
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")
|
|
@@ -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,16 @@ 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/
|
|
178
|
-
data = response.json()
|
|
179
|
-
|
|
180
|
-
print(f"
|
|
181
|
-
print(f"Build
|
|
182
|
-
print(f"
|
|
180
|
+
token = helpers.fget_token()
|
|
181
|
+
repo_id = helpers.fget_repo_id()
|
|
182
|
+
response = api.request_api(f"/cli/repos/status/{repo_id}", token=token)
|
|
183
|
+
data: api.StatusResponse = response.json()
|
|
184
|
+
print(f"Repository id: [dark_cyan]{repo_id}[/dark_cyan]")
|
|
185
|
+
print(f"Build status: {utils.enrich_status(data.get('status'))}")
|
|
186
|
+
if data.get("code"): print(f"Build code: [dark_red]{data['code']}[/dark_red]")
|
|
187
|
+
print(f"Build timestamp: [not bold dark_blue]{data.get('timestamp', '?')}[/not bold dark_blue]")
|
|
188
|
+
print(f"Build size: [not bold dark_blue]{data.get('size', '?')}[/not bold dark_blue]")
|
|
189
|
+
print(f"Repository details: {config.get_api_url()}/repos/details/{repo_id}")
|
|
183
190
|
|
|
184
191
|
# --- remove
|
|
185
192
|
@app.command()
|
|
@@ -187,11 +194,11 @@ def remove(
|
|
|
187
194
|
force: bool = typer.Option(False, "--force", "-f", help="Remove without prompting.")
|
|
188
195
|
):
|
|
189
196
|
"""Remove current repository from GitGlimpse."""
|
|
190
|
-
token = helpers.
|
|
191
|
-
|
|
192
|
-
print(f"[dim]Current repository id: '{
|
|
197
|
+
token = helpers.fget_token()
|
|
198
|
+
repo_id = helpers.fget_repo_id()
|
|
199
|
+
print(f"[dim]Current repository id: '{repo_id}'[/dim]")
|
|
193
200
|
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/{
|
|
201
|
+
api.request_api(f"/cli/repos/remove/{repo_id}", method="POST", token=token, handle_codes=[204])
|
|
195
202
|
config.repoconf_remove()
|
|
196
203
|
print("Removed repository from GitGlimpse.")
|
|
197
204
|
|
|
@@ -201,13 +208,13 @@ def build(
|
|
|
201
208
|
force: bool = typer.Option(False, "--force", "-f", help="Schedule without prompting.")
|
|
202
209
|
):
|
|
203
210
|
"""Schedule a build for current repository."""
|
|
204
|
-
token = helpers.
|
|
205
|
-
|
|
211
|
+
token = helpers.fget_token()
|
|
212
|
+
repo_id = helpers.fget_repo_id()
|
|
206
213
|
if not force:
|
|
207
214
|
print("Ensure that you pushed recent changes to GitHub.")
|
|
208
215
|
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/{
|
|
216
|
+
print(f"[dim]Scheduling a build for current repository (id: '{repo_id}')[/dim]")
|
|
217
|
+
response = api.request_api(f"/cli/repos/build/{repo_id}", method="POST", token=token, handle_codes=[202, 420, 425])
|
|
211
218
|
if response.status_code == 420:
|
|
212
219
|
print(f"[yellow]You have reached your usage limits.[/yellow]")
|
|
213
220
|
try:
|
|
@@ -219,36 +226,56 @@ def build(
|
|
|
219
226
|
print(f"[yellow]This repository already has a pending build.[/yellow]")
|
|
220
227
|
raise typer.Exit(1)
|
|
221
228
|
# response.status_code == 202
|
|
222
|
-
helpers.poll_build_status(token,
|
|
229
|
+
helpers.poll_build_status(token, repo_id)
|
|
223
230
|
|
|
224
231
|
# --- config
|
|
225
232
|
config_app = typer.Typer(help="Configure your cli.", no_args_is_help=True)
|
|
226
233
|
app.add_typer(config_app, name="config")
|
|
227
234
|
|
|
228
|
-
@config_app.command("
|
|
229
|
-
def
|
|
230
|
-
|
|
235
|
+
@config_app.command("list")
|
|
236
|
+
def config_list(
|
|
237
|
+
sensitive: bool = typer.Option(False, "--show-sensitive", help="Display sensitive data."),
|
|
238
|
+
local: bool = typer.Option(None, "--local/--global", help="Display only local or global config.")
|
|
239
|
+
):
|
|
240
|
+
"""Get current cli config."""
|
|
241
|
+
sensitive_keys = ["token", "repo_id"]
|
|
242
|
+
lconf = config._repoconf_load() or {}
|
|
243
|
+
gconf = config._cliconf_load() or {}
|
|
244
|
+
if local is None:
|
|
245
|
+
print("[bold]Current cli config[/bold]")
|
|
246
|
+
elif local:
|
|
247
|
+
print("[bold]Current LOCAL cli config[/bold]")
|
|
248
|
+
else:
|
|
249
|
+
print("[bold]Current GLOBAL cli config[/bold]")
|
|
250
|
+
if local != False:
|
|
251
|
+
for key, val in lconf.items():
|
|
252
|
+
val = f"[dim][{key.upper()}][/dim]" if not sensitive and key in sensitive_keys else val
|
|
253
|
+
print(f"{key}: {val}")
|
|
254
|
+
if local != True:
|
|
255
|
+
for key, val in gconf.items():
|
|
256
|
+
if local is None and key in lconf: continue
|
|
257
|
+
val = f"[dim][{key.upper()}][/dim]" if not sensitive and key in sensitive_keys else val
|
|
258
|
+
print(f"{key}: {val}")
|
|
259
|
+
|
|
260
|
+
@config_app.command("url")
|
|
261
|
+
def config_url(
|
|
262
|
+
url: str = typer.Argument(..., help="Api base url (e.g., http://localhost:8000 or https://gitglimpse.sutac.pl)"),
|
|
263
|
+
local: bool = typer.Option(False, "--local", "-l", help="Save config to local repository only.")
|
|
231
264
|
):
|
|
232
265
|
"""Set the active api server url."""
|
|
233
|
-
config.
|
|
266
|
+
config.conf_save({"api_url": (url if url else None)}, local)
|
|
234
267
|
if url:
|
|
235
268
|
print(f"Api url updated to: {url}")
|
|
236
269
|
else:
|
|
237
270
|
print("Api url unset.")
|
|
238
271
|
|
|
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
272
|
@config_app.command("debug")
|
|
247
273
|
def config_debug(
|
|
248
|
-
|
|
249
|
-
)
|
|
274
|
+
enabled: bool = typer.Argument(..., help="True to enable debug mode, False to disable."),
|
|
275
|
+
local: bool = typer.Option(False, "--local", "-l", help="Save config to local repository only.")
|
|
276
|
+
):
|
|
250
277
|
"""Enable or disable verbose debug output and full crash stack traces."""
|
|
251
|
-
config.
|
|
278
|
+
config.conf_save({"debug": enabled}, local)
|
|
252
279
|
status = "[bold green]enabled[/bold green]" if enabled else "[bold yellow]disabled[/bold yellow]"
|
|
253
280
|
print(f"Debug mode {status}.")
|
|
254
281
|
|
|
@@ -7,7 +7,7 @@ name = "git-glimpse-cli"
|
|
|
7
7
|
authors = [
|
|
8
8
|
{ name="sutaC", email="contact@sutac.pl" },
|
|
9
9
|
]
|
|
10
|
-
version = "0.1.
|
|
10
|
+
version = "0.1.3"
|
|
11
11
|
description = "CLI tool to manage and update shared GitHub repos with GitGlimpse."
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
requires-python = ">=3.10"
|
|
@@ -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.1 → git_glimpse_cli-0.1.3}/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
|