Simplify Go Endpoints + Add Tests (#120)

This MR represents a major refactor of the Go codebase, as well as introducing tests for the handlers. The MR also introduces an endpoint to shutdown or restart the Go server, which may be useful for clients who want to refresh the state of the plugin after checking out branches. Finally, this MR adds a contributing document for users who want to make feature changes.
This commit is contained in:
Harrison (Harry) Cramer
2023-12-04 10:15:07 -05:00
committed by GitHub
parent 10b0b596ae
commit 93fe3e8bd6
41 changed files with 1745 additions and 728 deletions

View File

@@ -14,34 +14,42 @@ import (
"github.com/xanzy/go-gitlab"
)
type Client struct {
projectId string
mergeId int
gitlabInstance string
authToken string
git *gitlab.Client
}
type DebugSettings struct {
GoRequest bool `json:"go_request"`
GoResponse bool `json:"go_response"`
}
/* This will parse and validate the project settings and then initialize the Gitlab client */
func (c *Client) initGitlabClient() error {
type ProjectInfo struct {
ProjectId string
MergeId int
}
/* The Client struct embeds all the methods from Gitlab for the different services */
type Client struct {
*gitlab.MergeRequestsService
*gitlab.MergeRequestApprovalsService
*gitlab.DiscussionsService
*gitlab.ProjectsService
*gitlab.ProjectMembersService
*gitlab.JobsService
*gitlab.PipelinesService
}
/* initGitlabClient parses and validates the project settings and initializes the Gitlab client. */
func initGitlabClient() (error, *Client) {
if len(os.Args) < 6 {
return errors.New("Must provide gitlab url, port, auth token, debug settings, and log path")
return errors.New("Must provide gitlab url, port, auth token, debug settings, and log path"), nil
}
gitlabInstance := os.Args[1]
if gitlabInstance == "" {
return errors.New("GitLab instance URL cannot be empty")
return errors.New("GitLab instance URL cannot be empty"), nil
}
authToken := os.Args[3]
if authToken == "" {
return errors.New("Auth token cannot be empty")
return errors.New("Auth token cannot be empty"), nil
}
/* Parse debug settings and initialize logger handlers */
@@ -49,7 +57,7 @@ func (c *Client) initGitlabClient() error {
var debugObject DebugSettings
err := json.Unmarshal([]byte(debugSettings), &debugObject)
if err != nil {
return fmt.Errorf("Could not parse debug settings: %w, %s", err, debugSettings)
return fmt.Errorf("Could not parse debug settings: %w, %s", err, debugSettings), nil
}
var apiCustUrl = fmt.Sprintf(gitlabInstance + "/api/v4")
@@ -66,65 +74,70 @@ func (c *Client) initGitlabClient() error {
gitlabOptions = append(gitlabOptions, gitlab.WithResponseLogHook(responseLogger))
}
git, err := gitlab.NewClient(authToken, gitlabOptions...)
client, err := gitlab.NewClient(authToken, gitlabOptions...)
if err != nil {
return fmt.Errorf("Failed to create client: %v", err)
return fmt.Errorf("Failed to create client: %v", err), nil
}
c.gitlabInstance = gitlabInstance
c.authToken = authToken
c.git = git
return nil
return nil, &Client{
MergeRequestsService: client.MergeRequests,
MergeRequestApprovalsService: client.MergeRequestApprovals,
DiscussionsService: client.Discussions,
ProjectsService: client.Projects,
ProjectMembersService: client.ProjectMembers,
JobsService: client.Jobs,
}
}
/* This will fetch the project ID and merge request ID using the client */
func (c *Client) initProjectSettings(g GitProjectInfo) error {
/* initProjectSettings fetch the project ID and merge request ID using the client. */
func initProjectSettings(c *Client, gitInfo GitProjectInfo) (error, *ProjectInfo) {
opt := gitlab.GetProjectOptions{}
project, _, err := c.git.Projects.GetProject(g.projectPath(), &opt)
project, _, err := c.GetProject(gitInfo.projectPath(), &opt)
if err != nil {
return fmt.Errorf(fmt.Sprintf("Error getting project at %s", g.RemoteUrl), err)
return fmt.Errorf(fmt.Sprintf("Error getting project at %s", gitInfo.RemoteUrl), err), nil
}
if project == nil {
return fmt.Errorf(fmt.Sprintf("Could not find project at %s", g.RemoteUrl), err)
return fmt.Errorf(fmt.Sprintf("Could not find project at %s", gitInfo.RemoteUrl), err), nil
}
if project == nil {
return fmt.Errorf("No projects you are a member of contained remote URL %s", g.RemoteUrl)
return fmt.Errorf("No projects you are a member of contained remote URL %s", gitInfo.RemoteUrl), nil
}
c.projectId = fmt.Sprint(project.ID)
projectId := fmt.Sprint(project.ID)
options := gitlab.ListProjectMergeRequestsOptions{
Scope: gitlab.String("all"),
State: gitlab.String("opened"),
SourceBranch: &g.BranchName,
SourceBranch: &gitInfo.BranchName,
}
mergeRequests, _, err := c.git.MergeRequests.ListProjectMergeRequests(c.projectId, &options)
mergeRequests, _, err := c.ListProjectMergeRequests(projectId, &options)
if err != nil {
return fmt.Errorf("Failed to list merge requests: %w", err)
return fmt.Errorf("Failed to list merge requests: %w", err), nil
}
if len(mergeRequests) == 0 {
return errors.New("No merge requests found")
return errors.New("No merge requests found"), nil
}
mergeId := strconv.Itoa(mergeRequests[0].IID)
mergeIdInt, err := strconv.Atoi(mergeId)
if err != nil {
return err
return err, nil
}
c.mergeId = mergeIdInt
return nil
return nil, &ProjectInfo{
MergeId: mergeIdInt,
ProjectId: projectId,
}
}
func (c *Client) handleError(w http.ResponseWriter, err error, message string, status int) {
/* handleError is a utililty handler that returns errors to the client along with their statuses and messages */
func handleError(w http.ResponseWriter, err error, message string, status int) {
w.WriteHeader(status)
response := ErrorResponse{
Message: message,
@@ -134,7 +147,7 @@ func (c *Client) handleError(w http.ResponseWriter, err error, message string, s
err = json.NewEncoder(w).Encode(response)
if err != nil {
c.handleError(w, err, "Could not encode response", http.StatusInternalServerError)
handleError(w, err, "Could not encode error response", http.StatusInternalServerError)
}
}