A terminal client for Tangled.
tui go tangled cli
8

Configure Feed

Select the types of activity you want to include in your feed.

gitutil: extract tangled remote URL helper

Aly Raffauf (Jul 8, 2026, 9:56 AM EDT) 217e49fb 282b3706

+34 -12
+5 -1
internal/cli/repo_clone.go
··· 28 28 } 29 29 30 30 fmt.Printf("Cloning %s/%s into %s...\n", handle, repo, dest) 31 - if err := gitutil.CloneRepo(ctx, handle, repo, dest); err != nil { 31 + if err := gitutil.CloneRepo(ctx, gitutil.CloneRepoParams{ 32 + Handle: handle, 33 + Repo: repo, 34 + RepoDir: dest, 35 + }); err != nil { 32 36 return fmt.Errorf("clone %q: %w", args[0], err) 33 37 } 34 38 return nil
+5 -1
internal/cli/repo_create.go
··· 69 69 fmt.Printf("Created repository %s/%s\n", handle, args[0]) 70 70 71 71 if repoCreateClone { 72 - if err := gitutil.CloneRepo(ctx, handle, args[0], args[0]); err != nil { 72 + if err := gitutil.CloneRepo(ctx, gitutil.CloneRepoParams{ 73 + Handle: handle, 74 + Repo: args[0], 75 + RepoDir: args[0], 76 + }); err != nil { 73 77 return fmt.Errorf("clone new repository: %w", err) 74 78 } 75 79 }
+1 -1
internal/gitutil/checkout_pull.go
··· 23 23 // CheckoutPull fetches the target branch as detached HEAD and applies 24 24 // the PR's gzipped patch blob on top, all inside params.RepoDir. 25 25 func CheckoutPull(ctx context.Context, params CheckoutPullParams) error { 26 - fetchURL := fmt.Sprintf("git@tangled.org:%s/%s", params.TargetHandle, params.TargetRepo) 26 + fetchURL := tangledRemoteURL(params.TargetHandle, params.TargetRepo) 27 27 if err := runIn(params.RepoDir, ctx, "git", "fetch", fetchURL, params.TargetBranch); err != nil { 28 28 return fmt.Errorf("fetch target branch: %w", err) 29 29 }
+11 -4
internal/gitutil/clone_repo.go
··· 2 2 3 3 import ( 4 4 "context" 5 - "fmt" 6 5 ) 7 6 8 - func CloneRepo(ctx context.Context, handle, repo, repoDir string) error { 9 - url := fmt.Sprintf("git@tangled.org:%s/%s", handle, repo) 10 - return run(ctx, "git", "clone", url, repoDir) 7 + // CloneRepoParams groups the inputs to CloneRepo. 8 + type CloneRepoParams struct { 9 + Handle string // Tangled owner handle 10 + Repo string // repository name 11 + RepoDir string // local directory to clone into 12 + } 13 + 14 + // CloneRepo clones handle/repo from Tangled into params.RepoDir. 15 + func CloneRepo(ctx context.Context, params CloneRepoParams) error { 16 + url := tangledRemoteURL(params.Handle, params.Repo) 17 + return run(ctx, "git", "clone", url, params.RepoDir) 11 18 }
+1 -1
internal/gitutil/push_repo.go
··· 15 15 // PushNewRepo adds a remote at Dir and pushes the current branch. 16 16 // Fails if RemoteName already exists. 17 17 func PushNewRepo(ctx context.Context, params PushNewRepoParams) error { 18 - remoteURL := fmt.Sprintf("git@tangled.org:%s/%s", params.Handle, params.Repo) 18 + remoteURL := tangledRemoteURL(params.Handle, params.Repo) 19 19 if err := runIn(params.Dir, ctx, "git", "remote", "add", params.RemoteName, remoteURL); err != nil { 20 20 return fmt.Errorf("add remote %q (already exists? use --remote to pick another name): %w", params.RemoteName, err) 21 21 }
+11 -4
internal/gitutil/repo_context.go
··· 7 7 "strings" 8 8 ) 9 9 10 + // tangledSSHPrefix is the SSH remote prefix for Tangled repositories. 11 + const tangledSSHPrefix = "git@tangled.org:" 12 + 13 + // tangledRemoteURL builds the SSH clone/push URL for a Tangled repo. 14 + func tangledRemoteURL(handle, repo string) string { 15 + return tangledSSHPrefix + handle + "/" + repo 16 + } 17 + 10 18 // RepoContext holds the handle and repo name parsed from a git remote URL. 11 19 type RepoContext struct { 12 20 Handle string ··· 24 32 25 33 url := strings.TrimSpace(string(output)) 26 34 27 - prefix := "git@tangled.org:" 28 - if !strings.HasPrefix(url, prefix) { 35 + if !strings.HasPrefix(url, tangledSSHPrefix) { 29 36 return nil, fmt.Errorf( 30 37 "remote URL %q does not look like a Tangled repo (expected %s<handle>/<repo>)", 31 - url, prefix, 38 + url, tangledSSHPrefix, 32 39 ) 33 40 } 34 41 35 - path := strings.TrimPrefix(url, prefix) 42 + path := strings.TrimPrefix(url, tangledSSHPrefix) 36 43 parts := strings.SplitN(path, "/", 2) 37 44 if len(parts) != 2 || parts[0] == "" || parts[1] == "" { 38 45 return nil, fmt.Errorf("could not parse handle/repo from %q", url)