Skip to content

Commit

Permalink
Enables gitlab provider in controller
Browse files Browse the repository at this point in the history
this enables gitlab integration with controller
using webhook.

Signed-off-by: Shivam Mukhade <[email protected]>
  • Loading branch information
Shivam Mukhade committed Mar 31, 2022
1 parent 0b94308 commit ed7787b
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 34 deletions.
13 changes: 13 additions & 0 deletions pkg/adapter/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/openshift-pipelines/pipelines-as-code/pkg/provider/bitbucketcloud"
"github.com/openshift-pipelines/pipelines-as-code/pkg/provider/bitbucketserver"
"github.com/openshift-pipelines/pipelines-as-code/pkg/provider/github"
"github.com/openshift-pipelines/pipelines-as-code/pkg/provider/gitlab"
"go.uber.org/zap"
"knative.dev/eventing/pkg/adapter/v2"
"knative.dev/pkg/logging"
Expand Down Expand Up @@ -143,6 +144,18 @@ func (l listener) detectProvider(reqHeader *http.Header, reqBody string) (provid
return nil, nil, nil
}

gitLab := &gitlab.Provider{}
isGitlab, processReq, logger, err := gitLab.Detect(reqHeader, reqBody, &log)
if isGitlab {
if err != nil {
return nil, logger, err
}
if processReq {
return gitLab, logger, nil
}
return nil, nil, nil
}

bitCloud := &bitbucketcloud.Provider{}
isBitCloud, processReq, logger, err := bitCloud.Detect(reqHeader, reqBody, &log)
if isBitCloud {
Expand Down
60 changes: 52 additions & 8 deletions pkg/provider/gitlab/gitlab.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import (
"fmt"
"net/http"
"path/filepath"
"regexp"
"strings"

"github.com/openshift-pipelines/pipelines-as-code/pkg/params"
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
"github.com/openshift-pipelines/pipelines-as-code/pkg/provider"
"github.com/xanzy/go-gitlab"
"go.uber.org/zap"
)

const (
Expand Down Expand Up @@ -43,9 +45,48 @@ type Provider struct {
repoURL string
}

// func (v *Provider) ParseEventType(request *http.Request, event *info.Event) error {
// panic("implement me")
// }
// Detect processes event and detect if it is a gitlab event, whether to process or reject it
// returns (if is a GL event, whether to process or reject, logger with event metadata,, error if any occurred)
func (v *Provider) Detect(reqHeader *http.Header, payload string, logger *zap.SugaredLogger) (bool, bool, *zap.SugaredLogger, error) {
isGL := false
event := reqHeader.Get("X-Gitlab-Event")
if event == "" {
return false, false, logger, nil
}

// it is a Gitlab event
isGL = true

setLoggerAndProceed := func() (bool, bool, *zap.SugaredLogger, error) {
logger = logger.With("provider", "gitlab", "event", reqHeader.Get("X-Request-Id"))
return isGL, true, logger, nil
}

eventInt, err := gitlab.ParseWebhook(gitlab.EventType(event), []byte(payload))
if err != nil {
return isGL, false, logger, err
}
_ = json.Unmarshal([]byte(payload), &eventInt)

switch gitEvent := eventInt.(type) {
case *gitlab.MergeEvent:
return setLoggerAndProceed()
case *gitlab.PushEvent:
return setLoggerAndProceed()
case *gitlab.MergeCommentEvent:
if gitEvent.MergeRequest.State == "opened" {
if matches, _ := regexp.MatchString(provider.RetestRegex, gitEvent.ObjectAttributes.Note); matches {
return setLoggerAndProceed()
}
if matches, _ := regexp.MatchString(provider.OktotestRegex, gitEvent.ObjectAttributes.Note); matches {
return setLoggerAndProceed()
}
}
return isGL, false, logger, nil
default:
return isGL, false, logger, fmt.Errorf("event %s is not supported", event)
}
}

// If I understood properly, you can have "personal" projects and groups
// attached projects. But this doesn't seem to show in the API, so we
Expand All @@ -62,12 +103,15 @@ func getOrgRepo(pathWithNamespace string) (string, string) {
}

func (v *Provider) ParsePayload(ctx context.Context, run *params.Run, request *http.Request, payload string) (*info.Event, error) {
// TODO: parse request to figure out which event
event := &info.Event{}
var processedEvent *info.Event

event := request.Header.Get("X-Gitlab-Event")
if event == "" {
return nil, fmt.Errorf("failed to find event type in request header")
}

payloadB := []byte(payload)
eventInt, err := gitlab.ParseWebhook(gitlab.EventType(event.EventType), payloadB)
eventInt, err := gitlab.ParseWebhook(gitlab.EventType(event), payloadB)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -137,15 +181,15 @@ func (v *Provider) ParsePayload(ctx context.Context, run *params.Run, request *h
v.sourceProjectID = gitEvent.MergeRequest.SourceProjectID
v.userID = gitEvent.User.ID
default:
return nil, fmt.Errorf("event %s is not supported", event.EventType)
return nil, fmt.Errorf("event %s is not supported", event)
}

processedEvent.Event = eventInt

// Remove the " Hook" suffix so looks better in status, and since we don't
// really use it anymore we good to do whatever we want with it for
// cosmetics.
processedEvent.EventType = strings.ReplaceAll(event.EventType, " Hook", "")
processedEvent.EventType = strings.ReplaceAll(event, " Hook", "")

v.repoURL = processedEvent.URL
return processedEvent, nil
Expand Down
142 changes: 121 additions & 21 deletions pkg/provider/gitlab/gitlab_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"github.com/openshift-pipelines/pipelines-as-code/pkg/provider"
thelp "github.com/openshift-pipelines/pipelines-as-code/pkg/provider/gitlab/test"
"github.com/xanzy/go-gitlab"
"go.uber.org/zap"
zapobserver "go.uber.org/zap/zaptest/observer"
"gotest.tools/v3/assert"
rtesting "knative.dev/pkg/reconciler/testing"
)
Expand Down Expand Up @@ -173,8 +175,6 @@ func TestCreateStatus(t *testing.T) {
}

func TestParsePayload(t *testing.T) {
// TODO: fix event parsing logic
t.Skip()
sample := thelp.TEvent{
Username: "foo",
DefaultBranch: "main",
Expand All @@ -197,7 +197,7 @@ func TestParsePayload(t *testing.T) {
userID int
}
type args struct {
// event *info.Event
event gitlab.EventType
payload string
}
tests := []struct {
Expand All @@ -212,26 +212,22 @@ func TestParsePayload(t *testing.T) {
name: "bad payload",
args: args{
payload: "nono",
// event: &info.Event{EventType: "none"},
event: "none",
},
wantErr: true,
},
{
name: "event not supported",
args: args{
// event: &info.Event{
// EventType: string(gitlab.EventTypePipeline),
// },
event: gitlab.EventTypePipeline,
payload: sample.MREventAsJSON(),
},
wantErr: true,
},
{
name: "merge event",
args: args{
// event: &info.Event{
// EventType: string(gitlab.EventTypeMergeRequest),
// },
event: gitlab.EventTypeMergeRequest,
payload: sample.MREventAsJSON(),
},
want: &info.Event{
Expand All @@ -244,19 +240,15 @@ func TestParsePayload(t *testing.T) {
{
name: "push event no commits",
args: args{
// event: &info.Event{
// EventType: string(gitlab.EventTypePush),
// },
event: gitlab.EventTypePush,
payload: sample.PushEventAsJSON(false),
},
wantErr: true,
},
{
name: "push event",
args: args{
// event: &info.Event{
// EventType: string(gitlab.EventTypePush),
// },
event: gitlab.EventTypePush,
payload: sample.PushEventAsJSON(true),
},
want: &info.Event{
Expand All @@ -270,10 +262,8 @@ func TestParsePayload(t *testing.T) {
{
name: "note event",
args: args{
// event: &info.Event{
// EventType: string(gitlab.EventTypeNote),
// },
payload: sample.NoteEventAsJSON(),
event: gitlab.EventTypeNote,
payload: sample.NoteEventAsJSON(""),
},
want: &info.Event{
EventType: "Note",
Expand Down Expand Up @@ -302,7 +292,10 @@ func TestParsePayload(t *testing.T) {
Info: info.Info{},
}

got, err := v.ParsePayload(ctx, run, &http.Request{}, tt.args.payload)
request := &http.Request{Header: map[string][]string{}}
request.Header.Set("X-Gitlab-Event", string(tt.args.event))

got, err := v.ParsePayload(ctx, run, request, tt.args.payload)
if (err != nil) != tt.wantErr {
t.Errorf("ParsePayload() error = %v, wantErr %v", err, tt.wantErr)
return
Expand Down Expand Up @@ -471,3 +464,110 @@ func TestGetFileInsideRepo(t *testing.T) {
_, err = v.GetFileInsideRepo(ctx, event, "notfound", "")
assert.Assert(t, err != nil)
}

func TestProvider_Detect(t *testing.T) {
sample := thelp.TEvent{
Username: "foo",
DefaultBranch: "main",
URL: "https://foo.com",
SHA: "sha",
SHAurl: "https://url",
SHAtitle: "commit it",
Headbranch: "branch",
Basebranch: "main",
UserID: 10,
MRID: 1,
TargetProjectID: 100,
SourceProjectID: 200,
PathWithNameSpace: "hello/this/is/me/ze/project",
}
tests := []struct {
name string
wantErrString string
isGL bool
processReq bool
event string
eventType gitlab.EventType
}{
{
name: "not a gitlab Event",
eventType: "",
isGL: false,
processReq: false,
},
{
name: "invalid gitlab Event",
eventType: "invalid",
wantErrString: "unexpected event type: invalid",
isGL: false,
processReq: false,
},
{
name: "valid merge Event",
event: sample.MREventAsJSON(),
eventType: gitlab.EventTypeMergeRequest,
isGL: true,
processReq: true,
},
{
name: "issue note event with no valid comment",
event: sample.NoteEventAsJSON("abc"),
eventType: gitlab.EventTypeNote,
isGL: true,
processReq: false,
},
{
name: "issue note Event with ok-to-test comment",
event: sample.NoteEventAsJSON("/ok-to-test"),
eventType: gitlab.EventTypeNote,
isGL: true,
processReq: true,
},
{
name: "issue comment Event with ok-to-test and some string",
event: sample.NoteEventAsJSON("abc /ok-to-test"),
eventType: gitlab.EventTypeNote,
isGL: true,
processReq: false,
},
{
name: "issue comment Event with retest",
event: sample.NoteEventAsJSON("/retest"),
eventType: gitlab.EventTypeNote,
isGL: true,
processReq: true,
},
{
name: "push event",
event: sample.PushEventAsJSON(true),
eventType: gitlab.EventTypePush,
isGL: true,
processReq: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gprovider := Provider{}
logger := getLogger()

header := &http.Header{}
header.Set("X-Gitlab-Event", string(tt.eventType))

isGL, processReq, _, err := gprovider.Detect(header, tt.event, logger)
if tt.wantErrString != "" {
assert.ErrorContains(t, err, tt.wantErrString)
return
}
assert.NilError(t, err)
assert.Equal(t, tt.isGL, isGL)
assert.Equal(t, tt.processReq, processReq)
})
}
}

func getLogger() *zap.SugaredLogger {
observer, _ := zapobserver.New(zap.InfoLevel)
logger := zap.New(observer).Sugar()
return logger
}
10 changes: 6 additions & 4 deletions pkg/provider/gitlab/test/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func MuxGetFile(t *testing.T, mux *http.ServeMux, pid int, fname, content string
type TEvent struct {
Username, DefaultBranch, URL, SHA, SHAurl, SHAtitle, Headbranch, Basebranch string
UserID, MRID, TargetProjectID, SourceProjectID int
PathWithNameSpace string
PathWithNameSpace, Comment string
}

func (t TEvent) PushEventAsJSON(withcommits bool) string {
Expand Down Expand Up @@ -135,13 +135,14 @@ func (t TEvent) PushEventAsJSON(withcommits bool) string {
return jeez
}

func (t TEvent) NoteEventAsJSON() string {
func (t TEvent) NoteEventAsJSON(comment string) string {
// nolint:misspell
return fmt.Sprintf(`{
"object_kind": "note",
"event_type": "note",
"object_attributes": {
"noteable_type": "MergeRequest"
"noteable_type": "MergeRequest",
"note": "%s"
},
"user": {
"username": "%s"
Expand All @@ -152,6 +153,7 @@ func (t TEvent) NoteEventAsJSON() string {
"path_with_namespace": "%s"
},
"merge_request": {
"state": "opened",
"iid": %d,
"target_project_id": %d,
"source_project_id": %d,
Expand All @@ -164,7 +166,7 @@ func (t TEvent) NoteEventAsJSON() string {
"message": "%s"
}
}
}`, t.Username, t.DefaultBranch, t.URL, t.PathWithNameSpace, t.MRID, t.TargetProjectID, t.SourceProjectID, t.Basebranch, t.Headbranch, t.SHA, t.SHAurl, t.SHAtitle, t.SHAtitle)
}`, comment, t.Username, t.DefaultBranch, t.URL, t.PathWithNameSpace, t.MRID, t.TargetProjectID, t.SourceProjectID, t.Basebranch, t.Headbranch, t.SHA, t.SHAurl, t.SHAtitle, t.SHAtitle)
}

func (t TEvent) MREventAsJSON() string {
Expand Down
1 change: 0 additions & 1 deletion test/gitlab_merge_request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (
)

func TestGitlabMergeRequest(t *testing.T) {
t.Skip()
targetNS := names.SimpleNameGenerator.RestrictLengthWithRandomSuffix("pac-e2e-ns")
ctx := context.Background()
runcnx, opts, glprovider, err := tgitlab.Setup(ctx)
Expand Down

0 comments on commit ed7787b

Please sign in to comment.