Skip to content

Commit 46dd1e5

Browse files
authored
Merge pull request #38 from kterada0509/feature/add-support-for-gitlab
Add support for gitlab and gitlab-ci
2 parents c6c949c + 555418a commit 46dd1e5

17 files changed

+1262
-0
lines changed

Gopkg.lock

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,54 @@ terraform:
173173
174174
</details>
175175
176+
<details>
177+
<summary>For GitLab</summary>
178+
179+
```yaml
180+
---
181+
ci: gitlabci
182+
notifier:
183+
gitlab:
184+
token: $GITLAB_TOKEN
185+
base_url: $GITLAB_BASE_URL
186+
repository:
187+
owner: "mercari"
188+
name: "tfnotify"
189+
terraform:
190+
fmt:
191+
template: |
192+
{{ .Title }}
193+
194+
{{ .Message }}
195+
196+
{{ .Result }}
197+
198+
{{ .Body }}
199+
plan:
200+
template: |
201+
{{ .Title }} <sup>[CI link]( {{ .Link }} )</sup>
202+
{{ .Message }}
203+
{{if .Result}}
204+
<pre><code> {{ .Result }}
205+
</pre></code>
206+
{{end}}
207+
<details><summary>Details (Click me)</summary>
208+
<pre><code> {{ .Body }}
209+
</pre></code></details>
210+
apply:
211+
template: |
212+
{{ .Title }}
213+
{{ .Message }}
214+
{{if .Result}}
215+
<pre><code> {{ .Result }}
216+
</pre></code>
217+
{{end}}
218+
<details><summary>Details (Click me)</summary>
219+
<pre><code> {{ .Body }}
220+
</pre></code></details>
221+
```
222+
</details>
223+
176224
<details>
177225
<summary>For Slack</summary>
178226
@@ -236,6 +284,7 @@ Currently, supported CI are here:
236284
- TeamCity
237285
- Drone
238286
- Jenkins
287+
- GitLab CI
239288
240289
### Private Repository Considerations
241290
GitHub private repositories require the `repo` and `write:discussion` permissions.

ci.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,23 @@ func jenkins() (ci CI, err error) {
101101
}
102102
return ci, err
103103
}
104+
105+
func gitlabci() (ci CI, err error) {
106+
ci.PR.Number = 0
107+
ci.PR.Revision = os.Getenv("CI_COMMIT_SHA")
108+
ci.URL = os.Getenv("CI_JOB_URL")
109+
pr := os.Getenv("CI_MERGE_REQUEST_IID")
110+
if pr == "" {
111+
refPath := os.Getenv("CI_MERGE_REQUEST_REF_PATH")
112+
rep := regexp.MustCompile(`refs/merge-requests/\d*/head`)
113+
if rep.MatchString(refPath) {
114+
strLen := strings.Split(refPath, "/")
115+
pr = strLen[2]
116+
}
117+
}
118+
if pr == "" {
119+
return ci, nil
120+
}
121+
ci.PR.Number, err = strconv.Atoi(pr)
122+
return ci, err
123+
}

ci_test.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,3 +536,89 @@ func TestJenkins(t *testing.T) {
536536
}
537537
}
538538
}
539+
540+
func TestGitLabCI(t *testing.T) {
541+
envs := []string{
542+
"CI_COMMIT_SHA",
543+
"CI_JOB_URL",
544+
"CI_MERGE_REQUEST_IID",
545+
"CI_MERGE_REQUEST_REF_PATH",
546+
}
547+
saveEnvs := make(map[string]string)
548+
for _, key := range envs {
549+
saveEnvs[key] = os.Getenv(key)
550+
os.Unsetenv(key)
551+
}
552+
defer func() {
553+
for key, value := range saveEnvs {
554+
os.Setenv(key, value)
555+
}
556+
}()
557+
558+
// https://docs.gitlab.com/ee/ci/variables/README.html
559+
testCases := []struct {
560+
fn func()
561+
ci CI
562+
ok bool
563+
}{
564+
{
565+
fn: func() {
566+
os.Setenv("CI_COMMIT_SHA", "abcdefg")
567+
os.Setenv("CI_JOB_URL", "https://gitlab.com/owner/repo/-/jobs/111111111")
568+
os.Setenv("CI_MERGE_REQUEST_IID", "1")
569+
os.Setenv("CI_MERGE_REQUEST_REF_PATH", "refs/merge-requests/1/head")
570+
},
571+
ci: CI{
572+
PR: PullRequest{
573+
Revision: "abcdefg",
574+
Number: 1,
575+
},
576+
URL: "https://gitlab.com/owner/repo/-/jobs/111111111",
577+
},
578+
ok: true,
579+
},
580+
{
581+
fn: func() {
582+
os.Setenv("CI_COMMIT_SHA", "hijklmn")
583+
os.Setenv("CI_JOB_URL", "https://gitlab.com/owner/repo/-/jobs/222222222")
584+
os.Setenv("CI_MERGE_REQUEST_REF_PATH", "refs/merge-requests/123/head")
585+
os.Unsetenv("CI_MERGE_REQUEST_IID")
586+
},
587+
ci: CI{
588+
PR: PullRequest{
589+
Revision: "hijklmn",
590+
Number: 123,
591+
},
592+
URL: "https://gitlab.com/owner/repo/-/jobs/222222222",
593+
},
594+
ok: true,
595+
},
596+
{
597+
fn: func() {
598+
os.Setenv("CI_COMMIT_SHA", "hijklmn")
599+
os.Setenv("CI_JOB_URL", "https://gitlab.com/owner/repo/-/jobs/333333333")
600+
os.Unsetenv("CI_MERGE_REQUEST_IID")
601+
os.Unsetenv("CI_MERGE_REQUEST_REF_PATH")
602+
},
603+
ci: CI{
604+
PR: PullRequest{
605+
Revision: "hijklmn",
606+
Number: 0,
607+
},
608+
URL: "https://gitlab.com/owner/repo/-/jobs/333333333",
609+
},
610+
ok: true,
611+
},
612+
}
613+
614+
for _, testCase := range testCases {
615+
testCase.fn()
616+
ci, err := gitlabci()
617+
if !reflect.DeepEqual(ci, testCase.ci) {
618+
t.Errorf("got %q but want %q", ci, testCase.ci)
619+
}
620+
if (err == nil) != testCase.ok {
621+
t.Errorf("got error %q", err)
622+
}
623+
}
624+
}

config/config.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ type Config struct {
2222
// Notifier is a notification notifier
2323
type Notifier struct {
2424
Github GithubNotifier `yaml:"github"`
25+
Gitlab GitlabNotifier `yaml:"gitlab"`
2526
Slack SlackNotifier `yaml:"slack"`
2627
Typetalk TypetalkNotifier `yaml:"typetalk"`
2728
}
@@ -33,6 +34,13 @@ type GithubNotifier struct {
3334
Repository Repository `yaml:"repository"`
3435
}
3536

37+
// GitlabNotifier is a notifier for GitLab
38+
type GitlabNotifier struct {
39+
Token string `yaml:"token"`
40+
BaseURL string `yaml:"base_url"`
41+
Repository Repository `yaml:"repository"`
42+
}
43+
3644
// Repository represents a GitHub repository
3745
type Repository struct {
3846
Owner string `yaml:"owner"`
@@ -98,6 +106,8 @@ func (cfg *Config) Validation() error {
98106
return errors.New("ci: need to be set")
99107
case "circleci", "circle-ci":
100108
// ok pattern
109+
case "gitlabci", "gitlab-ci":
110+
// ok pattern
101111
case "travis", "travisci", "travis-ci":
102112
// ok pattern
103113
case "codebuild":
@@ -119,6 +129,14 @@ func (cfg *Config) Validation() error {
119129
return fmt.Errorf("repository name is missing")
120130
}
121131
}
132+
if cfg.isDefinedGitlab() {
133+
if cfg.Notifier.Gitlab.Repository.Owner == "" {
134+
return fmt.Errorf("repository owner is missing")
135+
}
136+
if cfg.Notifier.Gitlab.Repository.Name == "" {
137+
return fmt.Errorf("repository name is missing")
138+
}
139+
}
122140
if cfg.isDefinedSlack() {
123141
if cfg.Notifier.Slack.Channel == "" {
124142
return fmt.Errorf("slack channel id is missing")
@@ -141,6 +159,11 @@ func (cfg *Config) isDefinedGithub() bool {
141159
return cfg.Notifier.Github != (GithubNotifier{})
142160
}
143161

162+
func (cfg *Config) isDefinedGitlab() bool {
163+
// not empty
164+
return cfg.Notifier.Gitlab != (GitlabNotifier{})
165+
}
166+
144167
func (cfg *Config) isDefinedSlack() bool {
145168
// not empty
146169
return cfg.Notifier.Slack != (SlackNotifier{})
@@ -156,6 +179,9 @@ func (cfg *Config) GetNotifierType() string {
156179
if cfg.isDefinedGithub() {
157180
return "github"
158181
}
182+
if cfg.isDefinedGitlab() {
183+
return "gitlab"
184+
}
159185
if cfg.isDefinedSlack() {
160186
return "slack"
161187
}

config/config_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,10 @@ func TestValidation(t *testing.T) {
151151
contents: []byte("ci: jenkins\n"),
152152
expected: "notifier is missing",
153153
},
154+
{
155+
contents: []byte("ci: gitlabci\n"),
156+
expected: "notifier is missing",
157+
},
154158
{
155159
contents: []byte("ci: circleci\nnotifier:\n github:\n"),
156160
expected: "notifier is missing",
@@ -220,6 +224,47 @@ notifier:
220224
{
221225
contents: []byte(`
222226
ci: circleci
227+
notifier:
228+
typetalk:
229+
token: token
230+
topic_id: 12345
231+
`),
232+
expected: "",
233+
},
234+
{
235+
contents: []byte(`
236+
ci: gitlabci
237+
notifier:
238+
gitlab:
239+
token: token
240+
repository:
241+
owner: owner
242+
`),
243+
expected: "repository name is missing",
244+
},
245+
{
246+
contents: []byte(`
247+
ci: gitlabci
248+
notifier:
249+
slack:
250+
`),
251+
expected: "notifier is missing",
252+
},
253+
{
254+
contents: []byte(`
255+
ci: gitlabci
256+
notifier:
257+
gitlab:
258+
token: token
259+
repository:
260+
owner: owner
261+
name: name
262+
`),
263+
expected: "",
264+
},
265+
{
266+
contents: []byte(`
267+
ci: gitlabci
223268
notifier:
224269
typetalk:
225270
token: token
@@ -272,6 +317,10 @@ func TestGetNotifierType(t *testing.T) {
272317
contents: []byte("repository:\n owner: a\n name: b\nci: circleci\nnotifier:\n typetalk:\n token: token\n"),
273318
expected: "typetalk",
274319
},
320+
{
321+
contents: []byte("repository:\n owner: a\n name: b\nci: gitlabci\nnotifier:\n gitlab:\n token: token\n"),
322+
expected: "gitlab",
323+
},
275324
}
276325
for _, testCase := range testCases {
277326
cfg, err := helperLoadConfig(testCase.contents)

main.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/mercari/tfnotify/config"
99
"github.com/mercari/tfnotify/notifier"
1010
"github.com/mercari/tfnotify/notifier/github"
11+
"github.com/mercari/tfnotify/notifier/gitlab"
1112
"github.com/mercari/tfnotify/notifier/slack"
1213
"github.com/mercari/tfnotify/notifier/typetalk"
1314
"github.com/mercari/tfnotify/terraform"
@@ -68,6 +69,11 @@ func (t *tfnotify) Run() error {
6869
if err != nil {
6970
return err
7071
}
72+
case "gitlabci", "gitlab-ci":
73+
ci, err = gitlabci()
74+
if err != nil {
75+
return err
76+
}
7177
case "":
7278
return fmt.Errorf("CI service: required (e.g. circleci)")
7379
default:
@@ -101,6 +107,26 @@ func (t *tfnotify) Run() error {
101107
return err
102108
}
103109
notifier = client.Notify
110+
case "gitlab":
111+
client, err := gitlab.NewClient(gitlab.Config{
112+
Token: t.config.Notifier.Gitlab.Token,
113+
BaseURL: t.config.Notifier.Gitlab.BaseURL,
114+
NameSpace: t.config.Notifier.Gitlab.Repository.Owner,
115+
Project: t.config.Notifier.Gitlab.Repository.Name,
116+
MR: gitlab.MergeRequest{
117+
Revision: ci.PR.Revision,
118+
Number: ci.PR.Number,
119+
Title: t.context.String("title"),
120+
Message: t.context.String("message"),
121+
},
122+
CI: ci.URL,
123+
Parser: t.parser,
124+
Template: t.template,
125+
})
126+
if err != nil {
127+
return err
128+
}
129+
notifier = client.Notify
104130
case "slack":
105131
client, err := slack.NewClient(slack.Config{
106132
Token: t.config.Notifier.Slack.Token,

0 commit comments

Comments
 (0)