Skip to content

Commit d2ba663

Browse files
committed
initial commit
0 parents  commit d2ba663

File tree

7 files changed

+416
-0
lines changed

7 files changed

+416
-0
lines changed

fn.go

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"github.com/aws/aws-lambda-go/events"
7+
"github.com/aws/aws-lambda-go/lambda"
8+
)
9+
10+
func GenerateResponse(Body string, Code int) events.APIGatewayProxyResponse {
11+
return events.APIGatewayProxyResponse{Body: Body, StatusCode: Code}
12+
}
13+
func HandleRequest(_ context.Context, request events.LambdaFunctionURLRequest) (events.APIGatewayProxyResponse, error) {
14+
//fmt.Printf("Body: %s", request.Body)
15+
//fmt.Printf("Headers: %v", request.Headers)
16+
17+
_, _, err := ParseWebHookJSON("", request)
18+
if err != nil {
19+
fmt.Printf("error: %v\n", err)
20+
}
21+
//fmt.Printf("gitlabEvent: %s\n", gitlabEvent)
22+
//fmt.Printf("webhook: %s\n", spew.Sdump(webhook))
23+
return GenerateResponse("Hello World", 200), nil
24+
}
25+
func main() {
26+
lambda.Start(HandleRequest)
27+
}

fn_test.go

+203
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
package main
2+
3+
import (
4+
"testing"
5+
)
6+
7+
var newMergeRequestJson = `{
8+
"object_kind": "pipeline",
9+
"object_attributes": {
10+
"id": 827393613,
11+
"iid": 40,
12+
"ref": "test_webhook_new_mr",
13+
"tag": false,
14+
"sha": "9d3bb4e65e705096fda282e3295fdd4b30d9207d",
15+
"before_sha": "0000000000000000000000000000000000000000",
16+
"source": "merge_request_event",
17+
"status": "failed",
18+
"detailed_status": "failed",
19+
"stages": [
20+
"env",
21+
"install",
22+
"digger"
23+
],
24+
"created_at": "2023-04-04 09:41:07 UTC",
25+
"finished_at": "2023-04-04 09:44:00 UTC",
26+
"duration": 171,
27+
"queued_duration": null,
28+
"variables": []
29+
},
30+
"merge_request": {
31+
"id": 215484580,
32+
"iid": 8,
33+
"title": "Update main.tf",
34+
"source_branch": "test_webhook_new_mr",
35+
"source_project_id": 44723537,
36+
"target_branch": "main",
37+
"target_project_id": 44723537,
38+
"state": "opened",
39+
"merge_status": "can_be_merged",
40+
"detailed_merge_status": "mergeable",
41+
"url": "https://gitlab.com/diggerdev/digger-demo/-/merge_requests/8"
42+
},
43+
"user": {
44+
"id": 13159253,
45+
"name": "Alexey Skriptsov",
46+
"username": "alexey_digger",
47+
"avatar_url": "https://secure.gravatar.com/avatar/2fbee1042b15f82c532c9f52002cb2d1?s=80&d=identicon",
48+
"email": "[REDACTED]"
49+
},
50+
"project": {
51+
"id": 44723537,
52+
"name": "Digger Demo",
53+
"description": null,
54+
"web_url": "https://gitlab.com/diggerdev/digger-demo",
55+
"avatar_url": null,
56+
"git_ssh_url": "[email protected]:diggerdev/digger-demo.git",
57+
"git_http_url": "https://gitlab.com/diggerdev/digger-demo.git",
58+
"namespace": "diggerdev",
59+
"visibility_level": 0,
60+
"path_with_namespace": "diggerdev/digger-demo",
61+
"default_branch": "main",
62+
"ci_config_path": ""
63+
},
64+
"commit": {
65+
"id": "9d3bb4e65e705096fda282e3295fdd4b30d9207d",
66+
"message": "Update main.tf",
67+
"title": "Update main.tf",
68+
"timestamp": "2023-04-04T09:40:59+00:00",
69+
"url": "https://gitlab.com/diggerdev/digger-demo/-/commit/9d3bb4e65e705096fda282e3295fdd4b30d9207d",
70+
"author": {
71+
"name": "Alexey Skriptsov",
72+
"email": "[email protected]"
73+
}
74+
},
75+
"builds": [
76+
{
77+
"id": 4057216008,
78+
"stage": "digger",
79+
"name": "run_digger",
80+
"status": "skipped",
81+
"created_at": "2023-04-04 09:41:07 UTC",
82+
"started_at": null,
83+
"finished_at": null,
84+
"duration": null,
85+
"queued_duration": null,
86+
"failure_reason": null,
87+
"when": "on_success",
88+
"manual": false,
89+
"allow_failure": false,
90+
"user": {
91+
"id": 13159253,
92+
"name": "Alexey Skriptsov",
93+
"username": "alexey_digger",
94+
"avatar_url": "https://secure.gravatar.com/avatar/2fbee1042b15f82c532c9f52002cb2d1?s=80&d=identicon",
95+
"email": "[REDACTED]"
96+
},
97+
"runner": null,
98+
"artifacts_file": {
99+
"filename": null,
100+
"size": null
101+
},
102+
"environment": null
103+
},
104+
{
105+
"id": 4057216005,
106+
"stage": "env",
107+
"name": "display_env",
108+
"status": "success",
109+
"created_at": "2023-04-04 09:41:07 UTC",
110+
"started_at": "2023-04-04 09:41:08 UTC",
111+
"finished_at": "2023-04-04 09:41:47 UTC",
112+
"duration": 38.787836,
113+
"queued_duration": 0.101601,
114+
"failure_reason": null,
115+
"when": "on_success",
116+
"manual": false,
117+
"allow_failure": false,
118+
"user": {
119+
"id": 13159253,
120+
"name": "Alexey Skriptsov",
121+
"username": "alexey_digger",
122+
"avatar_url": "https://secure.gravatar.com/avatar/2fbee1042b15f82c532c9f52002cb2d1?s=80&d=identicon",
123+
"email": "[REDACTED]"
124+
},
125+
"runner": {
126+
"id": 12270807,
127+
"description": "1-blue.shared.runners-manager.gitlab.com/default",
128+
"runner_type": "instance_type",
129+
"active": true,
130+
"is_shared": true,
131+
"tags": [
132+
"gce",
133+
"east-c",
134+
"linux",
135+
"ruby",
136+
"mysql",
137+
"postgres",
138+
"mongo",
139+
"git-annex",
140+
"shared",
141+
"docker",
142+
"saas-linux-small-amd64"
143+
]
144+
},
145+
"artifacts_file": {
146+
"filename": null,
147+
"size": null
148+
},
149+
"environment": null
150+
},
151+
{
152+
"id": 4057216007,
153+
"stage": "install",
154+
"name": "install_digger",
155+
"status": "failed",
156+
"created_at": "2023-04-04 09:41:07 UTC",
157+
"started_at": "2023-04-04 09:41:47 UTC",
158+
"finished_at": "2023-04-04 09:44:00 UTC",
159+
"duration": 132.961562,
160+
"queued_duration": 0.144775,
161+
"failure_reason": "script_failure",
162+
"when": "on_success",
163+
"manual": false,
164+
"allow_failure": false,
165+
"user": {
166+
"id": 13159253,
167+
"name": "Alexey Skriptsov",
168+
"username": "alexey_digger",
169+
"avatar_url": "https://secure.gravatar.com/avatar/2fbee1042b15f82c532c9f52002cb2d1?s=80&d=identicon",
170+
"email": "[REDACTED]"
171+
},
172+
"runner": {
173+
"id": 12270807,
174+
"description": "1-blue.shared.runners-manager.gitlab.com/default",
175+
"runner_type": "instance_type",
176+
"active": true,
177+
"is_shared": true,
178+
"tags": [
179+
"gce",
180+
"east-c",
181+
"linux",
182+
"ruby",
183+
"mysql",
184+
"postgres",
185+
"mongo",
186+
"git-annex",
187+
"shared",
188+
"docker",
189+
"saas-linux-small-amd64"
190+
]
191+
},
192+
"artifacts_file": {
193+
"filename": null,
194+
"size": null
195+
},
196+
"environment": null
197+
}
198+
]
199+
}`
200+
201+
func TestBitbucketPullRequestCommentCreated(t *testing.T) {
202+
203+
}

gitlab.go

+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"github.com/aws/aws-lambda-go/events"
7+
"github.com/xanzy/go-gitlab"
8+
"log"
9+
"os"
10+
"strings"
11+
)
12+
13+
func ParseWebHookJSON(secret string, lambdaRequest events.LambdaFunctionURLRequest) (interface{}, string, error) {
14+
// If we have a secret set, we should check if the request matches it.
15+
if len(secret) > 0 {
16+
signature := lambdaRequest.Headers["x-gitlab-token"]
17+
if signature != secret {
18+
return nil, "", errors.New("token validation failed")
19+
}
20+
}
21+
22+
gitlabEvent := lambdaRequest.Headers["x-gitlab-event"]
23+
if strings.TrimSpace(gitlabEvent) == "" {
24+
return nil, "", errors.New("missing X-Gitlab-Event Header")
25+
}
26+
27+
fmt.Printf("gitlabEvent: %s\n", gitlabEvent)
28+
29+
eventType := gitlab.EventType(gitlabEvent)
30+
31+
payload := lambdaRequest.Body
32+
if len(payload) == 0 {
33+
return nil, gitlabEvent, errors.New("request body is empty")
34+
}
35+
payloadBytes := []byte(payload)
36+
37+
result, err := gitlab.ParseWebhook(eventType, payloadBytes)
38+
if err != nil {
39+
return nil, gitlabEvent, fmt.Errorf("failed to parse webhook event: %w\n", err)
40+
}
41+
42+
switch eventType {
43+
case gitlab.EventTypeMergeRequest:
44+
event := result.(*gitlab.MergeEvent)
45+
projectId := event.Project.ID
46+
pipelineId := event.ObjectAttributes.HeadPipelineID
47+
branchName := event.ObjectAttributes.SourceBranch
48+
fmt.Printf("event action: %s\n", event.ObjectAttributes.Action)
49+
fmt.Printf("event ObjectKind: %s\n", event.ObjectKind)
50+
switch event.ObjectAttributes.Action {
51+
case "open":
52+
err := TriggerPipeline(projectId, *pipelineId, branchName, "merge_request_opened")
53+
if err != nil {
54+
return nil, "TriggerPipeline error", err
55+
}
56+
case "close":
57+
err := TriggerPipeline(projectId, *pipelineId, branchName, "merge_request_closed")
58+
if err != nil {
59+
return nil, "TriggerPipeline error", err
60+
}
61+
case "reopen":
62+
err := TriggerPipeline(projectId, *pipelineId, branchName, "merge_request_updated")
63+
if err != nil {
64+
return nil, "TriggerPipeline error", err
65+
}
66+
case "update":
67+
err := TriggerPipeline(projectId, *pipelineId, branchName, "merge_request_updated")
68+
if err != nil {
69+
return nil, "TriggerPipeline error", err
70+
}
71+
case "approved":
72+
case "unapproved":
73+
case "approval":
74+
case "unapproval":
75+
case "merge":
76+
err := TriggerPipeline(projectId, *pipelineId, branchName, "merge_request_closed")
77+
if err != nil {
78+
return nil, "TriggerPipeline error", err
79+
}
80+
81+
default:
82+
return nil, gitlabEvent, fmt.Errorf("unknown gitlab event action %s\n", event.ObjectAttributes.Action)
83+
}
84+
default:
85+
86+
}
87+
88+
fmt.Println("webhook event parsed successfully")
89+
90+
return result, gitlabEvent, nil
91+
}
92+
93+
func TriggerPipeline(projectId int, pipelineId int, branchName string, eventType string) error {
94+
gitlabToken := os.Getenv("GITLAB_TOKEN")
95+
if gitlabToken == "" {
96+
return fmt.Errorf("GITLAB_TOKEN has not been set\n")
97+
}
98+
git, err := gitlab.NewClient(gitlabToken)
99+
if err != nil {
100+
log.Fatal(err)
101+
}
102+
103+
pipeline, r, err := git.Pipelines.GetPipeline(projectId, pipelineId)
104+
if err != nil {
105+
log.Fatal(err)
106+
}
107+
108+
variables := make([]*gitlab.PipelineVariableOptions, 0)
109+
variables = append(variables, &gitlab.PipelineVariableOptions{
110+
Key: gitlab.String("MERGE_REQUEST_EVENT_NAME"),
111+
Value: gitlab.String(eventType),
112+
VariableType: gitlab.String("env_var"),
113+
})
114+
115+
opt := &gitlab.CreatePipelineOptions{Ref: &branchName, Variables: &variables}
116+
117+
build, r2, err := git.Pipelines.CreatePipeline(projectId, opt)
118+
if err != nil {
119+
log.Fatal(err)
120+
}
121+
println(pipeline)
122+
fmt.Printf("build %v\n", build)
123+
println(r)
124+
println(r2)
125+
return nil
126+
}

go.mod

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
module gitlab-webhook-lambda
2+
3+
go 1.20
4+
5+
require (
6+
github.com/aws/aws-lambda-go v1.39.1
7+
github.com/davecgh/go-spew v1.1.1
8+
github.com/tidwall/gjson v1.14.4
9+
github.com/xanzy/go-gitlab v0.81.0
10+
)
11+
12+
require (
13+
github.com/golang/protobuf v1.5.3 // indirect
14+
github.com/google/go-querystring v1.1.0 // indirect
15+
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
16+
github.com/hashicorp/go-retryablehttp v0.7.2 // indirect
17+
github.com/tidwall/match v1.1.1 // indirect
18+
github.com/tidwall/pretty v1.2.0 // indirect
19+
golang.org/x/net v0.8.0 // indirect
20+
golang.org/x/oauth2 v0.6.0 // indirect
21+
golang.org/x/time v0.3.0 // indirect
22+
google.golang.org/appengine v1.6.7 // indirect
23+
google.golang.org/protobuf v1.29.0 // indirect
24+
)

package.json

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"name": "gitlab-webhook-lambda",
3+
"version": "1.0.0",
4+
"description": "GitLab webhook lambda",
5+
"scripts": {
6+
"build": "env GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o bin/gitlab-webhook-lambda .",
7+
"deploy": "serverless deploy "
8+
}
9+
}

readme.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
3+
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o ./bin/gitlab-webhook-lambda fn.go

0 commit comments

Comments
 (0)