@@ -3,6 +3,7 @@ package cli
33import (
44 "errors"
55 "fmt"
6+ "net/url"
67 "os"
78 "os/exec"
89 "path/filepath"
@@ -86,12 +87,26 @@ func parseGitHubRepoSlugFromURL(url string) string {
8687// Supports HTTPS (https://host[:port]/path), HTTP (http://host[:port]/path), and SSH (git@host[:port]:path or ssh://git@host[:port]/path) formats.
8788// Returns the host portion as "host[:port]" when parsed, or "github.com" as the default if the URL cannot be parsed.
8889func extractHostFromRemoteURL (remoteURL string ) string {
89- // HTTPS / HTTP format: https://host/path or http://host/path
90+ // HTTPS / HTTP format: https://[userinfo@]host/path or http://[userinfo@]host/path
91+ // Use net/url.Parse to correctly handle all userinfo variants (user@, user:pass@,
92+ // and passwords containing '@') and to extract the bare host without credentials.
9093 for _ , scheme := range []string {"https://" , "http://" } {
91- if after , ok := strings .CutPrefix (remoteURL , scheme ); ok {
94+ if strings .HasPrefix (remoteURL , scheme ) {
95+ if u , err := url .Parse (remoteURL ); err == nil && u .Host != "" {
96+ return u .Host
97+ }
98+ // Fallback: strip scheme and any userinfo manually.
99+ after := remoteURL [len (scheme ):]
92100 if host , _ , found := strings .Cut (after , "/" ); found {
101+ // Strip optional userinfo (everything up to and including the last '@').
102+ if idx := strings .LastIndex (host , "@" ); idx >= 0 {
103+ host = host [idx + 1 :]
104+ }
93105 return host
94106 }
107+ if idx := strings .LastIndex (after , "@" ); idx >= 0 {
108+ return after [idx + 1 :]
109+ }
95110 return after
96111 }
97112 }
0 commit comments