From e23f56e81c9d70560e9e47b741785849eef8398b Mon Sep 17 00:00:00 2001 From: 6543 <6543@noreply.gitea.io> Date: Fri, 2 Oct 2020 15:57:48 +0000 Subject: [PATCH] Add Detail View for Login (#212) Impruve & Refactor AddLogin Impruve login comands Remove unused Package + Vars Co-authored-by: 6543 <6543@obermui.de> Reviewed-on: https://gitea.com/gitea/tea/pulls/212 Reviewed-by: Norwin Reviewed-by: Andrew Thornton --- cmd/login.go | 29 +++++++++++++++- cmd/login/add.go | 26 +++++++------- cmd/login/list.go | 5 +-- main.go | 6 ---- modules/config/login.go | 71 ++++++++++++++++++-------------------- modules/print/login.go | 41 ++++++++++++++++++++++ modules/setting/setting.go | 11 ------ modules/utils/parse.go | 2 +- 8 files changed, 119 insertions(+), 72 deletions(-) create mode 100644 modules/print/login.go delete mode 100644 modules/setting/setting.go diff --git a/cmd/login.go b/cmd/login.go index 26010d2..c65c66c 100644 --- a/cmd/login.go +++ b/cmd/login.go @@ -5,7 +5,11 @@ package cmd import ( + "fmt" + "code.gitea.io/tea/cmd/login" + "code.gitea.io/tea/modules/config" + "code.gitea.io/tea/modules/print" "github.com/urfave/cli/v2" ) @@ -16,7 +20,8 @@ var CmdLogin = cli.Command{ Aliases: []string{"login"}, Usage: "Log in to a Gitea server", Description: `Log in to a Gitea server`, - Action: login.RunLoginAddInteractive, // TODO show list if no arg & detail if login as arg + ArgsUsage: "[]", + Action: runLogins, Subcommands: []*cli.Command{ &login.CmdLoginList, &login.CmdLoginAdd, @@ -24,3 +29,25 @@ var CmdLogin = cli.Command{ &login.CmdLoginSetDefault, }, } + +func runLogins(ctx *cli.Context) error { + if ctx.Args().Len() == 1 { + return runLoginDetail(ctx.Args().First()) + } + return login.RunLoginList(ctx) +} + +func runLoginDetail(name string) error { + if err := config.LoadConfig(); err != nil { + return err + } + + l := config.GetLoginByName(name) + if l == nil { + fmt.Printf("Login '%s' do not exist\n\n", name) + return nil + } + + print.LoginDetails(l) + return nil +} diff --git a/cmd/login/add.go b/cmd/login/add.go index 2b1cc17..96dbde0 100644 --- a/cmd/login/add.go +++ b/cmd/login/add.go @@ -15,7 +15,7 @@ import ( var CmdLoginAdd = cli.Command{ Name: "add", Usage: "Add a Gitea login", - Description: `Add a Gitea login`, + Description: `Add a Gitea login, without args it will create one interactively`, Flags: []cli.Flag{ &cli.StringFlag{ Name: "name", @@ -23,12 +23,11 @@ var CmdLoginAdd = cli.Command{ Usage: "Login name", }, &cli.StringFlag{ - Name: "url", - Aliases: []string{"u"}, - Value: "https://try.gitea.io", - EnvVars: []string{"GITEA_SERVER_URL"}, - Usage: "Server URL", - Required: true, + Name: "url", + Aliases: []string{"u"}, + Value: "https://gitea.com", + EnvVars: []string{"GITEA_SERVER_URL"}, + Usage: "Server URL", }, &cli.StringFlag{ Name: "token", @@ -65,7 +64,12 @@ var CmdLoginAdd = cli.Command{ } func runLoginAdd(ctx *cli.Context) error { - // TODO: if no args -> interactive + // if no args create login interactive + if ctx.Args().Len() == 0 { + return interact.CreateLogin() + } + + // else use args to add login return config.AddLogin( ctx.String("name"), ctx.String("token"), @@ -75,9 +79,3 @@ func runLoginAdd(ctx *cli.Context) error { ctx.String("url"), ctx.Bool("insecure")) } - -// RunLoginAddInteractive create login interactive -// TODO: should be unexported -func RunLoginAddInteractive(_ *cli.Context) error { - return interact.CreateLogin() -} diff --git a/cmd/login/list.go b/cmd/login/list.go index 5359265..a49397e 100644 --- a/cmd/login/list.go +++ b/cmd/login/list.go @@ -21,11 +21,12 @@ var CmdLoginList = cli.Command{ Aliases: []string{"list"}, Usage: "List Gitea logins", Description: `List Gitea logins`, - Action: runLoginList, + Action: RunLoginList, Flags: []cli.Flag{&flags.OutputFlag}, } -func runLoginList(ctx *cli.Context) error { +// RunLoginList list all logins +func RunLoginList(ctx *cli.Context) error { err := config.LoadConfig() if err != nil { log.Fatal(err) diff --git a/main.go b/main.go index d382016..5f5d2b7 100644 --- a/main.go +++ b/main.go @@ -11,7 +11,6 @@ import ( "strings" "code.gitea.io/tea/cmd" - "code.gitea.io/tea/modules/setting" "github.com/urfave/cli/v2" ) @@ -22,11 +21,6 @@ var Version = "development" // Tags holds the build tags used var Tags = "" -func init() { - setting.AppVer = Version - setting.AppBuiltWith = formatBuiltWith(Tags) -} - func main() { app := cli.NewApp() app.Name = "tea" diff --git a/modules/config/login.go b/modules/config/login.go index e781918..9d37510 100644 --- a/modules/config/login.go +++ b/modules/config/login.go @@ -13,6 +13,7 @@ import ( "net/http/cookiejar" "net/url" "os" + "strings" "time" "code.gitea.io/tea/modules/utils" @@ -30,8 +31,10 @@ type Login struct { // optional path to the private key SSHKey string `yaml:"ssh_key"` Insecure bool `yaml:"insecure"` - // optional gitea username + // User is username from gitea User string `yaml:"user"` + // Created is auto created unix timestamp + Created int64 `yaml:"created"` } // Client returns a client to operate Gitea API @@ -120,9 +123,29 @@ func GetLoginByName(name string) *Login { // AddLogin add login to config ( global var & file) func AddLogin(name, token, user, passwd, sshKey, giteaURL string, insecure bool) error { + // checks ... + // ... if we have a url if len(giteaURL) == 0 { log.Fatal("You have to input Gitea server URL") } + + err := LoadConfig() + if err != nil { + log.Fatal("Unable to load config file " + yamlConfigPath) + } + + for _, l := range Config.Logins { + // ... if there already exist a login with same name + if strings.ToLower(l.Name) == strings.ToLower(name) { + return fmt.Errorf("login name '%s' has already been used", l.Name) + } + // ... if we already use this token + if l.Token == token { + return fmt.Errorf("token already been used, delete login '%s' first", l.Name) + } + } + + // .. if we have enough information to authenticate if len(token) == 0 && (len(user)+len(passwd)) == 0 { log.Fatal("No token set") } else if len(user) != 0 && len(passwd) == 0 { @@ -131,22 +154,19 @@ func AddLogin(name, token, user, passwd, sshKey, giteaURL string, insecure bool) log.Fatal("No user set") } + // Normalize URL serverURL, err := utils.NormalizeURL(giteaURL) if err != nil { log.Fatal("Unable to parse URL", err) } - err = LoadConfig() - if err != nil { - log.Fatal("Unable to load config file " + yamlConfigPath) - } - login := Login{ Name: name, URL: serverURL.String(), Token: token, Insecure: insecure, SSHKey: sshKey, + Created: time.Now().Unix(), } if len(token) == 0 { @@ -156,6 +176,7 @@ func AddLogin(name, token, user, passwd, sshKey, giteaURL string, insecure bool) } } + // Verify if authentication works and get user info u, _, err := login.Client().GetMyUserInfo() if err != nil { log.Fatal(err) @@ -169,11 +190,14 @@ func AddLogin(name, token, user, passwd, sshKey, giteaURL string, insecure bool) } } - err = addLoginToConfig(login) - if err != nil { - log.Fatal(err) - } + // we do not have a method to get SSH config from api, + // so we just use the hostname + login.SSHHost = serverURL.Hostname() + // save login to global var + Config.Logins = append(Config.Logins, login) + + // save login to config file err = SaveConfig() if err != nil { log.Fatal(err) @@ -223,33 +247,6 @@ func GenerateLoginName(url, user string) (string, error) { return name, nil } -// addLoginToConfig add a login to global Config var -func addLoginToConfig(login Login) error { - for _, l := range Config.Logins { - if l.Name == login.Name { - if l.URL == login.URL && l.Token == login.Token { - return nil - } - return errors.New("Login name has already been used") - } - if l.URL == login.URL && l.Token == login.Token { - return errors.New("Login for this URL and token already exists") - } - } - - if len(login.SSHHost) == 0 { - u, err := url.Parse(login.URL) - if err != nil { - return err - } - login.SSHHost = u.Hostname() - } - - Config.Logins = append(Config.Logins, login) - - return nil -} - // InitCommand returns repository and *Login based on flags func InitCommand(repoValue, loginValue, remoteValue string) (*Login, string, string) { var login *Login diff --git a/modules/print/login.go b/modules/print/login.go new file mode 100644 index 0000000..4801212 --- /dev/null +++ b/modules/print/login.go @@ -0,0 +1,41 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package print + +import ( + "fmt" + "strings" + "time" + + "code.gitea.io/tea/modules/config" + + "github.com/charmbracelet/glamour" +) + +// LoginDetails print login entry to stdout +func LoginDetails(login *config.Login) { + + in := fmt.Sprintf("# %s\n\n[@%s](%s/%s)\n", + login.Name, + login.User, + strings.TrimSuffix(login.URL, "/"), + login.User, + ) + if len(login.SSHKey) != 0 { + in += fmt.Sprintf("\nSSH Key: '%s' via %s\n", + login.SSHKey, + login.SSHHost, + ) + } + in += fmt.Sprintf("\nCreated: %s", time.Unix(login.Created, 0).Format(time.RFC822)) + + out, err := glamour.Render(in, getGlamourTheme()) + if err != nil { + // TODO: better Error handling + fmt.Printf("Error:\n%v\n\n", err) + return + } + fmt.Print(out) +} diff --git a/modules/setting/setting.go b/modules/setting/setting.go deleted file mode 100644 index 6fd97f7..0000000 --- a/modules/setting/setting.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2018 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package setting - -// App related variables -var ( - AppVer string - AppBuiltWith string -) diff --git a/modules/utils/parse.go b/modules/utils/parse.go index e3e9395..41e88ae 100644 --- a/modules/utils/parse.go +++ b/modules/utils/parse.go @@ -24,7 +24,7 @@ func NormalizeURL(raw string) (*url.URL, error) { if !strings.HasPrefix(raw, "http") { prefix = "https://" } - return url.Parse(prefix + raw) + return url.Parse(strings.TrimSuffix(prefix+raw, "/")) } // GetOwnerAndRepo return repoOwner and repoName