1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-14 11:03:09 +02:00
sap-jenkins-library/pkg/github/github.go
Sven Merk a1988f6808
feat(whitesourceExecuteScan): GitHub issue creation + SARIF (#3535)
* Add GH issue creation + SARIF

* Code cleanup

* Fix fmt, add debug

* Code enhancements

* Fix

* Added debug info

* Rework UA log scan

* Fix code

* read UA version

* Fix nil reference

* Extraction

* Credentials

* Issue creation

* Error handling

* Fix issue creation

* query escape

* Query escape 2

* Revert

* Test avoid update

* HTTP client

* Add support for custom TLS certs

* Fix code

* Fix code 2

* Fix code 3

* Disable cert check

* Fix auth

* Remove implicit trust

* Skip verification

* Fix

* Fix client

* Fix HTTP auth

* Fix trusted certs

* Trim version

* Code

* Add token

* Added token handling to client

* Fix token

* Cleanup

* Fix token

* Token rework

* Fix code

* Kick out oauth client

* Kick out oauth client

* Transport wrapping

* Token

* Simplification

* Refactor

* Variation

* Check

* Fix

* Debug

* Switch client

* Variation

* Debug

* Switch to cert check

* Add debug

* Parse self

* Cleanup

* Update resources/metadata/whitesourceExecuteScan.yaml

* Add debug

* Expose subjects

* Patch

* Debug

* Debug2

* Debug3

* Fix logging response body

* Cleanup

* Cleanup

* Fix request body logging

* Cleanup import

* Fix import cycle

* Cleanup

* Fix fmt

* Fix NopCloser reference

* Regenerate

* Reintroduce

* Fix test

* Fix tests

* Correction

* Fix error

* Code fix

* Fix tests

* Add tests

* Fix code climate issues

* Code climate

* Code climate again

* Code climate again

* Fix fmt

* Fix fmt 2

Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>
2022-02-23 09:30:19 +01:00

146 lines
4.9 KiB
Go

package github
import (
"context"
"fmt"
"net/url"
"strings"
piperhttp "github.com/SAP/jenkins-library/pkg/http"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/google/go-github/v32/github"
"github.com/pkg/errors"
"golang.org/x/oauth2"
)
type githubCreateIssueService interface {
Create(ctx context.Context, owner string, repo string, issue *github.IssueRequest) (*github.Issue, *github.Response, error)
}
type githubSearchIssuesService interface {
Issues(ctx context.Context, query string, opts *github.SearchOptions) (*github.IssuesSearchResult, *github.Response, error)
}
type githubCreateCommentService interface {
CreateComment(ctx context.Context, owner string, repo string, number int, comment *github.IssueComment) (*github.IssueComment, *github.Response, error)
}
// CreateIssueOptions to configure the creation
type CreateIssueOptions struct {
APIURL string `json:"apiUrl,omitempty"`
Assignees []string `json:"assignees,omitempty"`
Body []byte `json:"body,omitempty"`
Owner string `json:"owner,omitempty"`
Repository string `json:"repository,omitempty"`
Title string `json:"title,omitempty"`
UpdateExisting bool `json:"updateExisting,omitempty"`
Token string `json:"token,omitempty"`
TrustedCerts []string `json:"trustedCerts,omitempty"`
}
//NewClient creates a new GitHub client using an OAuth token for authentication
func NewClient(token, apiURL, uploadURL string, trustedCerts []string) (context.Context, *github.Client, error) {
httpClient := piperhttp.Client{}
httpClient.SetOptions(piperhttp.ClientOptions{
TrustedCerts: trustedCerts,
DoLogRequestBodyOnDebug: true,
DoLogResponseBodyOnDebug: true,
})
stdClient := httpClient.StandardClient()
ctx := context.WithValue(context.Background(), oauth2.HTTPClient, stdClient)
ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token, TokenType: "Bearer"})
tc := oauth2.NewClient(ctx, ts)
if !strings.HasSuffix(apiURL, "/") {
apiURL += "/"
}
baseURL, err := url.Parse(apiURL)
if err != nil {
return ctx, nil, err
}
if !strings.HasSuffix(uploadURL, "/") {
uploadURL += "/"
}
uploadTargetURL, err := url.Parse(uploadURL)
if err != nil {
return ctx, nil, err
}
client := github.NewClient(tc)
client.BaseURL = baseURL
client.UploadURL = uploadTargetURL
return ctx, client, nil
}
func CreateIssue(ghCreateIssueOptions *CreateIssueOptions) error {
ctx, client, err := NewClient(ghCreateIssueOptions.Token, ghCreateIssueOptions.APIURL, "", ghCreateIssueOptions.TrustedCerts)
if err != nil {
return errors.Wrap(err, "failed to get GitHub client")
}
return createIssueLocal(ctx, ghCreateIssueOptions, client.Issues, client.Search, client.Issues)
}
func createIssueLocal(ctx context.Context, ghCreateIssueOptions *CreateIssueOptions, ghCreateIssueService githubCreateIssueService, ghSearchIssuesService githubSearchIssuesService, ghCreateCommentService githubCreateCommentService) error {
issue := github.IssueRequest{
Title: &ghCreateIssueOptions.Title,
}
var bodyString string
if len(ghCreateIssueOptions.Body) > 0 {
bodyString = string(ghCreateIssueOptions.Body)
} else {
bodyString = ""
}
issue.Body = &bodyString
if len(ghCreateIssueOptions.Assignees) > 0 {
issue.Assignees = &ghCreateIssueOptions.Assignees
} else {
issue.Assignees = &[]string{}
}
var existingIssue *github.Issue = nil
if ghCreateIssueOptions.UpdateExisting {
queryString := fmt.Sprintf("is:open is:issue repo:%v/%v in:title %v", ghCreateIssueOptions.Owner, ghCreateIssueOptions.Repository, ghCreateIssueOptions.Title)
searchResult, resp, err := ghSearchIssuesService.Issues(ctx, queryString, nil)
if err != nil {
if resp != nil {
log.Entry().Errorf("GitHub search issue returned response code %v", resp.Status)
}
return errors.Wrap(err, "error occurred when looking for existing issue")
} else {
for _, value := range searchResult.Issues {
if value != nil && *value.Title == ghCreateIssueOptions.Title {
existingIssue = value
}
}
}
if existingIssue != nil {
comment := &github.IssueComment{Body: issue.Body}
_, resp, err := ghCreateCommentService.CreateComment(ctx, ghCreateIssueOptions.Owner, ghCreateIssueOptions.Repository, *existingIssue.Number, comment)
if err != nil {
if resp != nil {
log.Entry().Errorf("GitHub create comment returned response code %v", resp.Status)
}
return errors.Wrap(err, "error occurred when adding comment to existing issue")
}
}
}
if existingIssue == nil {
newIssue, resp, err := ghCreateIssueService.Create(ctx, ghCreateIssueOptions.Owner, ghCreateIssueOptions.Repository, &issue)
if err != nil {
if resp != nil {
log.Entry().Errorf("GitHub create issue returned response code %v", resp.Status)
}
return errors.Wrap(err, "error occurred when creating issue")
}
log.Entry().Debugf("New issue created: %v", newIssue)
}
return nil
}