mirror of
				https://gitea.com/gitea/tea.git
				synced 2025-10-31 01:05:26 +01:00 
			
		
		
		
	fix InitCommand() (#285)
split modules/config login_tasks.go should probably be modules/task/login.go, but i didn't do that, as it still depends on the global `Config` variable from the config module, see https://gitea.com/gitea/tea/issues/158 rework InitCommand() - make it error tolerant if $PWD is not a git repo (#200) - don't force default login when repo flag is set (#191) remove InitCommandLoginOnly() Merge branch 'master' into issue-200-initcommand improve docs Merge branch 'master' into issue-200-initcommand move config func and config task func to right place Co-authored-by: Norwin Roosen <git@nroo.de> Co-authored-by: 6543 <6543@obermui.de> Reviewed-on: https://gitea.com/gitea/tea/pulls/285 Reviewed-by: 6543 <6543@obermui.de> Reviewed-by: khmarbaise <khmarbaise@noreply.gitea.io> Co-Authored-By: Norwin <noerw@noreply.gitea.io> Co-Committed-By: Norwin <noerw@noreply.gitea.io>
This commit is contained in:
		| @@ -34,7 +34,7 @@ var LoginFlag = cli.StringFlag{ | |||||||
| var RepoFlag = cli.StringFlag{ | var RepoFlag = cli.StringFlag{ | ||||||
| 	Name:        "repo", | 	Name:        "repo", | ||||||
| 	Aliases:     []string{"r"}, | 	Aliases:     []string{"r"}, | ||||||
| 	Usage:       "Repository to interact with. Optional", | 	Usage:       "Override local repository path or gitea repository slug to interact with. Optional", | ||||||
| 	Destination: &GlobalRepoValue, | 	Destination: &GlobalRepoValue, | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -47,6 +47,8 @@ func runNotifications(ctx *cli.Context) error { | |||||||
| 	var news []*gitea.NotificationThread | 	var news []*gitea.NotificationThread | ||||||
| 	var err error | 	var err error | ||||||
|  |  | ||||||
|  | 	login, owner, repo := config.InitCommand(flags.GlobalRepoValue, flags.GlobalLoginValue, flags.GlobalRemoteValue) | ||||||
|  |  | ||||||
| 	listOpts := flags.GetListOptions(ctx) | 	listOpts := flags.GetListOptions(ctx) | ||||||
| 	if listOpts.Page == 0 { | 	if listOpts.Page == 0 { | ||||||
| 		listOpts.Page = 1 | 		listOpts.Page = 1 | ||||||
| @@ -61,13 +63,11 @@ func runNotifications(ctx *cli.Context) error { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if ctx.Bool("all") { | 	if ctx.Bool("all") { | ||||||
| 		login := config.InitCommandLoginOnly(flags.GlobalLoginValue) |  | ||||||
| 		news, _, err = login.Client().ListNotifications(gitea.ListNotificationOptions{ | 		news, _, err = login.Client().ListNotifications(gitea.ListNotificationOptions{ | ||||||
| 			ListOptions: listOpts, | 			ListOptions: listOpts, | ||||||
| 			Status:      status, | 			Status:      status, | ||||||
| 		}) | 		}) | ||||||
| 	} else { | 	} else { | ||||||
| 		login, owner, repo := config.InitCommand(flags.GlobalRepoValue, flags.GlobalLoginValue, flags.GlobalRemoteValue) |  | ||||||
| 		news, _, err = login.Client().ListRepoNotifications(owner, repo, gitea.ListNotificationOptions{ | 		news, _, err = login.Client().ListRepoNotifications(owner, repo, gitea.ListNotificationOptions{ | ||||||
| 			ListOptions: listOpts, | 			ListOptions: listOpts, | ||||||
| 			Status:      status, | 			Status:      status, | ||||||
|   | |||||||
| @@ -24,8 +24,7 @@ var CmdOrganizationDelete = cli.Command{ | |||||||
|  |  | ||||||
| // RunOrganizationDelete delete user organization | // RunOrganizationDelete delete user organization | ||||||
| func RunOrganizationDelete(ctx *cli.Context) error { | func RunOrganizationDelete(ctx *cli.Context) error { | ||||||
| 	//TODO: Reconsider the usage InitCommandLoginOnly related to #200 | 	login, _, _ := config.InitCommand(flags.GlobalRepoValue, flags.GlobalLoginValue, flags.GlobalRemoteValue) | ||||||
| 	login := config.InitCommandLoginOnly(flags.GlobalLoginValue) |  | ||||||
|  |  | ||||||
| 	client := login.Client() | 	client := login.Client() | ||||||
|  |  | ||||||
|   | |||||||
| @@ -30,8 +30,7 @@ var CmdOrganizationList = cli.Command{ | |||||||
|  |  | ||||||
| // RunOrganizationList list user organizations | // RunOrganizationList list user organizations | ||||||
| func RunOrganizationList(ctx *cli.Context) error { | func RunOrganizationList(ctx *cli.Context) error { | ||||||
| 	//TODO: Reconsider the usage InitCommandLoginOnly related to #200 | 	login, _, _ := config.InitCommand(flags.GlobalRepoValue, flags.GlobalLoginValue, flags.GlobalRemoteValue) | ||||||
| 	login := config.InitCommandLoginOnly(flags.GlobalLoginValue) |  | ||||||
|  |  | ||||||
| 	client := login.Client() | 	client := login.Client() | ||||||
|  |  | ||||||
|   | |||||||
| @@ -39,9 +39,9 @@ func runRepos(ctx *cli.Context) error { | |||||||
| } | } | ||||||
|  |  | ||||||
| func runRepoDetail(path string) error { | func runRepoDetail(path string) error { | ||||||
| 	login := config.InitCommandLoginOnly(flags.GlobalLoginValue) | 	login, ownerFallback, _ := config.InitCommand(flags.GlobalRepoValue, flags.GlobalLoginValue, flags.GlobalRemoteValue) | ||||||
| 	client := login.Client() | 	client := login.Client() | ||||||
| 	repoOwner, repoName := utils.GetOwnerAndRepo(path, login.User) | 	repoOwner, repoName := utils.GetOwnerAndRepo(path, ownerFallback) | ||||||
| 	repo, _, err := client.GetRepo(repoOwner, repoName) | 	repo, _, err := client.GetRepo(repoOwner, repoName) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
|   | |||||||
| @@ -83,7 +83,7 @@ var CmdRepoCreate = cli.Command{ | |||||||
| } | } | ||||||
|  |  | ||||||
| func runRepoCreate(ctx *cli.Context) error { | func runRepoCreate(ctx *cli.Context) error { | ||||||
| 	login := config.InitCommandLoginOnly(flags.GlobalLoginValue) | 	login, _, _ := config.InitCommand(flags.GlobalRepoValue, flags.GlobalLoginValue, flags.GlobalRemoteValue) | ||||||
| 	client := login.Client() | 	client := login.Client() | ||||||
| 	var ( | 	var ( | ||||||
| 		repo *gitea.Repository | 		repo *gitea.Repository | ||||||
|   | |||||||
| @@ -45,7 +45,7 @@ var CmdReposList = cli.Command{ | |||||||
|  |  | ||||||
| // RunReposList list repositories | // RunReposList list repositories | ||||||
| func RunReposList(ctx *cli.Context) error { | func RunReposList(ctx *cli.Context) error { | ||||||
| 	login := config.InitCommandLoginOnly(flags.GlobalLoginValue) | 	login, _, _ := config.InitCommand(flags.GlobalRepoValue, flags.GlobalLoginValue, flags.GlobalRemoteValue) | ||||||
| 	client := login.Client() | 	client := login.Client() | ||||||
|  |  | ||||||
| 	typeFilter, err := getTypeFilter(ctx) | 	typeFilter, err := getTypeFilter(ctx) | ||||||
|   | |||||||
| @@ -57,7 +57,7 @@ var CmdReposSearch = cli.Command{ | |||||||
| } | } | ||||||
|  |  | ||||||
| func runReposSearch(ctx *cli.Context) error { | func runReposSearch(ctx *cli.Context) error { | ||||||
| 	login := config.InitCommandLoginOnly(flags.GlobalLoginValue) | 	login, _, _ := config.InitCommand(flags.GlobalRepoValue, flags.GlobalLoginValue, flags.GlobalRemoteValue) | ||||||
| 	client := login.Client() | 	client := login.Client() | ||||||
|  |  | ||||||
| 	var ownerID int64 | 	var ownerID int64 | ||||||
|   | |||||||
							
								
								
									
										130
									
								
								modules/config/command.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								modules/config/command.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,130 @@ | |||||||
|  | // 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 config | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"log" | ||||||
|  | 	"strings" | ||||||
|  |  | ||||||
|  | 	"code.gitea.io/tea/modules/git" | ||||||
|  | 	"code.gitea.io/tea/modules/utils" | ||||||
|  |  | ||||||
|  | 	gogit "github.com/go-git/go-git/v5" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // InitCommand resolves the application context, and returns the active login, and if | ||||||
|  | // available the repo slug. It does this by reading the config file for logins, parsing | ||||||
|  | // the remotes of the .git repo specified in repoFlag or $PWD, and using overrides from | ||||||
|  | // command flags. If a local git repo can't be found, repo slug values are unset. | ||||||
|  | func InitCommand(repoFlag, loginFlag, remoteFlag string) (login *Login, owner string, reponame string) { | ||||||
|  | 	err := LoadConfig() | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatal(err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var repoSlug string | ||||||
|  | 	var repoPath string // empty means PWD | ||||||
|  | 	var repoFlagPathExists bool | ||||||
|  |  | ||||||
|  | 	// check if repoFlag can be interpreted as path to local repo. | ||||||
|  | 	if len(repoFlag) != 0 { | ||||||
|  | 		repoFlagPathExists, err = utils.PathExists(repoFlag) | ||||||
|  | 		if err != nil { | ||||||
|  | 			log.Fatal(err.Error()) | ||||||
|  | 		} | ||||||
|  | 		if repoFlagPathExists { | ||||||
|  | 			repoPath = repoFlag | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// try to read git repo & extract context, ignoring if PWD is not a repo | ||||||
|  | 	login, repoSlug, err = contextFromLocalRepo(repoPath, remoteFlag) | ||||||
|  | 	if err != nil && err != gogit.ErrRepositoryNotExists { | ||||||
|  | 		log.Fatal(err.Error()) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// if repoFlag is not a path, use it to override repoSlug | ||||||
|  | 	if len(repoFlag) != 0 && !repoFlagPathExists { | ||||||
|  | 		repoSlug = repoFlag | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// override login from flag, or use default login if repo based detection failed | ||||||
|  | 	if len(loginFlag) != 0 { | ||||||
|  | 		login = GetLoginByName(loginFlag) | ||||||
|  | 		if login == nil { | ||||||
|  | 			log.Fatalf("Login name '%s' does not exist", loginFlag) | ||||||
|  | 		} | ||||||
|  | 	} else if login == nil { | ||||||
|  | 		if login, err = GetDefaultLogin(); err != nil { | ||||||
|  | 			log.Fatal(err.Error()) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// parse reposlug (owner falling back to login owner if reposlug contains only repo name) | ||||||
|  | 	owner, reponame = utils.GetOwnerAndRepo(repoSlug, login.User) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // discovers login & repo slug from the default branch remote of the given local repo | ||||||
|  | func contextFromLocalRepo(repoValue, remoteValue string) (*Login, string, error) { | ||||||
|  | 	repo, err := git.RepoFromPath(repoValue) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, "", err | ||||||
|  | 	} | ||||||
|  | 	gitConfig, err := repo.Config() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, "", err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// if no remote | ||||||
|  | 	if len(gitConfig.Remotes) == 0 { | ||||||
|  | 		return nil, "", errors.New("No remote(s) found in this Git repository") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// if only one remote exists | ||||||
|  | 	if len(gitConfig.Remotes) >= 1 && len(remoteValue) == 0 { | ||||||
|  | 		for remote := range gitConfig.Remotes { | ||||||
|  | 			remoteValue = remote | ||||||
|  | 		} | ||||||
|  | 		if len(gitConfig.Remotes) > 1 { | ||||||
|  | 			// if master branch is present, use it as the default remote | ||||||
|  | 			masterBranch, ok := gitConfig.Branches["master"] | ||||||
|  | 			if ok { | ||||||
|  | 				if len(masterBranch.Remote) > 0 { | ||||||
|  | 					remoteValue = masterBranch.Remote | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	remoteConfig, ok := gitConfig.Remotes[remoteValue] | ||||||
|  | 	if !ok || remoteConfig == nil { | ||||||
|  | 		return nil, "", errors.New("Remote " + remoteValue + " not found in this Git repository") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for _, l := range Config.Logins { | ||||||
|  | 		for _, u := range remoteConfig.URLs { | ||||||
|  | 			p, err := git.ParseURL(strings.TrimSpace(u)) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return nil, "", fmt.Errorf("Git remote URL parse failed: %s", err.Error()) | ||||||
|  | 			} | ||||||
|  | 			if strings.EqualFold(p.Scheme, "http") || strings.EqualFold(p.Scheme, "https") { | ||||||
|  | 				if strings.HasPrefix(u, l.URL) { | ||||||
|  | 					ps := strings.Split(p.Path, "/") | ||||||
|  | 					path := strings.Join(ps[len(ps)-2:], "/") | ||||||
|  | 					return &l, strings.TrimSuffix(path, ".git"), nil | ||||||
|  | 				} | ||||||
|  | 			} else if strings.EqualFold(p.Scheme, "ssh") { | ||||||
|  | 				if l.GetSSHHost() == strings.Split(p.Host, ":")[0] { | ||||||
|  | 					return &l, strings.TrimLeft(strings.TrimSuffix(p.Path, ".git"), "/"), nil | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil, "", errors.New("No Gitea login found. You might want to specify --repo (and --login) to work outside of a repository") | ||||||
|  | } | ||||||
| @@ -5,14 +5,11 @@ | |||||||
| package config | package config | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"errors" |  | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
| 	"log" | 	"log" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| 	"strings" |  | ||||||
|  |  | ||||||
| 	"code.gitea.io/tea/modules/git" |  | ||||||
| 	"code.gitea.io/tea/modules/utils" | 	"code.gitea.io/tea/modules/utils" | ||||||
|  |  | ||||||
| 	"github.com/adrg/xdg" | 	"github.com/adrg/xdg" | ||||||
| @@ -84,68 +81,3 @@ func SaveConfig() error { | |||||||
| 	} | 	} | ||||||
| 	return ioutil.WriteFile(ymlPath, bs, 0660) | 	return ioutil.WriteFile(ymlPath, bs, 0660) | ||||||
| } | } | ||||||
|  |  | ||||||
| func curGitRepoPath(repoValue, remoteValue string) (*Login, string, error) { |  | ||||||
| 	var err error |  | ||||||
| 	var repo *git.TeaRepo |  | ||||||
| 	if len(repoValue) == 0 { |  | ||||||
| 		repo, err = git.RepoForWorkdir() |  | ||||||
| 	} else { |  | ||||||
| 		repo, err = git.RepoFromPath(repoValue) |  | ||||||
| 	} |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, "", err |  | ||||||
| 	} |  | ||||||
| 	gitConfig, err := repo.Config() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, "", err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// if no remote |  | ||||||
| 	if len(gitConfig.Remotes) == 0 { |  | ||||||
| 		return nil, "", errors.New("No remote(s) found in this Git repository") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// if only one remote exists |  | ||||||
| 	if len(gitConfig.Remotes) >= 1 && len(remoteValue) == 0 { |  | ||||||
| 		for remote := range gitConfig.Remotes { |  | ||||||
| 			remoteValue = remote |  | ||||||
| 		} |  | ||||||
| 		if len(gitConfig.Remotes) > 1 { |  | ||||||
| 			// if master branch is present, use it as the default remote |  | ||||||
| 			masterBranch, ok := gitConfig.Branches["master"] |  | ||||||
| 			if ok { |  | ||||||
| 				if len(masterBranch.Remote) > 0 { |  | ||||||
| 					remoteValue = masterBranch.Remote |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	remoteConfig, ok := gitConfig.Remotes[remoteValue] |  | ||||||
| 	if !ok || remoteConfig == nil { |  | ||||||
| 		return nil, "", errors.New("Remote " + remoteValue + " not found in this Git repository") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for _, l := range Config.Logins { |  | ||||||
| 		for _, u := range remoteConfig.URLs { |  | ||||||
| 			p, err := git.ParseURL(strings.TrimSpace(u)) |  | ||||||
| 			if err != nil { |  | ||||||
| 				return nil, "", fmt.Errorf("Git remote URL parse failed: %s", err.Error()) |  | ||||||
| 			} |  | ||||||
| 			if strings.EqualFold(p.Scheme, "http") || strings.EqualFold(p.Scheme, "https") { |  | ||||||
| 				if strings.HasPrefix(u, l.URL) { |  | ||||||
| 					ps := strings.Split(p.Path, "/") |  | ||||||
| 					path := strings.Join(ps[len(ps)-2:], "/") |  | ||||||
| 					return &l, strings.TrimSuffix(path, ".git"), nil |  | ||||||
| 				} |  | ||||||
| 			} else if strings.EqualFold(p.Scheme, "ssh") { |  | ||||||
| 				if l.GetSSHHost() == strings.Split(p.Host, ":")[0] { |  | ||||||
| 					return &l, strings.TrimLeft(strings.TrimSuffix(p.Path, ".git"), "/"), nil |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil, "", errors.New("No Gitea login found. You might want to specify --repo (and --login) to work outside of a repository") |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -12,9 +12,6 @@ import ( | |||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/http/cookiejar" | 	"net/http/cookiejar" | ||||||
| 	"net/url" | 	"net/url" | ||||||
| 	"os" |  | ||||||
| 	"strings" |  | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"code.gitea.io/tea/modules/utils" | 	"code.gitea.io/tea/modules/utils" | ||||||
|  |  | ||||||
| @@ -37,6 +34,69 @@ type Login struct { | |||||||
| 	Created int64 `yaml:"created"` | 	Created int64 `yaml:"created"` | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // GetDefaultLogin return the default login | ||||||
|  | func GetDefaultLogin() (*Login, error) { | ||||||
|  | 	if len(Config.Logins) == 0 { | ||||||
|  | 		return nil, errors.New("No available login") | ||||||
|  | 	} | ||||||
|  | 	for _, l := range Config.Logins { | ||||||
|  | 		if l.Default { | ||||||
|  | 			return &l, nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return &Config.Logins[0], nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // GetLoginByName get login by name | ||||||
|  | func GetLoginByName(name string) *Login { | ||||||
|  | 	for _, l := range Config.Logins { | ||||||
|  | 		if l.Name == name { | ||||||
|  | 			return &l | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // GenerateLoginName generates a name string based on instance URL & adds username if the result is not unique | ||||||
|  | func GenerateLoginName(url, user string) (string, error) { | ||||||
|  | 	parsedURL, err := utils.NormalizeURL(url) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  | 	name := parsedURL.Host | ||||||
|  |  | ||||||
|  | 	// append user name if login name already exists | ||||||
|  | 	if len(user) != 0 { | ||||||
|  | 		for _, l := range Config.Logins { | ||||||
|  | 			if l.Name == name { | ||||||
|  | 				name += "_" + user | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return name, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // DeleteLogin delete a login by name | ||||||
|  | func DeleteLogin(name string) error { | ||||||
|  | 	var idx = -1 | ||||||
|  | 	for i, l := range Config.Logins { | ||||||
|  | 		if l.Name == name { | ||||||
|  | 			idx = i | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if idx == -1 { | ||||||
|  | 		return fmt.Errorf("can not delete login '%s', does not exist", name) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	Config.Logins = append(Config.Logins[:idx], Config.Logins[idx+1:]...) | ||||||
|  |  | ||||||
|  | 	return SaveConfig() | ||||||
|  | } | ||||||
|  |  | ||||||
| // Client returns a client to operate Gitea API | // Client returns a client to operate Gitea API | ||||||
| func (l *Login) Client() *gitea.Client { | func (l *Login) Client() *gitea.Client { | ||||||
| 	httpClient := &http.Client{} | 	httpClient := &http.Client{} | ||||||
| @@ -73,235 +133,3 @@ func (l *Login) GetSSHHost() string { | |||||||
|  |  | ||||||
| 	return u.Hostname() | 	return u.Hostname() | ||||||
| } | } | ||||||
|  |  | ||||||
| // GenerateToken creates a new token when given BasicAuth credentials |  | ||||||
| func (l *Login) GenerateToken(user, pass string) (string, error) { |  | ||||||
| 	client := l.Client() |  | ||||||
| 	gitea.SetBasicAuth(user, pass)(client) |  | ||||||
|  |  | ||||||
| 	host, _ := os.Hostname() |  | ||||||
| 	tl, _, err := client.ListAccessTokens(gitea.ListAccessTokensOptions{}) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return "", err |  | ||||||
| 	} |  | ||||||
| 	tokenName := host + "-tea" |  | ||||||
|  |  | ||||||
| 	for i := range tl { |  | ||||||
| 		if tl[i].Name == tokenName { |  | ||||||
| 			tokenName += time.Now().Format("2006-01-02_15-04-05") |  | ||||||
| 			break |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	t, _, err := client.CreateAccessToken(gitea.CreateAccessTokenOption{Name: tokenName}) |  | ||||||
| 	return t.Token, err |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // GetDefaultLogin return the default login |  | ||||||
| func GetDefaultLogin() (*Login, error) { |  | ||||||
| 	if len(Config.Logins) == 0 { |  | ||||||
| 		return nil, errors.New("No available login") |  | ||||||
| 	} |  | ||||||
| 	for _, l := range Config.Logins { |  | ||||||
| 		if l.Default { |  | ||||||
| 			return &l, nil |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return &Config.Logins[0], nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // GetLoginByName get login by name |  | ||||||
| func GetLoginByName(name string) *Login { |  | ||||||
| 	for _, l := range Config.Logins { |  | ||||||
| 		if l.Name == name { |  | ||||||
| 			return &l |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // 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(err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	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 { |  | ||||||
| 		log.Fatal("No password set") |  | ||||||
| 	} else if len(user) == 0 && len(passwd) != 0 { |  | ||||||
| 		log.Fatal("No user set") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Normalize URL |  | ||||||
| 	serverURL, err := utils.NormalizeURL(giteaURL) |  | ||||||
| 	if err != nil { |  | ||||||
| 		log.Fatal("Unable to parse URL", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	login := Login{ |  | ||||||
| 		Name:     name, |  | ||||||
| 		URL:      serverURL.String(), |  | ||||||
| 		Token:    token, |  | ||||||
| 		Insecure: insecure, |  | ||||||
| 		SSHKey:   sshKey, |  | ||||||
| 		Created:  time.Now().Unix(), |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(token) == 0 { |  | ||||||
| 		login.Token, err = login.GenerateToken(user, passwd) |  | ||||||
| 		if err != nil { |  | ||||||
| 			log.Fatal(err) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Verify if authentication works and get user info |  | ||||||
| 	u, _, err := login.Client().GetMyUserInfo() |  | ||||||
| 	if err != nil { |  | ||||||
| 		log.Fatal(err) |  | ||||||
| 	} |  | ||||||
| 	login.User = u.UserName |  | ||||||
|  |  | ||||||
| 	if len(login.Name) == 0 { |  | ||||||
| 		login.Name, err = GenerateLoginName(giteaURL, login.User) |  | ||||||
| 		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) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	fmt.Printf("Login as %s on %s successful. Added this login as %s\n", login.User, login.URL, login.Name) |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // DeleteLogin delete a login by name |  | ||||||
| func DeleteLogin(name string) error { |  | ||||||
| 	var idx = -1 |  | ||||||
| 	for i, l := range Config.Logins { |  | ||||||
| 		if l.Name == name { |  | ||||||
| 			idx = i |  | ||||||
| 			break |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	if idx == -1 { |  | ||||||
| 		return fmt.Errorf("can not delete login '%s', does not exist", name) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	Config.Logins = append(Config.Logins[:idx], Config.Logins[idx+1:]...) |  | ||||||
|  |  | ||||||
| 	return SaveConfig() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // GenerateLoginName generates a name string based on instance URL & adds username if the result is not unique |  | ||||||
| func GenerateLoginName(url, user string) (string, error) { |  | ||||||
| 	parsedURL, err := utils.NormalizeURL(url) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return "", err |  | ||||||
| 	} |  | ||||||
| 	name := parsedURL.Host |  | ||||||
|  |  | ||||||
| 	// append user name if login name already exists |  | ||||||
| 	if len(user) != 0 { |  | ||||||
| 		for _, l := range Config.Logins { |  | ||||||
| 			if l.Name == name { |  | ||||||
| 				name += "_" + user |  | ||||||
| 				break |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return name, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // InitCommand returns repository and *Login based on flags |  | ||||||
| func InitCommand(repoValue, loginValue, remoteValue string) (*Login, string, string) { |  | ||||||
| 	var login *Login |  | ||||||
|  |  | ||||||
| 	err := LoadConfig() |  | ||||||
| 	if err != nil { |  | ||||||
| 		log.Fatal(err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if login, err = GetDefaultLogin(); err != nil { |  | ||||||
| 		log.Fatal(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	exist, err := utils.PathExists(repoValue) |  | ||||||
| 	if err != nil { |  | ||||||
| 		log.Fatal(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if exist || len(repoValue) == 0 { |  | ||||||
| 		login, repoValue, err = curGitRepoPath(repoValue, remoteValue) |  | ||||||
| 		if err != nil { |  | ||||||
| 			log.Fatal(err.Error()) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if loginValue != "" { |  | ||||||
| 		login = GetLoginByName(loginValue) |  | ||||||
| 		if login == nil { |  | ||||||
| 			log.Fatal("Login name " + loginValue + " does not exist") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	owner, repo := utils.GetOwnerAndRepo(repoValue, login.User) |  | ||||||
| 	return login, owner, repo |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // InitCommandLoginOnly return *Login based on flags |  | ||||||
| func InitCommandLoginOnly(loginValue string) *Login { |  | ||||||
| 	err := LoadConfig() |  | ||||||
| 	if err != nil { |  | ||||||
| 		log.Fatal(err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var login *Login |  | ||||||
| 	if loginValue == "" { |  | ||||||
| 		login, err = GetDefaultLogin() |  | ||||||
| 		if err != nil { |  | ||||||
| 			log.Fatal(err) |  | ||||||
| 		} |  | ||||||
| 	} else { |  | ||||||
| 		login = GetLoginByName(loginValue) |  | ||||||
| 		if login == nil { |  | ||||||
| 			log.Fatal("Login name " + loginValue + " does not exist") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return login |  | ||||||
| } |  | ||||||
|   | |||||||
							
								
								
									
										126
									
								
								modules/config/login_tasks.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								modules/config/login_tasks.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,126 @@ | |||||||
|  | // 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 config | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"log" | ||||||
|  | 	"os" | ||||||
|  | 	"strings" | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
|  | 	"code.gitea.io/tea/modules/utils" | ||||||
|  |  | ||||||
|  | 	"code.gitea.io/sdk/gitea" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // 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(err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	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 { | ||||||
|  | 		log.Fatal("No password set") | ||||||
|  | 	} else if len(user) == 0 && len(passwd) != 0 { | ||||||
|  | 		log.Fatal("No user set") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Normalize URL | ||||||
|  | 	serverURL, err := utils.NormalizeURL(giteaURL) | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatal("Unable to parse URL", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	login := Login{ | ||||||
|  | 		Name:     name, | ||||||
|  | 		URL:      serverURL.String(), | ||||||
|  | 		Token:    token, | ||||||
|  | 		Insecure: insecure, | ||||||
|  | 		SSHKey:   sshKey, | ||||||
|  | 		Created:  time.Now().Unix(), | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if len(token) == 0 { | ||||||
|  | 		login.Token, err = GenerateToken(login.Client(), user, passwd) | ||||||
|  | 		if err != nil { | ||||||
|  | 			log.Fatal(err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Verify if authentication works and get user info | ||||||
|  | 	u, _, err := login.Client().GetMyUserInfo() | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatal(err) | ||||||
|  | 	} | ||||||
|  | 	login.User = u.UserName | ||||||
|  |  | ||||||
|  | 	if len(login.Name) == 0 { | ||||||
|  | 		login.Name, err = GenerateLoginName(giteaURL, login.User) | ||||||
|  | 		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) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	fmt.Printf("Login as %s on %s successful. Added this login as %s\n", login.User, login.URL, login.Name) | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // GenerateToken creates a new token when given BasicAuth credentials | ||||||
|  | func GenerateToken(client *gitea.Client, user, pass string) (string, error) { | ||||||
|  | 	gitea.SetBasicAuth(user, pass)(client) | ||||||
|  |  | ||||||
|  | 	host, _ := os.Hostname() | ||||||
|  | 	tl, _, err := client.ListAccessTokens(gitea.ListAccessTokensOptions{}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  | 	tokenName := host + "-tea" | ||||||
|  |  | ||||||
|  | 	for i := range tl { | ||||||
|  | 		if tl[i].Name == tokenName { | ||||||
|  | 			tokenName += time.Now().Format("2006-01-02_15-04-05") | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	t, _, err := client.CreateAccessToken(gitea.CreateAccessTokenOption{Name: tokenName}) | ||||||
|  | 	return t.Token, err | ||||||
|  | } | ||||||
| @@ -16,18 +16,14 @@ type TeaRepo struct { | |||||||
| // RepoForWorkdir tries to open the git repository in the local directory | // RepoForWorkdir tries to open the git repository in the local directory | ||||||
| // for reading or modification. | // for reading or modification. | ||||||
| func RepoForWorkdir() (*TeaRepo, error) { | func RepoForWorkdir() (*TeaRepo, error) { | ||||||
| 	repo, err := git.PlainOpenWithOptions("./", &git.PlainOpenOptions{ | 	return RepoFromPath("") | ||||||
| 		DetectDotGit: true, |  | ||||||
| 	}) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return &TeaRepo{repo}, nil |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // RepoFromPath tries to open the git repository by path | // RepoFromPath tries to open the git repository by path | ||||||
| func RepoFromPath(path string) (*TeaRepo, error) { | func RepoFromPath(path string) (*TeaRepo, error) { | ||||||
|  | 	if len(path) == 0 { | ||||||
|  | 		path = "./" | ||||||
|  | 	} | ||||||
| 	repo, err := git.PlainOpenWithOptions(path, &git.PlainOpenOptions{ | 	repo, err := git.PlainOpenWithOptions(path, &git.PlainOpenOptions{ | ||||||
| 		DetectDotGit: true, | 		DetectDotGit: true, | ||||||
| 	}) | 	}) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Norwin
					Norwin