From 46f2f44118cc333d4bf2f26bbad6d291afb3d9a6 Mon Sep 17 00:00:00 2001 From: mpabi Date: Wed, 29 Apr 2026 02:21:59 +0200 Subject: [PATCH] Auto-rename origin during token sync --- README.md | 64 +++++++++++++++++++++++---------------------------- doc/rvctl.md | 3 +++ doc/tokens.md | 3 +++ rvctl.py | 45 +++++++++++++++++++++++++++++++++++- 4 files changed, 79 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index f63fcb8..a3e9615 100644 --- a/README.md +++ b/README.md @@ -191,15 +191,6 @@ git clone http://77.90.8.171:3001/edu-tools/rv-launcher.git cd rv-launcher ``` -Etap 3: zmień nazwę remota z `origin` na `r1`: - -```bash -git remote rename origin r1 -``` - -`tokens.json` jest mapowany na nazwy git remotes, dlatego repo launchera ma -używać remota `r1`. - Po `git clone` workspace wygląda tak: ```text @@ -210,7 +201,7 @@ Po `git clone` workspace wygląda tak: └── tokens.json ``` -Etap 4: sprawdź store i wpisz credentials ze store do remota `r1`: +Etap 3: sprawdź store i wpisz credentials ze store do remota `r1`: ```bash ./rvctl tokens list store @@ -220,6 +211,8 @@ Etap 4: sprawdź store i wpisz credentials ze store do remota `r1`: `tokens list store` sprawdza, czy skopiowany `tokens.json` zawiera wpis dla remota `r1`. `tokens sync store r1` bierze token ze store i wpisuje credentials do git remota `r1`, tak aby kolejne operacje Git mogły używać tego tokena. +Jeżeli po `git clone` repo ma tylko remote `origin` wskazujący to samo repo, +`rvctl` automatycznie przemianuje go na `r1`. `list store` powinien pokazać token ze store: @@ -235,6 +228,7 @@ item source kind server proto host org repo use ```text repo_root /home/user/dev/workspace/rv/tools/rv-launcher remote r1 +renamed_from origin server http://77.90.8.171:3001 user u1 id r1 @@ -242,7 +236,7 @@ status updated url http://77.90.8.171:3001/edu-tools/rv-launcher.git ``` -Etap 5: odśwież metadane tokena i porównaj store z remote: +Etap 4: odśwież metadane tokena i porównaj store z remote: ```bash ./rvctl tokens update r1 @@ -263,7 +257,7 @@ item server proto host org repo user remote tok 1 gitea http 77.90.8.171:3001 edu-tools rv-launcher u1 r1 r1 * e59cc...13be forever ``` -Etap 6: po operacjach Git możesz usunąć sekret z `.git/config`, zostawiając +Etap 5: po operacjach Git możesz usunąć sekret z `.git/config`, zostawiając token tylko w store: ```bash @@ -281,6 +275,29 @@ item server proto host org repo user remote tok 1 gitea http 77.90.8.171:3001 edu-tools rv-launcher u1 r1 r1 S e59cc...13be forever ``` +## Szybki start + +Najpierw zobacz konfigurację i dostępne komendy: + +```bash +./rvctl +./rvctl show-config +``` + +Typowy przepływ pracy: + +```bash +./rvctl tokens compare +./rvctl list-series +./rvctl list-cards inf +./rvctl tmux-container inf 03 --dry-run +./rvctl tmux-container inf 03 --session rv-inf03 --attach +./rvctl submission inf 03 --class 4i --nick u1 +``` + +`--dry-run` jest przydatny przy sprawdzaniu planu uruchomienia lub konfiguracji +repo, zanim narzędzie coś zmieni. + ### Po pobraniu kart pracy Karty trafiają do `series` w workspace: @@ -320,29 +337,6 @@ Repozytoria źródłowe poza workspace, na przykład `~/dev/edu/repos/rv`, są zapleczem dla autora materiałów albo fallbackiem dla narzędzi. Nie są wymagane do zwykłej pracy w workspace. -## Szybki start - -Najpierw zobacz konfigurację i dostępne komendy: - -```bash -./rvctl -./rvctl show-config -``` - -Typowy przepływ pracy: - -```bash -./rvctl tokens compare -./rvctl list-series -./rvctl list-cards inf -./rvctl tmux-container inf 03 --dry-run -./rvctl tmux-container inf 03 --session rv-inf03 --attach -./rvctl submission inf 03 --class 4i --nick u1 -``` - -`--dry-run` jest przydatny przy sprawdzaniu planu uruchomienia lub konfiguracji -repo, zanim narzędzie coś zmieni. - ## Dokumentacja - `doc/rvctl.md` - techniczna dokumentacja CLI: wszystkie komendy, argumenty diff --git a/doc/rvctl.md b/doc/rvctl.md index 56f806e..2c1aa38 100644 --- a/doc/rvctl.md +++ b/doc/rvctl.md @@ -447,6 +447,9 @@ Zapisuje dane auth z rekordu `REMOTE_ID` w `tokens.json` do git remote o tej samej nazwie. Jeśli remote jeszcze nie istnieje, URL jest budowany z pól `server.endpoint`, `org` i `repo` w `tokens.json`. +Jeżeli repo ma tylko remote `origin` wskazujący ten sam URL, `sync store` +automatycznie przemianuje `origin` na `REMOTE_ID` przed wpisaniem credentials. + Przełączniki: - `--repo PATH` diff --git a/doc/tokens.md b/doc/tokens.md index f7a744c..62b57da 100644 --- a/doc/tokens.md +++ b/doc/tokens.md @@ -136,6 +136,9 @@ Jeśli remote `r1` nie istnieje, `rvctl` buduje URL z pól `server.endpoint`, http://77.90.8.171:3001/edu-tools/rv-launcher.git ``` +Jeżeli w repo istnieje tylko `origin` wskazujący ten sam URL, `sync store r1` +automatycznie przemianuje `origin` na `r1`, a potem wpisze credentials. + Opcjonalnie można podać URL ręcznie: ```bash diff --git a/rvctl.py b/rvctl.py index 5f28150..75c910e 100755 --- a/rvctl.py +++ b/rvctl.py @@ -1939,6 +1939,35 @@ def remote_url_from_token_record(token_record: dict) -> str: return f"{endpoint}/{quote(owner, safe='')}/{quote(repo_name, safe='')}" +def remote_urls_point_to_same_repo(left_url: str, right_url: str) -> bool: + try: + left_sanitized, _ = sanitize_remote_url(left_url) + right_sanitized, _ = sanitize_remote_url(right_url) + except SystemExit: + return False + return left_sanitized.rstrip("/") == right_sanitized.rstrip("/") + + +def find_origin_rename_candidate( + config: WorkspaceConfig, + repo_root: Path, + target_remote: str, + target_url: str, +) -> tuple[str, str] | None: + origin_remote = config.git.origin_remote + if not origin_remote or origin_remote == target_remote: + return None + if git_capture(repo_root, ["remote", "get-url", target_remote]) is not None: + return None + + origin_url = git_capture(repo_root, ["remote", "get-url", origin_remote]) + if not origin_url: + return None + if not remote_urls_point_to_same_repo(origin_url, target_url): + return None + return origin_remote, origin_url + + def resolve_repo_argument(repo_arg: str | None) -> Path: return Path(repo_arg).expanduser().resolve() if repo_arg else Path.cwd().resolve() @@ -2171,6 +2200,7 @@ def run_tokens_sync(config: WorkspaceConfig, args: argparse.Namespace) -> None: args.repo = str(repo_path) args.remote = args.remote_id args.token_name = args.remote_id + args.auto_rename_origin = True run_tokens_write(config, args) return raise SystemExit(f"Unsupported tokens sync direction: {args.direction}") @@ -2255,11 +2285,17 @@ def run_tokens_write(config: WorkspaceConfig, args: argparse.Namespace) -> None: f"Missing target remote URL and tokens.json has no org/repo for: {server_endpoint}:{remote_id}" ) + rename_candidate = None + if getattr(args, "auto_rename_origin", False) and existing_remote_url is None: + rename_candidate = find_origin_rename_candidate(config, repo_root, args.remote, target_url) + if rename_candidate: + _, existing_remote_url = rename_candidate + final_url = credentialed_remote_url(target_url, user_name, token_value) status = "added" if existing_remote_url is None else "updated" existing_credentials = remote_credentials(existing_remote_url) if existing_remote_url else None if existing_credentials == (user_name, token_value): - status = "unchanged" + status = "renamed" if rename_candidate else "unchanged" elif existing_credentials is not None and not args.replace: raise SystemExit( f"Remote '{args.remote}' already has different credentials. " @@ -2268,6 +2304,8 @@ def run_tokens_write(config: WorkspaceConfig, args: argparse.Namespace) -> None: print(f"repo_root\t{repo_root}") print(f"remote\t{args.remote}") + if rename_candidate: + print(f"renamed_from\t{rename_candidate[0]}") print(f"server\t{server_endpoint}") print(f"user\t{user_name}") print(f"id\t{remote_id}") @@ -2277,6 +2315,11 @@ def run_tokens_write(config: WorkspaceConfig, args: argparse.Namespace) -> None: if args.dry_run or status == "unchanged": return + if rename_candidate: + subprocess.run( + ["git", "-C", str(repo_root), "remote", "rename", rename_candidate[0], args.remote], + check=True, + ) set_git_remote(repo_root, args.remote, final_url)