Add token skeleton command
This commit is contained in:
@@ -397,10 +397,12 @@ def normalize_v3_token(config: WorkspaceConfig, raw_token: dict) -> dict | None:
|
||||
return None
|
||||
|
||||
token_id = raw_token.get("token_id") or raw_token.get("id") or raw_token.get("token_ref")
|
||||
token_value = raw_token.get("value") or raw_token.get("token")
|
||||
token_value = raw_token.get("value")
|
||||
if token_value is None:
|
||||
token_value = raw_token.get("token")
|
||||
if not isinstance(token_id, str) or not token_id:
|
||||
return None
|
||||
if not isinstance(token_value, str) or not token_value:
|
||||
if not isinstance(token_value, str):
|
||||
return None
|
||||
|
||||
server_record = normalize_server_record(config, raw_token.get("server", {}))
|
||||
@@ -1154,7 +1156,7 @@ def token_store_rows(store_servers: dict[str, dict]) -> list[dict[str, str]]:
|
||||
for row in server_entry.get("tokens", []):
|
||||
token_value = row.get("token_value", "")
|
||||
token_id = row.get("token_id", "")
|
||||
if token_value and token_id:
|
||||
if token_id:
|
||||
rows.append(
|
||||
{
|
||||
"endpoint": endpoint,
|
||||
@@ -1620,6 +1622,48 @@ def run_tokens_stats(config: WorkspaceConfig, args: argparse.Namespace) -> None:
|
||||
print_status_counts(status_counts)
|
||||
|
||||
|
||||
def run_tokens_add(config: WorkspaceConfig, args: argparse.Namespace) -> None:
|
||||
server_url = (args.server or config.git.base_url).rstrip("/")
|
||||
server_info = server_info_from_url(config, server_url)
|
||||
if server_info is None:
|
||||
raise SystemExit(f"Only http/https server URLs are supported: {server_url}")
|
||||
|
||||
token_data = load_token_store(config)
|
||||
existing_token = find_token_record(token_data, server_info["endpoint"], args.token_id)
|
||||
if existing_token is not None:
|
||||
raise SystemExit(f"Token already exists in tokens.json: {server_info['endpoint']}:{args.token_id}")
|
||||
|
||||
token_record = {
|
||||
"token_id": args.token_id,
|
||||
"value": args.value or "",
|
||||
"server": server_record_from_info(server_info),
|
||||
"remotes": [],
|
||||
}
|
||||
if args.user:
|
||||
token_record["user"] = args.user
|
||||
if args.remote:
|
||||
token_record["remotes"].append(
|
||||
{
|
||||
"name": args.remote,
|
||||
"org": args.org or "",
|
||||
"repo": args.repo_name or "",
|
||||
}
|
||||
)
|
||||
|
||||
print(f"token_path\t{config.token_path}")
|
||||
print(f"server\t{server_info['endpoint']}")
|
||||
print(f"token_id\t{args.token_id}")
|
||||
print(f"value\t{'set' if token_record['value'] else 'empty'}")
|
||||
print(f"remote\t{args.remote or ''}")
|
||||
print(f"status\t{'dry-run' if args.dry_run else 'added'}")
|
||||
|
||||
if args.dry_run:
|
||||
return
|
||||
|
||||
token_data.setdefault("tokens", []).append(token_record)
|
||||
write_token_store(config, token_data)
|
||||
|
||||
|
||||
def run_tokens_write(config: WorkspaceConfig, args: argparse.Namespace) -> None:
|
||||
repo_path = resolve_repo_argument(args.repo)
|
||||
repo_root = git_repo_root(repo_path)
|
||||
@@ -1648,6 +1692,8 @@ def run_tokens_write(config: WorkspaceConfig, args: argparse.Namespace) -> None:
|
||||
server_endpoint = token_server_endpoint(token_record)
|
||||
token_id = str(token_record.get("token_id", ""))
|
||||
token_value = str(token_record.get("value", ""))
|
||||
if not token_value:
|
||||
raise SystemExit(f"Token value is empty in tokens.json: {server_endpoint}:{token_id}")
|
||||
|
||||
final_url = credentialed_remote_url(target_url, token_id, token_value)
|
||||
status = "added" if existing_remote_url is None else "updated"
|
||||
@@ -1971,7 +2017,7 @@ def print_main_overview(config_path: Path) -> None:
|
||||
["list-cards", "[series]", "list cards in a selected series"],
|
||||
["tmux-container", "[series] [card]", "start tmux with container in pane 0"],
|
||||
["submission", "[series] [card] --class K --nick N", "prepare answer repo and student branch"],
|
||||
["tokens", "scan|read|stats|write|update", "manage tokens.json and Git remote credentials"],
|
||||
["tokens", "scan|add|read|stats|write|update", "manage tokens.json and Git remote credentials"],
|
||||
],
|
||||
)
|
||||
print()
|
||||
@@ -2008,6 +2054,7 @@ def print_tokens_overview() -> None:
|
||||
["command", "common options", "direction", "purpose"],
|
||||
[
|
||||
["scan", "[--repo PATH]", "read-only", "print token table with remote/store marker and auth masks"],
|
||||
["add", "TOKEN_ID", "tokens.json", "add an empty token skeleton for manual editing"],
|
||||
["read", "[--server ENDPOINT]", "tokens.json", "show servers, token ids and remotes"],
|
||||
["stats", "[--repo PATH]", "repo + tokens.json", "compare remote URLs with local token store"],
|
||||
["write", "--remote R [--replace]", "tokens.json -> repo", "write selected token into a remote URL"],
|
||||
@@ -2126,6 +2173,19 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
tokens_read_parser.add_argument("--server", help="Filter output to one server endpoint.")
|
||||
tokens_read_parser.add_argument("--show-secrets", action="store_true", help="Print full token values.")
|
||||
|
||||
tokens_add_parser = tokens_subparsers.add_parser(
|
||||
"add",
|
||||
help="Add an empty token skeleton to tokens.json.",
|
||||
)
|
||||
tokens_add_parser.add_argument("token_id", help="Token id, for example 't1' or 'r6'.")
|
||||
tokens_add_parser.add_argument("--server", help="Server endpoint. Default: git.base_url from workspace.json.")
|
||||
tokens_add_parser.add_argument("--value", default="", help="Optional token value. Default: empty for manual editing.")
|
||||
tokens_add_parser.add_argument("--user", help="Optional API user label.")
|
||||
tokens_add_parser.add_argument("--remote", help="Optional remote name to attach to this token.")
|
||||
tokens_add_parser.add_argument("--org", help="Optional remote organization.")
|
||||
tokens_add_parser.add_argument("--repo", dest="repo_name", help="Optional remote repository.")
|
||||
tokens_add_parser.add_argument("--dry-run", action="store_true", help="Print the planned token without writing it.")
|
||||
|
||||
tokens_stats_parser = tokens_subparsers.add_parser(
|
||||
"stats",
|
||||
help="Print per-server token statistics from tokens.json.",
|
||||
@@ -2197,6 +2257,9 @@ def main() -> int:
|
||||
if args.tokens_command == "scan":
|
||||
run_tokens_scan(config, args)
|
||||
return 0
|
||||
if args.tokens_command == "add":
|
||||
run_tokens_add(config, args)
|
||||
return 0
|
||||
if args.tokens_command == "read":
|
||||
run_tokens_read(config, args)
|
||||
return 0
|
||||
|
||||
Reference in New Issue
Block a user