@@ -3,6 +3,7 @@ package cli
33import (
44 "fmt"
55 "log"
6+ "net/url"
67 "strconv"
78 "strings"
89 "time"
@@ -71,6 +72,7 @@ func buildUserCreateCommand(cfg *config.CLIConfig) *cobra.Command {
7172 cmd .Flags ().StringVarP (& cfg .ConfigFile , "config" , "f" , "../test-users.yaml" , "配置文件路径" )
7273 cmd .Flags ().StringVar (& cfg .GitLabHost , "host" , "" , "GitLab 主机地址" )
7374 cmd .Flags ().StringVar (& cfg .GitLabToken , "token" , "" , "GitLab Personal Access Token" )
75+ cmd .Flags ().StringVar (& cfg .GitLabSSHEndpoint , "ssh-endpoint" , "" , "GitLab SSH endpoint (e.g., ssh://git@host:22)" )
7476 cmd .Flags ().StringVarP (& cfg .OutputFile , "output" , "o" , "" , "输出结果到 YAML 文件" )
7577 cmd .Flags ().StringVarP (& cfg .TemplateFile , "template" , "t" , "" , "使用模板文件格式化输出" )
7678
@@ -175,11 +177,25 @@ func runUserCreate(cfg *config.CLIConfig) error {
175177 // 从 GitLabHost 解析 endpoint、scheme、host 和 port
176178 endpoint , scheme , host , port := parseGitLabHostURL (cfg .GitLabHost )
177179
180+ // Parse SSH endpoint information for template rendering
181+ sshEndpoint , sshHost , sshPort := parseGitLabSSHEndpoint (cfg .GitLabSSHEndpoint )
182+
183+ // sshConfig holds parsed SSH endpoint details when available
184+ var sshConfig * types.SSHConfig
185+ if sshEndpoint != "" {
186+ sshConfig = & types.SSHConfig {
187+ Endpoint : sshEndpoint ,
188+ Host : sshHost ,
189+ Port : sshPort ,
190+ }
191+ }
192+
178193 output := & types.OutputConfig {
179194 Endpoint : endpoint ,
180195 Scheme : scheme ,
181196 Host : host ,
182197 Port : port ,
198+ SSH : sshConfig ,
183199 Users : userOutputs ,
184200 }
185201
@@ -495,6 +511,51 @@ func initializeClient(cfg *config.CLIConfig) (*client.GitLabClient, error) {
495511 return gitlabClient , nil
496512}
497513
514+ // parseGitLabSSHEndpoint extracts endpoint, host, and port from the SSH URL string
515+ func parseGitLabSSHEndpoint (rawEndpoint string ) (endpoint , host string , port int ) {
516+ // trimmedEndpoint stores the SSH endpoint without trailing slash or spaces
517+ trimmedEndpoint := strings .TrimSpace (rawEndpoint )
518+ if trimmedEndpoint == "" {
519+ return "" , "" , 0
520+ }
521+
522+ // normalizedEndpoint ensures the SSH URL includes a scheme for parsing
523+ normalizedEndpoint := strings .TrimSuffix (trimmedEndpoint , "/" )
524+ if ! strings .Contains (normalizedEndpoint , "://" ) {
525+ normalizedEndpoint = "ssh://" + normalizedEndpoint
526+ }
527+
528+ // parsedURL holds the parsed SSH URL result
529+ parsedURL , err := url .Parse (normalizedEndpoint )
530+ if err != nil {
531+ return normalizedEndpoint , "" , 0
532+ }
533+
534+ // hostName captures the hostname portion of the SSH URL
535+ hostName := parsedURL .Hostname ()
536+ // portNumber defaults to standard SSH port
537+ portNumber := 22
538+ if parsedURL .Port () != "" {
539+ if parsedPort , err := strconv .Atoi (parsedURL .Port ()); err == nil {
540+ portNumber = parsedPort
541+ } else {
542+ portNumber = 0
543+ }
544+ }
545+
546+ // endpointBuilder rebuilds the endpoint including user info when available
547+ endpointBuilder := parsedURL .Scheme + "://"
548+ if parsedURL .User != nil {
549+ endpointBuilder += parsedURL .User .String () + "@"
550+ }
551+ endpointBuilder += hostName
552+ if portNumber > 0 {
553+ endpointBuilder += ":" + strconv .Itoa (portNumber )
554+ }
555+
556+ return endpointBuilder , hostName , portNumber
557+ }
558+
498559// parseGitLabHostURL 从 GitLab Host URL 解析出 endpoint、scheme 和 host
499560func parseGitLabHostURL (gitlabHost string ) (endpoint , scheme , host string , port int ) {
500561 // 默认值
0 commit comments