project create: user project path

Use project path for project creation and get the project clone url directly
from the remote source
This commit is contained in:
Simone Gotti 2019-04-03 11:07:54 +02:00
parent 6736f5aebc
commit 3d39553189
8 changed files with 84 additions and 39 deletions

View File

@ -36,7 +36,7 @@ var cmdProjectCreate = &cobra.Command{
type projectCreateOptions struct { type projectCreateOptions struct {
name string name string
parentPath string parentPath string
repoURL string repoPath string
remoteSourceName string remoteSourceName string
skipSSHHostKeyCheck bool skipSSHHostKeyCheck bool
} }
@ -47,7 +47,7 @@ func init() {
flags := cmdProjectCreate.Flags() flags := cmdProjectCreate.Flags()
flags.StringVarP(&projectCreateOpts.name, "name", "n", "", "project name") 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.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.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`) 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{ req := &api.CreateProjectRequest{
Name: projectCreateOpts.name, Name: projectCreateOpts.name,
ParentID: projectCreateOpts.parentPath, ParentID: projectCreateOpts.parentPath,
RepoURL: projectCreateOpts.repoURL, RepoPath: projectCreateOpts.repoPath,
RemoteSourceName: projectCreateOpts.remoteSourceName, RemoteSourceName: projectCreateOpts.remoteSourceName,
SkipSSHHostKeyCheck: projectCreateOpts.skipSSHHostKeyCheck, SkipSSHHostKeyCheck: projectCreateOpts.skipSSHHostKeyCheck,
} }

View File

@ -127,6 +127,10 @@ func (c *Client) GetUserInfo() (*gitsource.UserInfo, error) {
return nil, nil 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) { 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) resp, err := c.getResponse("GET", fmt.Sprintf("%s/%s/raw/%s/%s", owner, repo, commit, file), nil, nil, nil)
if err != nil { if err != nil {

View File

@ -111,6 +111,18 @@ func (c *Client) GetUserInfo() (*gitsource.UserInfo, error) {
}, nil }, 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) { func (c *Client) GetFile(owner, repo, commit, file string) ([]byte, error) {
data, err := c.client.GetFile(owner, repo, commit, file) data, err := c.client.GetFile(owner, repo, commit, file)
return data, err return data, err

View File

@ -121,6 +121,18 @@ func (c *Client) RequestOauth2Token(callbackURL, code string) (*oauth2.Token, er
return token, nil 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) { func (c *Client) GetUserInfo() (*gitsource.UserInfo, error) {
user, _, err := c.client.Users.CurrentUser() user, _, err := c.client.Users.CurrentUser()
if err != nil { if err != nil {

View File

@ -30,6 +30,7 @@ const (
) )
type GitSource interface { type GitSource interface {
GetRepoInfo(owner, repo string) (*RepoInfo, error)
GetFile(owner, repo, commit, file string) ([]byte, error) GetFile(owner, repo, commit, file string) ([]byte, error)
DeleteDeployKey(owner, repo, title string) error DeleteDeployKey(owner, repo, title string) error
CreateDeployKey(owner, repo, title, pubKey string, readonly bool) error CreateDeployKey(owner, repo, title, pubKey string, readonly bool) error
@ -57,6 +58,12 @@ type Oauth2Source interface {
RequestOauth2Token(callbackURL, code string) (*oauth2.Token, error) RequestOauth2Token(callbackURL, code string) (*oauth2.Token, error)
} }
type RepoInfo struct {
ID string
SSHCloneURL string
HTTPCloneURL string
}
type UserInfo struct { type UserInfo struct {
ID string ID string
LoginName string LoginName string

View File

@ -31,7 +31,7 @@ import (
type CreateProjectRequest struct { type CreateProjectRequest struct {
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
ParentID string `json:"parent_id,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"` RemoteSourceName string `json:"remote_source_name,omitempty"`
SkipSSHHostKeyCheck bool `json:"skip_ssh_host_key_check,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{ creq := &command.CreateProjectRequest{
Name: req.Name, Name: req.Name,
ParentID: req.ParentID, ParentID: req.ParentID,
RepoURL: req.RepoURL, RepoPath: req.RepoPath,
RemoteSourceName: req.RemoteSourceName, RemoteSourceName: req.RemoteSourceName,
CurrentUserID: userID, CurrentUserID: userID,
SkipSSHHostKeyCheck: req.SkipSSHHostKeyCheck, SkipSSHHostKeyCheck: req.SkipSSHHostKeyCheck,

View File

@ -18,6 +18,7 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"net/http" "net/http"
"sort"
"strconv" "strconv"
gitsource "github.com/sorintlab/agola/internal/gitsources" gitsource "github.com/sorintlab/agola/internal/gitsources"
@ -196,13 +197,20 @@ func (h *UserByNameHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
type UserResponse struct { type UserResponse struct {
ID string `json:"id"` ID string `json:"id"`
UserName string `json:"username"` UserName string `json:"username"`
Tokens []string `json:"tokens"`
} }
func createUserResponse(r *types.User) *UserResponse { func createUserResponse(u *types.User) *UserResponse {
user := &UserResponse{ user := &UserResponse{
ID: r.ID, ID: u.ID,
UserName: r.UserName, 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 return user
} }

View File

@ -17,7 +17,6 @@ package command
import ( import (
"context" "context"
"fmt" "fmt"
"net/url"
"path" "path"
"strings" "strings"
@ -32,7 +31,7 @@ type CreateProjectRequest struct {
Name string Name string
ParentID string ParentID string
RemoteSourceName string RemoteSourceName string
RepoURL string RepoPath string
CurrentUserID string CurrentUserID string
SkipSSHHostKeyCheck bool 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) 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) user, _, err := c.configstoreClient.GetUser(ctx, req.CurrentUserID)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "failed to get user %q", req.CurrentUserID) 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) 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 parentID := req.ParentID
if parentID == "" { if parentID == "" {
// create project in current user namespace // create project in current user namespace
@ -98,8 +99,8 @@ func (c *CommandHandler) CreateProject(ctx context.Context, req *CreateProjectRe
ID: parentID, ID: parentID,
}, },
LinkedAccountID: la.ID, LinkedAccountID: la.ID,
RepoPath: fmt.Sprintf("%s/%s", repoOwner, repoName), RepoPath: req.RepoPath,
CloneURL: cloneURL, CloneURL: sshCloneURL,
SkipSSHHostKeyCheck: req.SkipSSHHostKeyCheck, SkipSSHHostKeyCheck: req.SkipSSHHostKeyCheck,
SSHPrivateKey: string(privateKey), 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 { 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) 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)) pubKey, err := util.ExtractPublicKey([]byte(conf.Project.SSHPrivateKey))
if err != nil { 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) webhookURL := fmt.Sprintf("%s/webhooks?projectid=%s", c.apiExposedURL, conf.Project.ID)