Add token remove command
This commit is contained in:
@@ -159,6 +159,8 @@ Podstawowe komendy tokenow:
|
|||||||
./rvctl tokens sync remote r1
|
./rvctl tokens sync remote r1
|
||||||
./rvctl tokens update r1
|
./rvctl tokens update r1
|
||||||
./rvctl tokens sync store r1
|
./rvctl tokens sync store r1
|
||||||
|
./rvctl tokens remove store r1
|
||||||
|
./rvctl tokens remove remote r1
|
||||||
./rvctl tokens add r1
|
./rvctl tokens add r1
|
||||||
./rvctl tokens read
|
./rvctl tokens read
|
||||||
./rvctl tokens stats --repo ~/dev/workspace/rv/series/inf/03
|
./rvctl tokens stats --repo ~/dev/workspace/rv/series/inf/03
|
||||||
@@ -166,6 +168,8 @@ Podstawowe komendy tokenow:
|
|||||||
|
|
||||||
`tokens scan` wypisuje tabele `tokens` i niczego nie zapisuje: jeden wiersz na
|
`tokens scan` wypisuje tabele `tokens` i niczego nie zapisuje: jeden wiersz na
|
||||||
logiczny remote tokena.
|
logiczny remote tokena.
|
||||||
|
`tokens.json` synchronizujemy z repo `rv-launcher`; remotes kart pracy i
|
||||||
|
odpowiedzi sa generowane jako pochodne tego ustawienia.
|
||||||
`token_ref` laczy nazwe tokena z markerem po prawej stronie: `*` oznacza, ze
|
`token_ref` laczy nazwe tokena z markerem po prawej stronie: `*` oznacza, ze
|
||||||
remote i `tokens.json` sa zgodne, `R` oznacza token tylko w remote, a `S`
|
remote i `tokens.json` sa zgodne, `R` oznacza token tylko w remote, a `S`
|
||||||
token tylko w `tokens.json`. Kolumny `scope`, `org` i `repo` sa maskami
|
token tylko w `tokens.json`. Kolumny `scope`, `org` i `repo` sa maskami
|
||||||
@@ -173,6 +177,8 @@ uprawnien; bez zgodnego wpisu maja wartosc `?????????`, `?????` albo `????`.
|
|||||||
Zapis z remote do `tokens.json` robi `tokens sync remote r1`.
|
Zapis z remote do `tokens.json` robi `tokens sync remote r1`.
|
||||||
Odczyt `valid` i uprawnien z API robi `tokens update r1`.
|
Odczyt `valid` i uprawnien z API robi `tokens update r1`.
|
||||||
Zapis z `tokens.json` do remota robi `tokens sync store r1`.
|
Zapis z `tokens.json` do remota robi `tokens sync store r1`.
|
||||||
|
Usuniecie wpisu robi `tokens remove store r1`, a usuniecie git remota
|
||||||
|
`tokens remove remote r1`.
|
||||||
Kolumna `valid` oznacza, czy token zostal zaakceptowany przez API teraz.
|
Kolumna `valid` oznacza, czy token zostal zaakceptowany przez API teraz.
|
||||||
Jesli przy tokenie w `tokens.json` zapiszesz `expires_at`, `valid` moze pokazac
|
Jesli przy tokenie w `tokens.json` zapiszesz `expires_at`, `valid` moze pokazac
|
||||||
date wygasniecia; bez daty poprawny token pokazuje `forever`.
|
date wygasniecia; bez daty poprawny token pokazuje `forever`.
|
||||||
|
|||||||
+27
-2
@@ -299,7 +299,7 @@ pokazuje jeden logiczny wiersz na token. Komenda jest read-only.
|
|||||||
Przelaczniki:
|
Przelaczniki:
|
||||||
|
|
||||||
- `--repo PATH`
|
- `--repo PATH`
|
||||||
Sciezka wewnatrz docelowego repo. Domyslnie biezacy katalog.
|
Sciezka wewnatrz docelowego repo. Domyslnie repo zawierajace `rvctl`.
|
||||||
|
|
||||||
Typowy wynik:
|
Typowy wynik:
|
||||||
|
|
||||||
@@ -369,7 +369,7 @@ pobiera metadanych z API.
|
|||||||
Przelaczniki:
|
Przelaczniki:
|
||||||
|
|
||||||
- `--repo PATH`
|
- `--repo PATH`
|
||||||
Sciezka wewnatrz docelowego repo. Domyslnie biezacy katalog.
|
Sciezka wewnatrz docelowego repo. Domyslnie repo zawierajace `rvctl`.
|
||||||
- `--dry-run`
|
- `--dry-run`
|
||||||
Pokazuje plan bez zapisu.
|
Pokazuje plan bez zapisu.
|
||||||
|
|
||||||
@@ -404,6 +404,31 @@ Przyklad:
|
|||||||
./rvctl tokens sync store r1 --repo ~/dev/workspace/rv/series/inf/03
|
./rvctl tokens sync store r1 --repo ~/dev/workspace/rv/series/inf/03
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## `tokens remove store|remote|both REMOTE_ID`
|
||||||
|
|
||||||
|
Usuwa rekord z `tokens.json`, git remote albo oba miejsca.
|
||||||
|
Domyslnym repo dla `remote` i `both` jest repo, w ktorym lezy `rvctl`. Inne
|
||||||
|
repo mozna wskazac przez `--repo PATH`.
|
||||||
|
|
||||||
|
Przelaczniki:
|
||||||
|
|
||||||
|
- `--repo PATH`
|
||||||
|
Repo, z ktorego ma byc usuniety git remote. Domyslnie repo zawierajace
|
||||||
|
`rvctl`.
|
||||||
|
- `--server ENDPOINT`
|
||||||
|
Endpoint serwera, jesli `tokens.json` ma kilka rekordow o tym samym `id`.
|
||||||
|
- `--dry-run`
|
||||||
|
Pokazuje plan bez usuwania.
|
||||||
|
|
||||||
|
Przyklady:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./rvctl tokens remove store r1
|
||||||
|
./rvctl tokens remove remote r1
|
||||||
|
./rvctl tokens remove both r1
|
||||||
|
./rvctl tokens remove remote r1 --repo ~/dev/workspace/rv/series/inf/03
|
||||||
|
```
|
||||||
|
|
||||||
## `tokens read`
|
## `tokens read`
|
||||||
|
|
||||||
Pokazuje zawartosc `tokens/tokens.json` w podziale na endpointy serwerow.
|
Pokazuje zawartosc `tokens/tokens.json` w podziale na endpointy serwerow.
|
||||||
|
|||||||
+25
-2
@@ -17,6 +17,10 @@ Sa dwa miejsca, w ktorych moga byc zapisane dane dostepowe:
|
|||||||
`tokens update r1` nie synchronizuje sekretu; tylko pobiera z API metadane
|
`tokens update r1` nie synchronizuje sekretu; tylko pobiera z API metadane
|
||||||
tokenu: `valid`, `scope`, `org_perm` i `repo_perm`.
|
tokenu: `valid`, `scope`, `org_perm` i `repo_perm`.
|
||||||
|
|
||||||
|
W podstawowym flow `tokens.json` synchronizujemy z repo `rv-launcher`. Remoty
|
||||||
|
kart pracy i repo odpowiedzi sa generowane jako pochodne konfiguracji launchera,
|
||||||
|
nie jako osobne zrodla prawdy dla tokenow.
|
||||||
|
|
||||||
## Format `tokens.json`
|
## Format `tokens.json`
|
||||||
|
|
||||||
Aktualny format to `version: 3`. Glownym rekordem jest remote-token. Pole
|
Aktualny format to `version: 3`. Glownym rekordem jest remote-token. Pole
|
||||||
@@ -177,7 +181,7 @@ Read-only. Czyta remote URL-e i `tokens.json`, a potem wypisuje tabele
|
|||||||
### `tokens sync remote REMOTE_ID`
|
### `tokens sync remote REMOTE_ID`
|
||||||
|
|
||||||
Kopiuje dane dostepowe z git remote do `tokens.json`. Nie pobiera metadanych z
|
Kopiuje dane dostepowe z git remote do `tokens.json`. Nie pobiera metadanych z
|
||||||
API.
|
API. Bez `--repo` czyta repo zawierajace `rvctl`.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./rvctl tokens sync remote r1
|
./rvctl tokens sync remote r1
|
||||||
@@ -197,13 +201,32 @@ Nie zmienia git remote URL-a i nie kopiuje sekretu z remote.
|
|||||||
### `tokens sync store REMOTE_ID`
|
### `tokens sync store REMOTE_ID`
|
||||||
|
|
||||||
Zapisuje dane z rekordu `REMOTE_ID` w `tokens.json` do git remote o tej samej
|
Zapisuje dane z rekordu `REMOTE_ID` w `tokens.json` do git remote o tej samej
|
||||||
nazwie.
|
nazwie. Bez `--repo` zapisuje do repo zawierajacego `rvctl`.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./rvctl tokens sync store r1 --repo ~/dev/workspace/rv/series/inf/03
|
./rvctl tokens sync store r1 --repo ~/dev/workspace/rv/series/inf/03
|
||||||
./rvctl tokens sync store r1 --repo PATH --replace
|
./rvctl tokens sync store r1 --repo PATH --replace
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `tokens remove store|remote|both REMOTE_ID`
|
||||||
|
|
||||||
|
Usuwa rekord `REMOTE_ID` z `tokens.json`, git remote albo oba miejsca.
|
||||||
|
Domyslnym repo dla `remote` i `both` jest repo, w ktorym lezy `rvctl`. Inne
|
||||||
|
repo mozna wskazac przez `--repo PATH`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./rvctl tokens remove store r1
|
||||||
|
./rvctl tokens remove remote r1
|
||||||
|
./rvctl tokens remove both r1
|
||||||
|
./rvctl tokens remove remote r1 --repo ~/dev/workspace/rv/series/inf/03
|
||||||
|
```
|
||||||
|
|
||||||
|
Przelaczniki:
|
||||||
|
|
||||||
|
- `--server ENDPOINT` - rozroznia rekord w `tokens.json`, jezeli ten sam `id` wystepuje dla wielu serwerow
|
||||||
|
- `--repo PATH` - repo, z ktorego usuwany jest git remote
|
||||||
|
- `--dry-run` - pokazuje plan bez usuwania
|
||||||
|
|
||||||
### `tokens read`
|
### `tokens read`
|
||||||
|
|
||||||
Pokazuje zawartosc `tokens.json`.
|
Pokazuje zawartosc `tokens.json`.
|
||||||
|
|||||||
@@ -1736,6 +1736,19 @@ def resolve_repo_argument(repo_arg: str | None) -> Path:
|
|||||||
return Path(repo_arg).expanduser().resolve() if repo_arg else Path.cwd().resolve()
|
return Path(repo_arg).expanduser().resolve() if repo_arg else Path.cwd().resolve()
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_launcher_repo_argument(repo_arg: str | None) -> Path:
|
||||||
|
return Path(repo_arg).expanduser().resolve() if repo_arg else Path(__file__).resolve().parent
|
||||||
|
|
||||||
|
|
||||||
|
def safe_remote_url_label(remote_url: str | None) -> str:
|
||||||
|
if not remote_url:
|
||||||
|
return ""
|
||||||
|
split_url = urlsplit(remote_url)
|
||||||
|
if split_url.scheme in {"http", "https"} and split_url.hostname is not None:
|
||||||
|
return sanitize_remote_url(remote_url)[0]
|
||||||
|
return remote_url
|
||||||
|
|
||||||
|
|
||||||
def run_tokens_scan(config: WorkspaceConfig, args: argparse.Namespace) -> None:
|
def run_tokens_scan(config: WorkspaceConfig, args: argparse.Namespace) -> None:
|
||||||
repo_path = resolve_repo_argument(args.repo)
|
repo_path = resolve_repo_argument(args.repo)
|
||||||
token_data = load_token_store(config, write_normalized=False)
|
token_data = load_token_store(config, write_normalized=False)
|
||||||
@@ -1808,18 +1821,123 @@ def run_tokens_stats(config: WorkspaceConfig, args: argparse.Namespace) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def print_token_action_result(result: dict[str, str]) -> None:
|
def print_token_action_result(result: dict[str, str]) -> None:
|
||||||
for field_name in ["repo_root", "remote", "server", "user", "org", "repo", "valid", "status"]:
|
for field_name in ["repo_root", "token_path", "remote", "server", "user", "org", "repo", "valid", "url", "removed", "status"]:
|
||||||
field_value = result.get(field_name)
|
field_value = result.get(field_name)
|
||||||
if field_value is not None:
|
if field_value is not None:
|
||||||
print(f"{field_name}\t{field_value}")
|
print(f"{field_name}\t{field_value}")
|
||||||
|
|
||||||
|
|
||||||
|
def remove_token_from_store(
|
||||||
|
config: WorkspaceConfig,
|
||||||
|
remote_id: str,
|
||||||
|
endpoint: str | None = None,
|
||||||
|
dry_run: bool = False,
|
||||||
|
) -> dict[str, str]:
|
||||||
|
token_data = load_token_store(config, write_normalized=False)
|
||||||
|
matches = []
|
||||||
|
for index, token_record in enumerate(token_data.get("tokens", [])):
|
||||||
|
if token_record_id(token_record) != remote_id:
|
||||||
|
continue
|
||||||
|
if endpoint and token_server_endpoint(token_record) != endpoint:
|
||||||
|
continue
|
||||||
|
matches.append((index, token_record))
|
||||||
|
|
||||||
|
if not matches:
|
||||||
|
return {
|
||||||
|
"token_path": str(config.token_path),
|
||||||
|
"remote": remote_id,
|
||||||
|
"server": endpoint or "",
|
||||||
|
"removed": "0",
|
||||||
|
"status": "missing",
|
||||||
|
}
|
||||||
|
if len(matches) > 1 and not endpoint:
|
||||||
|
available = ", ".join(sorted(token_server_endpoint(token_record) for _, token_record in matches))
|
||||||
|
raise SystemExit(f"Multiple tokens with id '{remote_id}'. Pass --server. Available: {available}")
|
||||||
|
|
||||||
|
removed_indexes = {index for index, _ in matches}
|
||||||
|
first_record = matches[0][1]
|
||||||
|
if not dry_run:
|
||||||
|
token_data["tokens"] = [
|
||||||
|
token_record
|
||||||
|
for index, token_record in enumerate(token_data.get("tokens", []))
|
||||||
|
if index not in removed_indexes
|
||||||
|
]
|
||||||
|
write_token_store(config, token_data)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"token_path": str(config.token_path),
|
||||||
|
"remote": remote_id,
|
||||||
|
"server": token_server_endpoint(first_record),
|
||||||
|
"user": str(first_record.get("user", "")),
|
||||||
|
"org": str(first_record.get("org", "")),
|
||||||
|
"repo": str(first_record.get("repo", "")),
|
||||||
|
"removed": str(len(matches)),
|
||||||
|
"status": "dry-run" if dry_run else "removed",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def remove_git_remote(repo_path: Path, remote_id: str, dry_run: bool = False) -> dict[str, str]:
|
||||||
|
repo_root = git_repo_root(repo_path)
|
||||||
|
if repo_root is None:
|
||||||
|
raise SystemExit(f"Missing git repo at path: {repo_path}")
|
||||||
|
|
||||||
|
remote_url = git_capture(repo_root, ["remote", "get-url", remote_id])
|
||||||
|
if not remote_url:
|
||||||
|
return {
|
||||||
|
"repo_root": str(repo_root),
|
||||||
|
"remote": remote_id,
|
||||||
|
"removed": "0",
|
||||||
|
"status": "missing",
|
||||||
|
}
|
||||||
|
|
||||||
|
if not dry_run:
|
||||||
|
subprocess.run(
|
||||||
|
["git", "-C", str(repo_root), "remote", "remove", remote_id],
|
||||||
|
check=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"repo_root": str(repo_root),
|
||||||
|
"remote": remote_id,
|
||||||
|
"url": safe_remote_url_label(remote_url),
|
||||||
|
"removed": "1",
|
||||||
|
"status": "dry-run" if dry_run else "removed",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def run_tokens_remove(config: WorkspaceConfig, args: argparse.Namespace) -> None:
|
||||||
|
if args.target == "store":
|
||||||
|
result = remove_token_from_store(config, args.remote_id, args.server, args.dry_run)
|
||||||
|
print_token_action_result(result)
|
||||||
|
return
|
||||||
|
|
||||||
|
if args.target == "remote":
|
||||||
|
result = remove_git_remote(resolve_launcher_repo_argument(args.repo), args.remote_id, args.dry_run)
|
||||||
|
print_token_action_result(result)
|
||||||
|
return
|
||||||
|
|
||||||
|
if args.target == "both":
|
||||||
|
repo_path = resolve_launcher_repo_argument(args.repo)
|
||||||
|
if not args.dry_run:
|
||||||
|
remove_token_from_store(config, args.remote_id, args.server, dry_run=True)
|
||||||
|
remote_result = remove_git_remote(repo_path, args.remote_id, args.dry_run)
|
||||||
|
print_token_action_result(remote_result)
|
||||||
|
print()
|
||||||
|
store_result = remove_token_from_store(config, args.remote_id, args.server, args.dry_run)
|
||||||
|
print_token_action_result(store_result)
|
||||||
|
return
|
||||||
|
|
||||||
|
raise SystemExit(f"Unsupported tokens remove target: {args.target}")
|
||||||
|
|
||||||
|
|
||||||
def run_tokens_sync(config: WorkspaceConfig, args: argparse.Namespace) -> None:
|
def run_tokens_sync(config: WorkspaceConfig, args: argparse.Namespace) -> None:
|
||||||
|
repo_path = resolve_launcher_repo_argument(args.repo)
|
||||||
if args.direction == "remote":
|
if args.direction == "remote":
|
||||||
result = sync_token_from_remote(config, resolve_repo_argument(args.repo), args.remote_id, args.dry_run)
|
result = sync_token_from_remote(config, repo_path, args.remote_id, args.dry_run)
|
||||||
print_token_action_result(result)
|
print_token_action_result(result)
|
||||||
return
|
return
|
||||||
if args.direction == "store":
|
if args.direction == "store":
|
||||||
|
args.repo = str(repo_path)
|
||||||
args.remote = args.remote_id
|
args.remote = args.remote_id
|
||||||
args.token_name = args.remote_id
|
args.token_name = args.remote_id
|
||||||
run_tokens_write(config, args)
|
run_tokens_write(config, args)
|
||||||
@@ -2227,7 +2345,7 @@ def print_main_overview(config_path: Path) -> None:
|
|||||||
["list-cards", "[series]", "list cards in a selected series"],
|
["list-cards", "[series]", "list cards in a selected series"],
|
||||||
["tmux-container", "[series] [card]", "start tmux with container in pane 0"],
|
["tmux-container", "[series] [card]", "start tmux with container in pane 0"],
|
||||||
["submission", "[series] [card] --class K --nick N", "prepare answer repo and student branch"],
|
["submission", "[series] [card] --class K --nick N", "prepare answer repo and student branch"],
|
||||||
["tokens", "scan|sync|update|add|read|stats|write", "manage tokens.json and Git remote credentials"],
|
["tokens", "scan|sync|update|remove|add|read|stats|write", "manage tokens.json and Git remote credentials"],
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
print()
|
print()
|
||||||
@@ -2269,6 +2387,7 @@ def print_tokens_overview() -> None:
|
|||||||
["stats", "[--repo PATH]", "repo + tokens.json", "compare remote URLs with local token store"],
|
["stats", "[--repo PATH]", "repo + tokens.json", "compare remote URLs with local token store"],
|
||||||
["sync remote", "REMOTE_ID [--repo PATH]", "repo -> tokens.json", "copy one remote URL into the store"],
|
["sync remote", "REMOTE_ID [--repo PATH]", "repo -> tokens.json", "copy one remote URL into the store"],
|
||||||
["sync store", "REMOTE_ID [--repo PATH]", "tokens.json -> repo", "write one store record into a remote URL"],
|
["sync store", "REMOTE_ID [--repo PATH]", "tokens.json -> repo", "write one store record into a remote URL"],
|
||||||
|
["remove", "store|remote|both REMOTE_ID", "selected", "remove token store record or Git remote"],
|
||||||
["write", "--remote R [--replace]", "tokens.json -> repo", "write selected token into a remote URL"],
|
["write", "--remote R [--replace]", "tokens.json -> repo", "write selected token into a remote URL"],
|
||||||
["update", "REMOTE_ID", "API -> tokens.json", "refresh valid/scope/org/repo metadata"],
|
["update", "REMOTE_ID", "API -> tokens.json", "refresh valid/scope/org/repo metadata"],
|
||||||
],
|
],
|
||||||
@@ -2282,6 +2401,8 @@ def print_tokens_overview() -> None:
|
|||||||
["read remote r1 into store", "./rvctl tokens sync remote r1"],
|
["read remote r1 into store", "./rvctl tokens sync remote r1"],
|
||||||
["refresh r1 metadata", "./rvctl tokens update r1"],
|
["refresh r1 metadata", "./rvctl tokens update r1"],
|
||||||
["write store r1 to remote", "./rvctl tokens sync store r1 --repo PATH"],
|
["write store r1 to remote", "./rvctl tokens sync store r1 --repo PATH"],
|
||||||
|
["remove r1 from store", "./rvctl tokens remove store r1"],
|
||||||
|
["remove Git remote r1", "./rvctl tokens remove remote r1"],
|
||||||
["scan selected card", "./rvctl tokens scan --repo ~/dev/workspace/rv/series/inf/03"],
|
["scan selected card", "./rvctl tokens scan --repo ~/dev/workspace/rv/series/inf/03"],
|
||||||
["compare state", "./rvctl tokens stats --repo ~/dev/workspace/rv/series/inf/03"],
|
["compare state", "./rvctl tokens stats --repo ~/dev/workspace/rv/series/inf/03"],
|
||||||
["write auth to r1", "./rvctl tokens write --repo PATH --remote r1 --server URL"],
|
["write auth to r1", "./rvctl tokens write --repo PATH --remote r1 --server URL"],
|
||||||
@@ -2414,12 +2535,28 @@ def build_parser() -> argparse.ArgumentParser:
|
|||||||
)
|
)
|
||||||
tokens_sync_parser.add_argument("direction", choices=["remote", "store"], help="'remote' reads git remote into store; 'store' writes store into git remote.")
|
tokens_sync_parser.add_argument("direction", choices=["remote", "store"], help="'remote' reads git remote into store; 'store' writes store into git remote.")
|
||||||
tokens_sync_parser.add_argument("remote_id", help="Remote id, for example 'r1' or 'r1a'.")
|
tokens_sync_parser.add_argument("remote_id", help="Remote id, for example 'r1' or 'r1a'.")
|
||||||
add_repo_option(tokens_sync_parser)
|
tokens_sync_parser.add_argument(
|
||||||
|
"--repo",
|
||||||
|
help="Path inside a target git repo. Default: repo containing rvctl.",
|
||||||
|
)
|
||||||
tokens_sync_parser.add_argument("--url", help="Target remote URL used when direction is 'store' and the remote does not exist yet.")
|
tokens_sync_parser.add_argument("--url", help="Target remote URL used when direction is 'store' and the remote does not exist yet.")
|
||||||
add_store_selection_options(tokens_sync_parser)
|
add_store_selection_options(tokens_sync_parser)
|
||||||
tokens_sync_parser.add_argument("--replace", action="store_true", help="Replace different credentials when writing store -> remote.")
|
tokens_sync_parser.add_argument("--replace", action="store_true", help="Replace different credentials when writing store -> remote.")
|
||||||
tokens_sync_parser.add_argument("--dry-run", action="store_true", help="Print the planned sync without writing it.")
|
tokens_sync_parser.add_argument("--dry-run", action="store_true", help="Print the planned sync without writing it.")
|
||||||
|
|
||||||
|
tokens_remove_parser = tokens_subparsers.add_parser(
|
||||||
|
"remove",
|
||||||
|
help="Remove a token store record, a Git remote, or both.",
|
||||||
|
)
|
||||||
|
tokens_remove_parser.add_argument("target", choices=["store", "remote", "both"], help="Where to remove REMOTE_ID from.")
|
||||||
|
tokens_remove_parser.add_argument("remote_id", help="Remote id, for example 'r1' or 'r1a'.")
|
||||||
|
tokens_remove_parser.add_argument(
|
||||||
|
"--repo",
|
||||||
|
help="Path inside a target git repo for target remote/both. Default: repo containing rvctl.",
|
||||||
|
)
|
||||||
|
tokens_remove_parser.add_argument("--server", help="Server endpoint used to disambiguate store records.")
|
||||||
|
tokens_remove_parser.add_argument("--dry-run", action="store_true", help="Print the planned removal without writing it.")
|
||||||
|
|
||||||
tokens_write_parser = tokens_subparsers.add_parser(
|
tokens_write_parser = tokens_subparsers.add_parser(
|
||||||
"write",
|
"write",
|
||||||
help="Write credentials from tokens.json into a repo remote URL.",
|
help="Write credentials from tokens.json into a repo remote URL.",
|
||||||
@@ -2496,6 +2633,9 @@ def main() -> int:
|
|||||||
if args.tokens_command == "sync":
|
if args.tokens_command == "sync":
|
||||||
run_tokens_sync(config, args)
|
run_tokens_sync(config, args)
|
||||||
return 0
|
return 0
|
||||||
|
if args.tokens_command == "remove":
|
||||||
|
run_tokens_remove(config, args)
|
||||||
|
return 0
|
||||||
if args.tokens_command == "write":
|
if args.tokens_command == "write":
|
||||||
run_tokens_write(config, args)
|
run_tokens_write(config, args)
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
Reference in New Issue
Block a user