gateway: add UserCreateRun api and related action

add an api to execute a user direct run. This method will replace the current
custom webhook way to create a direct run.
This commit is contained in:
Simone Gotti 2019-06-11 15:09:41 +02:00
parent 810abaaab8
commit 2a95c93f0d
5 changed files with 104 additions and 4 deletions

View File

@ -30,7 +30,10 @@ import (
errors "golang.org/x/xerrors"
)
var jsonContent = http.Header{"content-type": []string{"application/json"}}
var (
branchRefPrefix = "refs/heads/"
tagRefPrefix = "refs/tags/"
)
// Client represents a Gogs API client.
type Client struct {
@ -131,7 +134,7 @@ func (c *Client) GetRepoInfo(repopath string) (*gitsource.RepoInfo, error) {
}
func (c *Client) GetFile(repopath, commit, file string) ([]byte, error) {
resp, err := c.getResponse("GET", fmt.Sprintf("%s/raw/%s/%s", repopath, commit, file), nil, nil, nil)
resp, err := c.getResponse("GET", fmt.Sprintf("%s.git/raw/%s/%s", repopath, commit, file), nil, nil, nil)
if err != nil {
return nil, err
}
@ -182,11 +185,11 @@ func (c *Client) GetCommit(repopath, commitSHA string) (*gitsource.Commit, error
}
func (c *Client) BranchRef(branch string) string {
return ""
return branchRefPrefix + branch
}
func (c *Client) TagRef(tag string) string {
return ""
return tagRefPrefix + tag
}
func (c *Client) PullRequestRef(prID string) string {

View File

@ -17,9 +17,12 @@ package action
import (
"context"
"encoding/json"
"fmt"
"strings"
"time"
gitsource "github.com/sorintlab/agola/internal/gitsources"
"github.com/sorintlab/agola/internal/gitsources/agolagit"
"github.com/sorintlab/agola/internal/services/common"
csapi "github.com/sorintlab/agola/internal/services/configstore/api"
"github.com/sorintlab/agola/internal/services/types"
@ -814,3 +817,49 @@ func (h *ActionHandler) DeleteUserToken(ctx context.Context, userRef, tokenName
}
return nil
}
func (h *ActionHandler) UserCreateRun(ctx context.Context, repoPath, branch, commitSHA, message string) error {
curUserID := h.CurrentUserID(ctx)
user, resp, err := h.configstoreClient.GetUser(ctx, curUserID)
if err != nil {
return errors.Errorf("failed to get user %q: %w", curUserID, ErrFromRemote(resp, err))
}
// Verify that the repo is owned by the user
repoParts := strings.Split(repoPath, "/")
if len(repoParts) != 2 {
return util.NewErrBadRequest(errors.Errorf("wrong repo path: %q", repoPath))
}
if repoParts[0] != user.ID {
return util.NewErrUnauthorized(errors.Errorf("repo %q not owned", repoPath))
}
gitSource := agolagit.New(h.apiExposedURL + "/repos")
cloneURL := fmt.Sprintf("%s/%s.git", h.apiExposedURL+"/repos", repoPath)
req := &CreateRunRequest{
RunType: types.RunTypeUser,
RefType: types.RunRefTypeBranch,
RunCreationTrigger: types.RunCreationTriggerTypeManual,
Project: nil,
User: user,
RepoPath: repoPath,
GitSource: gitSource,
CommitSHA: commitSHA,
Message: message,
Branch: branch,
Tag: "",
PullRequestID: "",
Ref: gitSource.BranchRef(branch),
CloneURL: cloneURL,
CommitLink: "",
BranchLink: "",
TagLink: "",
PullRequestLink: "",
}
return h.CreateRuns(ctx, req)
}

View File

@ -282,6 +282,15 @@ func (c *Client) DeleteUser(ctx context.Context, userRef string) (*http.Response
return c.getResponse(ctx, "DELETE", fmt.Sprintf("/users/%s", userRef), nil, jsonContent, nil)
}
func (c *Client) UserCreateRun(ctx context.Context, req *UserCreateRunRequest) (*http.Response, error) {
reqj, err := json.Marshal(req)
if err != nil {
return nil, err
}
return c.getResponse(ctx, "POST", "/user/createrun", nil, jsonContent, bytes.NewReader(reqj))
}
func (c *Client) CreateUserLA(ctx context.Context, userRef string, req *CreateUserLARequest) (*CreateUserLAResponse, *http.Response, error) {
reqj, err := json.Marshal(req)
if err != nil {

View File

@ -603,3 +603,40 @@ func (h *LoginUserHandler) loginUser(ctx context.Context, req *LoginUserRequest)
}
return resp, nil
}
type UserCreateRunRequest struct {
RepoPath string `json:"repo_path,omitempty"`
Branch string `json:"branch,omitempty"`
CommitSHA string `json:"commit_sha,omitempty"`
Message string `json:"message,omitempty"`
}
type UserCreateRunHandler struct {
log *zap.SugaredLogger
ah *action.ActionHandler
}
func NewUserCreateRunHandler(logger *zap.Logger, ah *action.ActionHandler) *UserCreateRunHandler {
return &UserCreateRunHandler{log: logger.Sugar(), ah: ah}
}
func (h *UserCreateRunHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var req UserCreateRunRequest
d := json.NewDecoder(r.Body)
if err := d.Decode(&req); err != nil {
httpError(w, util.NewErrBadRequest(err))
return
}
err := h.ah.UserCreateRun(ctx, req.RepoPath, req.Branch, req.CommitSHA, req.Message)
if httpError(w, err) {
h.log.Errorf("err: %+v", err)
return
}
if err := httpResponse(w, http.StatusCreated, nil); err != nil {
h.log.Errorf("err: %+v", err)
}
}

View File

@ -177,6 +177,7 @@ func (g *Gateway) Run(ctx context.Context) error {
usersHandler := api.NewUsersHandler(logger, g.ah)
createUserHandler := api.NewCreateUserHandler(logger, g.ah)
deleteUserHandler := api.NewDeleteUserHandler(logger, g.ah)
userCreateRunHandler := api.NewUserCreateRunHandler(logger, g.ah)
createUserLAHandler := api.NewCreateUserLAHandler(logger, g.ah)
deleteUserLAHandler := api.NewDeleteUserLAHandler(logger, g.ah)
@ -264,6 +265,7 @@ func (g *Gateway) Run(ctx context.Context) error {
apirouter.Handle("/users", authForcedHandler(usersHandler)).Methods("GET")
apirouter.Handle("/users", authForcedHandler(createUserHandler)).Methods("POST")
apirouter.Handle("/users/{userref}", authForcedHandler(deleteUserHandler)).Methods("DELETE")
apirouter.Handle("/user/createrun", authForcedHandler(userCreateRunHandler)).Methods("POST")
apirouter.Handle("/users/{userref}/linkedaccounts", authForcedHandler(createUserLAHandler)).Methods("POST")
apirouter.Handle("/users/{userref}/linkedaccounts/{laid}", authForcedHandler(deleteUserLAHandler)).Methods("DELETE")