diff --git a/cmd/agola/cmd/projectcreate.go b/cmd/agola/cmd/projectcreate.go index 68ef1b3..70d8f1b 100644 --- a/cmd/agola/cmd/projectcreate.go +++ b/cmd/agola/cmd/projectcreate.go @@ -36,7 +36,7 @@ var cmdProjectCreate = &cobra.Command{ type projectCreateOptions struct { name string parentPath string - repoURL string + repoPath string remoteSourceName string skipSSHHostKeyCheck bool } @@ -47,7 +47,7 @@ func init() { flags := cmdProjectCreate.Flags() flags.StringVarP(&projectCreateOpts.name, "name", "n", "", "project name") - flags.StringVar(&projectCreateOpts.repoURL, "repo-url", "", "repository url") + flags.StringVar(&projectCreateOpts.repoPath, "repo-path", "", "repository path (i.e agola-io/agola)") flags.StringVar(&projectCreateOpts.remoteSourceName, "remote-source", "", "remote source name") flags.BoolVarP(&projectCreateOpts.skipSSHHostKeyCheck, "skip-ssh-host-key-check", "s", false, "skip ssh host key check") flags.StringVar(&projectCreateOpts.parentPath, "parent", "", `parent project group path (i.e "org/org01" for root project group in org01, "user/user01/group01/subgroub01") or project group id where the project should be created`) @@ -66,7 +66,7 @@ func projectCreate(cmd *cobra.Command, args []string) error { req := &api.CreateProjectRequest{ Name: projectCreateOpts.name, ParentID: projectCreateOpts.parentPath, - RepoURL: projectCreateOpts.repoURL, + RepoPath: projectCreateOpts.repoPath, RemoteSourceName: projectCreateOpts.remoteSourceName, SkipSSHHostKeyCheck: projectCreateOpts.skipSSHHostKeyCheck, } diff --git a/internal/gitsources/agolagit/agolagit.go b/internal/gitsources/agolagit/agolagit.go index ce50a19..109636c 100644 --- a/internal/gitsources/agolagit/agolagit.go +++ b/internal/gitsources/agolagit/agolagit.go @@ -127,6 +127,10 @@ func (c *Client) GetUserInfo() (*gitsource.UserInfo, error) { return nil, nil } +func (c *Client) GetRepoInfo(owner, reponame string) (*gitsource.RepoInfo, error) { + return nil, nil +} + func (c *Client) GetFile(owner, repo, commit, file string) ([]byte, error) { resp, err := c.getResponse("GET", fmt.Sprintf("%s/%s/raw/%s/%s", owner, repo, commit, file), nil, nil, nil) if err != nil { diff --git a/internal/gitsources/gitea/gitea.go b/internal/gitsources/gitea/gitea.go index 5bc11f4..f2e4c8f 100644 --- a/internal/gitsources/gitea/gitea.go +++ b/internal/gitsources/gitea/gitea.go @@ -111,6 +111,18 @@ func (c *Client) GetUserInfo() (*gitsource.UserInfo, error) { }, nil } +func (c *Client) GetRepoInfo(owner, reponame string) (*gitsource.RepoInfo, error) { + repo, err := c.client.GetRepo(owner, reponame) + if err != nil { + return nil, err + } + return &gitsource.RepoInfo{ + ID: strconv.FormatInt(repo.ID, 10), + SSHCloneURL: repo.SSHURL, + HTTPCloneURL: repo.CloneURL, + }, nil +} + func (c *Client) GetFile(owner, repo, commit, file string) ([]byte, error) { data, err := c.client.GetFile(owner, repo, commit, file) return data, err diff --git a/internal/gitsources/gitlab/gitlab.go b/internal/gitsources/gitlab/gitlab.go index 9f54153..7cc1ba1 100644 --- a/internal/gitsources/gitlab/gitlab.go +++ b/internal/gitsources/gitlab/gitlab.go @@ -121,6 +121,18 @@ func (c *Client) RequestOauth2Token(callbackURL, code string) (*oauth2.Token, er return token, nil } +func (c *Client) GetRepoInfo(owner, reponame string) (*gitsource.RepoInfo, error) { + repo, _, err := c.client.Projects.GetProject(path.Join(owner, reponame)) + if err != nil { + return nil, err + } + return &gitsource.RepoInfo{ + ID: strconv.Itoa(repo.ID), + SSHCloneURL: repo.SSHURLToRepo, + HTTPCloneURL: repo.HTTPURLToRepo, + }, nil +} + func (c *Client) GetUserInfo() (*gitsource.UserInfo, error) { user, _, err := c.client.Users.CurrentUser() if err != nil { diff --git a/internal/gitsources/gitsource.go b/internal/gitsources/gitsource.go index 570177e..23d82c9 100644 --- a/internal/gitsources/gitsource.go +++ b/internal/gitsources/gitsource.go @@ -30,6 +30,7 @@ const ( ) type GitSource interface { + GetRepoInfo(owner, repo string) (*RepoInfo, error) GetFile(owner, repo, commit, file string) ([]byte, error) DeleteDeployKey(owner, repo, title string) error CreateDeployKey(owner, repo, title, pubKey string, readonly bool) error @@ -57,6 +58,12 @@ type Oauth2Source interface { RequestOauth2Token(callbackURL, code string) (*oauth2.Token, error) } +type RepoInfo struct { + ID string + SSHCloneURL string + HTTPCloneURL string +} + type UserInfo struct { ID string LoginName string diff --git a/internal/services/gateway/api/project.go b/internal/services/gateway/api/project.go index beaa10a..e0474fc 100644 --- a/internal/services/gateway/api/project.go +++ b/internal/services/gateway/api/project.go @@ -31,7 +31,7 @@ import ( type CreateProjectRequest struct { Name string `json:"name,omitempty"` ParentID string `json:"parent_id,omitempty"` - RepoURL string `json:"repo_url,omitempty"` + RepoPath string `json:"repo_path,omitempty"` RemoteSourceName string `json:"remote_source_name,omitempty"` SkipSSHHostKeyCheck bool `json:"skip_ssh_host_key_check,omitempty"` } @@ -68,7 +68,7 @@ func (h *CreateProjectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) creq := &command.CreateProjectRequest{ Name: req.Name, ParentID: req.ParentID, - RepoURL: req.RepoURL, + RepoPath: req.RepoPath, RemoteSourceName: req.RemoteSourceName, CurrentUserID: userID, SkipSSHHostKeyCheck: req.SkipSSHHostKeyCheck, diff --git a/internal/services/gateway/api/user.go b/internal/services/gateway/api/user.go index 9622877..bbf6612 100644 --- a/internal/services/gateway/api/user.go +++ b/internal/services/gateway/api/user.go @@ -18,6 +18,7 @@ import ( "context" "encoding/json" "net/http" + "sort" "strconv" gitsource "github.com/sorintlab/agola/internal/gitsources" @@ -194,15 +195,22 @@ func (h *UserByNameHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } type UserResponse struct { - ID string `json:"id"` - UserName string `json:"username"` + ID string `json:"id"` + UserName string `json:"username"` + Tokens []string `json:"tokens"` } -func createUserResponse(r *types.User) *UserResponse { +func createUserResponse(u *types.User) *UserResponse { user := &UserResponse{ - ID: r.ID, - UserName: r.UserName, + ID: u.ID, + UserName: u.UserName, + Tokens: make([]string, 0, len(u.Tokens)), } + for tokenName := range u.Tokens { + user.Tokens = append(user.Tokens, tokenName) + } + sort.Sort(sort.StringSlice(user.Tokens)) + return user } diff --git a/internal/services/gateway/command/project.go b/internal/services/gateway/command/project.go index 244afcf..a25b561 100644 --- a/internal/services/gateway/command/project.go +++ b/internal/services/gateway/command/project.go @@ -17,7 +17,6 @@ package command import ( "context" "fmt" - "net/url" "path" "strings" @@ -32,7 +31,7 @@ type CreateProjectRequest struct { Name string ParentID string RemoteSourceName string - RepoURL string + RepoPath string CurrentUserID string SkipSSHHostKeyCheck bool } @@ -42,28 +41,6 @@ func (c *CommandHandler) CreateProject(ctx context.Context, req *CreateProjectRe return nil, errors.Errorf("invalid project name %q", req.Name) } - u, err := url.Parse(req.RepoURL) - if err != nil { - return nil, errors.Wrapf(err, "failed to parse repo url") - } - - repoOwner := strings.TrimPrefix(path.Dir(u.Path), "/") - repoName := path.Base(u.Path) - - u.RawQuery = "" - u.Path = "" - host := u.Hostname() - c.log.Infof("repoOwner: %s, repoName: %s", repoOwner, repoName) - - cloneURL := fmt.Sprintf("git@%s:%s/%s.git", host, repoOwner, repoName) - c.log.Infof("cloneURL: %s", cloneURL) - - c.log.Infof("generating ssh key pairs") - privateKey, _, err := util.GenSSHKeyPair(4096) - if err != nil { - return nil, errors.Wrapf(err, "failed to generate ssh key pair") - } - user, _, err := c.configstoreClient.GetUser(ctx, req.CurrentUserID) if err != nil { return nil, errors.Wrapf(err, "failed to get user %q", req.CurrentUserID) @@ -85,6 +62,30 @@ func (c *CommandHandler) CreateProject(ctx context.Context, req *CreateProjectRe return nil, errors.Errorf("user doesn't have a linked account for remote source %q", rs.Name) } + gitsource, err := common.GetGitSource(rs, la) + if err != nil { + return nil, errors.Wrapf(err, "failed to create gitsource client") + } + + repoOwner := strings.TrimPrefix(path.Dir(req.RepoPath), "/") + repoName := path.Base(req.RepoPath) + c.log.Infof("repoOwner: %s, repoName: %s", repoOwner, repoName) + + repo, err := gitsource.GetRepoInfo(repoOwner, repoName) + if err != nil { + return nil, errors.Wrapf(err, "failed to get repository info from gitsource") + } + + //cloneURL := fmt.Sprintf("git@%s:%s/%s.git", host, repoOwner, repoName) + sshCloneURL := repo.SSHCloneURL + c.log.Infof("sshCloneURL: %s", sshCloneURL) + + c.log.Infof("generating ssh key pairs") + privateKey, _, err := util.GenSSHKeyPair(4096) + if err != nil { + return nil, errors.Wrapf(err, "failed to generate ssh key pair") + } + parentID := req.ParentID if parentID == "" { // create project in current user namespace @@ -98,8 +99,8 @@ func (c *CommandHandler) CreateProject(ctx context.Context, req *CreateProjectRe ID: parentID, }, LinkedAccountID: la.ID, - RepoPath: fmt.Sprintf("%s/%s", repoOwner, repoName), - CloneURL: cloneURL, + RepoPath: req.RepoPath, + CloneURL: sshCloneURL, SkipSSHHostKeyCheck: req.SkipSSHHostKeyCheck, SSHPrivateKey: string(privateKey), } @@ -125,13 +126,14 @@ type SetupProjectRequest struct { } func (c *CommandHandler) SetupProject(ctx context.Context, rs *types.RemoteSource, la *types.LinkedAccount, conf *SetupProjectRequest) error { - c.log.Infof("setupproject") - gitsource, err := common.GetGitSource(rs, la) + if err != nil { + return errors.Wrapf(err, "failed to create gitsource client") + } pubKey, err := util.ExtractPublicKey([]byte(conf.Project.SSHPrivateKey)) if err != nil { - return errors.Wrapf(err, "failed to create gitea client") + return errors.Wrapf(err, "failed to extract public key") } webhookURL := fmt.Sprintf("%s/webhooks?projectid=%s", c.apiExposedURL, conf.Project.ID)