services.go

  1//
  2// Copyright 2017, Sander van Harmelen
  3//
  4// Licensed under the Apache License, Version 2.0 (the "License");
  5// you may not use this file except in compliance with the License.
  6// You may obtain a copy of the License at
  7//
  8//     http://www.apache.org/licenses/LICENSE-2.0
  9//
 10// Unless required by applicable law or agreed to in writing, software
 11// distributed under the License is distributed on an "AS IS" BASIS,
 12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13// See the License for the specific language governing permissions and
 14// limitations under the License.
 15//
 16
 17package gitlab
 18
 19import (
 20	"encoding/json"
 21	"fmt"
 22	"strconv"
 23	"time"
 24)
 25
 26// ServicesService handles communication with the services related methods of
 27// the GitLab API.
 28//
 29// GitLab API docs: https://docs.gitlab.com/ce/api/services.html
 30type ServicesService struct {
 31	client *Client
 32}
 33
 34// Service represents a GitLab service.
 35//
 36// GitLab API docs: https://docs.gitlab.com/ce/api/services.html
 37type Service struct {
 38	ID                       int        `json:"id"`
 39	Title                    string     `json:"title"`
 40	CreatedAt                *time.Time `json:"created_at"`
 41	UpdatedAt                *time.Time `json:"updated_at"`
 42	Active                   bool       `json:"active"`
 43	PushEvents               bool       `json:"push_events"`
 44	IssuesEvents             bool       `json:"issues_events"`
 45	ConfidentialIssuesEvents bool       `json:"confidential_issues_events"`
 46	MergeRequestsEvents      bool       `json:"merge_requests_events"`
 47	TagPushEvents            bool       `json:"tag_push_events"`
 48	NoteEvents               bool       `json:"note_events"`
 49	ConfidentialNoteEvents   bool       `json:"confidential_note_events"`
 50	PipelineEvents           bool       `json:"pipeline_events"`
 51	JobEvents                bool       `json:"job_events"`
 52	WikiPageEvents           bool       `json:"wiki_page_events"`
 53}
 54
 55// SetGitLabCIServiceOptions represents the available SetGitLabCIService()
 56// options.
 57//
 58// GitLab API docs:
 59// https://docs.gitlab.com/ce/api/services.html#edit-gitlab-ci-service
 60type SetGitLabCIServiceOptions struct {
 61	Token      *string `url:"token,omitempty" json:"token,omitempty"`
 62	ProjectURL *string `url:"project_url,omitempty" json:"project_url,omitempty"`
 63}
 64
 65// SetGitLabCIService sets GitLab CI service for a project.
 66//
 67// GitLab API docs:
 68// https://docs.gitlab.com/ce/api/services.html#edit-gitlab-ci-service
 69func (s *ServicesService) SetGitLabCIService(pid interface{}, opt *SetGitLabCIServiceOptions, options ...OptionFunc) (*Response, error) {
 70	project, err := parseID(pid)
 71	if err != nil {
 72		return nil, err
 73	}
 74	u := fmt.Sprintf("projects/%s/services/gitlab-ci", pathEscape(project))
 75
 76	req, err := s.client.NewRequest("PUT", u, opt, options)
 77	if err != nil {
 78		return nil, err
 79	}
 80
 81	return s.client.Do(req, nil)
 82}
 83
 84// DeleteGitLabCIService deletes GitLab CI service settings for a project.
 85//
 86// GitLab API docs:
 87// https://docs.gitlab.com/ce/api/services.html#delete-gitlab-ci-service
 88func (s *ServicesService) DeleteGitLabCIService(pid interface{}, options ...OptionFunc) (*Response, error) {
 89	project, err := parseID(pid)
 90	if err != nil {
 91		return nil, err
 92	}
 93	u := fmt.Sprintf("projects/%s/services/gitlab-ci", pathEscape(project))
 94
 95	req, err := s.client.NewRequest("DELETE", u, nil, options)
 96	if err != nil {
 97		return nil, err
 98	}
 99
100	return s.client.Do(req, nil)
101}
102
103// SetHipChatServiceOptions represents the available SetHipChatService()
104// options.
105//
106// GitLab API docs:
107// https://docs.gitlab.com/ce/api/services.html#edit-hipchat-service
108type SetHipChatServiceOptions struct {
109	Token *string `url:"token,omitempty" json:"token,omitempty" `
110	Room  *string `url:"room,omitempty" json:"room,omitempty"`
111}
112
113// SetHipChatService sets HipChat service for a project
114//
115// GitLab API docs:
116// https://docs.gitlab.com/ce/api/services.html#edit-hipchat-service
117func (s *ServicesService) SetHipChatService(pid interface{}, opt *SetHipChatServiceOptions, options ...OptionFunc) (*Response, error) {
118	project, err := parseID(pid)
119	if err != nil {
120		return nil, err
121	}
122	u := fmt.Sprintf("projects/%s/services/hipchat", pathEscape(project))
123
124	req, err := s.client.NewRequest("PUT", u, opt, options)
125	if err != nil {
126		return nil, err
127	}
128
129	return s.client.Do(req, nil)
130}
131
132// DeleteHipChatService deletes HipChat service for project.
133//
134// GitLab API docs:
135// https://docs.gitlab.com/ce/api/services.html#delete-hipchat-service
136func (s *ServicesService) DeleteHipChatService(pid interface{}, options ...OptionFunc) (*Response, error) {
137	project, err := parseID(pid)
138	if err != nil {
139		return nil, err
140	}
141	u := fmt.Sprintf("projects/%s/services/hipchat", pathEscape(project))
142
143	req, err := s.client.NewRequest("DELETE", u, nil, options)
144	if err != nil {
145		return nil, err
146	}
147
148	return s.client.Do(req, nil)
149}
150
151// DroneCIService represents Drone CI service settings.
152//
153// GitLab API docs:
154// https://docs.gitlab.com/ce/api/services.html#drone-ci
155type DroneCIService struct {
156	Service
157	Properties *DroneCIServiceProperties `json:"properties"`
158}
159
160// DroneCIServiceProperties represents Drone CI specific properties.
161//
162// GitLab API docs:
163// https://docs.gitlab.com/ce/api/services.html#drone-ci
164type DroneCIServiceProperties struct {
165	Token                 string `json:"token"`
166	DroneURL              string `json:"drone_url"`
167	EnableSSLVerification bool   `json:"enable_ssl_verification"`
168}
169
170// GetDroneCIService gets Drone CI service settings for a project.
171//
172// GitLab API docs:
173// https://docs.gitlab.com/ce/api/services.html#get-drone-ci-service-settings
174func (s *ServicesService) GetDroneCIService(pid interface{}, options ...OptionFunc) (*DroneCIService, *Response, error) {
175	project, err := parseID(pid)
176	if err != nil {
177		return nil, nil, err
178	}
179	u := fmt.Sprintf("projects/%s/services/drone-ci", pathEscape(project))
180
181	req, err := s.client.NewRequest("GET", u, nil, options)
182	if err != nil {
183		return nil, nil, err
184	}
185
186	svc := new(DroneCIService)
187	resp, err := s.client.Do(req, svc)
188	if err != nil {
189		return nil, resp, err
190	}
191
192	return svc, resp, err
193}
194
195// SetDroneCIServiceOptions represents the available SetDroneCIService()
196// options.
197//
198// GitLab API docs:
199// https://docs.gitlab.com/ce/api/services.html#createedit-drone-ci-service
200type SetDroneCIServiceOptions struct {
201	Token                 *string `url:"token" json:"token" `
202	DroneURL              *string `url:"drone_url" json:"drone_url"`
203	EnableSSLVerification *bool   `url:"enable_ssl_verification,omitempty" json:"enable_ssl_verification,omitempty"`
204}
205
206// SetDroneCIService sets Drone CI service for a project.
207//
208// GitLab API docs:
209// https://docs.gitlab.com/ce/api/services.html#createedit-drone-ci-service
210func (s *ServicesService) SetDroneCIService(pid interface{}, opt *SetDroneCIServiceOptions, options ...OptionFunc) (*Response, error) {
211	project, err := parseID(pid)
212	if err != nil {
213		return nil, err
214	}
215	u := fmt.Sprintf("projects/%s/services/drone-ci", pathEscape(project))
216
217	req, err := s.client.NewRequest("PUT", u, opt, options)
218	if err != nil {
219		return nil, err
220	}
221
222	return s.client.Do(req, nil)
223}
224
225// DeleteDroneCIService deletes Drone CI service settings for a project.
226//
227// GitLab API docs:
228// https://docs.gitlab.com/ce/api/services.html#delete-drone-ci-service
229func (s *ServicesService) DeleteDroneCIService(pid interface{}, options ...OptionFunc) (*Response, error) {
230	project, err := parseID(pid)
231	if err != nil {
232		return nil, err
233	}
234	u := fmt.Sprintf("projects/%s/services/drone-ci", pathEscape(project))
235
236	req, err := s.client.NewRequest("DELETE", u, nil, options)
237	if err != nil {
238		return nil, err
239	}
240
241	return s.client.Do(req, nil)
242}
243
244// SlackService represents Slack service settings.
245//
246// GitLab API docs:
247// https://docs.gitlab.com/ce/api/services.html#slack
248type SlackService struct {
249	Service
250	Properties *SlackServiceProperties `json:"properties"`
251}
252
253// SlackServiceProperties represents Slack specific properties.
254//
255// GitLab API docs:
256// https://docs.gitlab.com/ce/api/services.html#slack
257type SlackServiceProperties struct {
258	WebHook                   string    `json:"webhook,omitempty"`
259	Username                  string    `json:"username,omitempty"`
260	Channel                   string    `json:"channel,omitempty"`
261	NotifyOnlyBrokenPipelines BoolValue `json:"notify_only_broken_pipelines,omitempty"`
262	NotifyOnlyDefaultBranch   BoolValue `json:"notify_only_default_branch,omitempty"`
263	ConfidentialIssueChannel  string    `json:"confidential_issue_channel,omitempty"`
264	ConfidentialNoteChannel   string    `json:"confidential_note_channel,omitempty"`
265	DeploymentChannel         string    `json:"deployment_channel,omitempty"`
266	IssueChannel              string    `json:"issue_channel,omitempty"`
267	MergeRequestChannel       string    `json:"merge_request_channel,omitempty"`
268	NoteChannel               string    `json:"note_channel,omitempty"`
269	TagPushChannel            string    `json:"tag_push_channel,omitempty"`
270	PipelineChannel           string    `json:"pipeline_channel,omitempty"`
271	PushChannel               string    `json:"push_channel,omitempty"`
272	WikiPageChannel           string    `json:"wiki_page_channel,omitempty"`
273}
274
275// GetSlackService gets Slack service settings for a project.
276//
277// GitLab API docs:
278// https://docs.gitlab.com/ce/api/services.html#get-slack-service-settings
279func (s *ServicesService) GetSlackService(pid interface{}, options ...OptionFunc) (*SlackService, *Response, error) {
280	project, err := parseID(pid)
281	if err != nil {
282		return nil, nil, err
283	}
284	u := fmt.Sprintf("projects/%s/services/slack", pathEscape(project))
285
286	req, err := s.client.NewRequest("GET", u, nil, options)
287	if err != nil {
288		return nil, nil, err
289	}
290
291	svc := new(SlackService)
292	resp, err := s.client.Do(req, svc)
293	if err != nil {
294		return nil, resp, err
295	}
296
297	return svc, resp, err
298}
299
300// SetSlackServiceOptions represents the available SetSlackService()
301// options.
302//
303// GitLab API docs:
304// https://docs.gitlab.com/ce/api/services.html#edit-slack-service
305type SetSlackServiceOptions struct {
306	WebHook                   *string `url:"webhook,omitempty" json:"webhook,omitempty"`
307	Username                  *string `url:"username,omitempty" json:"username,omitempty"`
308	Channel                   *string `url:"channel,omitempty" json:"channel,omitempty"`
309	NotifyOnlyBrokenPipelines *bool   `url:"notify_only_broken_pipelines,omitempty" json:"notify_only_broken_pipelines,omitempty"`
310	NotifyOnlyDefaultBranch   *bool   `url:"notify_only_default_branch,omitempty" json:"notify_only_default_branch,omitempty"`
311	ConfidentialIssueChannel  *string `url:"confidential_issue_channel,omitempty" json:"confidential_issue_channel,omitempty"`
312	ConfidentialIssuesEvents  *bool   `url:"confidential_issues_events,omitempty" json:"confidential_issues_events,omitempty"`
313	// TODO: Currently, GitLab ignores this option (not implemented yet?), so
314	// there is no way to set it. Uncomment when this is fixed.
315	// See: https://gitlab.com/gitlab-org/gitlab-ce/issues/49730
316	//ConfidentialNoteChannel   *string `json:"confidential_note_channel,omitempty"`
317	ConfidentialNoteEvents *bool   `url:"confidential_note_events,omitempty" json:"confidential_note_events,omitempty"`
318	DeploymentChannel      *string `url:"deployment_channel,omitempty" json:"deployment_channel,omitempty"`
319	DeploymentEvents       *bool   `url:"deployment_events,omitempty" json:"deployment_events,omitempty"`
320	IssueChannel           *string `url:"issue_channel,omitempty" json:"issue_channel,omitempty"`
321	IssuesEvents           *bool   `url:"issues_events,omitempty" json:"issues_events,omitempty"`
322	MergeRequestChannel    *string `url:"merge_request_channel,omitempty" json:"merge_request_channel,omitempty"`
323	MergeRequestsEvents    *bool   `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"`
324	TagPushChannel         *string `url:"tag_push_channel,omitempty" json:"tag_push_channel,omitempty"`
325	TagPushEvents          *bool   `url:"tag_push_events,omitempty" json:"tag_push_events,omitempty"`
326	NoteChannel            *string `url:"note_channel,omitempty" json:"note_channel,omitempty"`
327	NoteEvents             *bool   `url:"note_events,omitempty" json:"note_events,omitempty"`
328	PipelineChannel        *string `url:"pipeline_channel,omitempty" json:"pipeline_channel,omitempty"`
329	PipelineEvents         *bool   `url:"pipeline_events,omitempty" json:"pipeline_events,omitempty"`
330	PushChannel            *string `url:"push_channel,omitempty" json:"push_channel,omitempty"`
331	PushEvents             *bool   `url:"push_events,omitempty" json:"push_events,omitempty"`
332	WikiPageChannel        *string `url:"wiki_page_channel,omitempty" json:"wiki_page_channel,omitempty"`
333	WikiPageEvents         *bool   `url:"wiki_page_events,omitempty" json:"wiki_page_events,omitempty"`
334}
335
336// SetSlackService sets Slack service for a project
337//
338// GitLab API docs:
339// https://docs.gitlab.com/ce/api/services.html#edit-slack-service
340func (s *ServicesService) SetSlackService(pid interface{}, opt *SetSlackServiceOptions, options ...OptionFunc) (*Response, error) {
341	project, err := parseID(pid)
342	if err != nil {
343		return nil, err
344	}
345	u := fmt.Sprintf("projects/%s/services/slack", pathEscape(project))
346
347	req, err := s.client.NewRequest("PUT", u, opt, options)
348	if err != nil {
349		return nil, err
350	}
351
352	return s.client.Do(req, nil)
353}
354
355// DeleteSlackService deletes Slack service for project.
356//
357// GitLab API docs:
358// https://docs.gitlab.com/ce/api/services.html#delete-slack-service
359func (s *ServicesService) DeleteSlackService(pid interface{}, options ...OptionFunc) (*Response, error) {
360	project, err := parseID(pid)
361	if err != nil {
362		return nil, err
363	}
364	u := fmt.Sprintf("projects/%s/services/slack", pathEscape(project))
365
366	req, err := s.client.NewRequest("DELETE", u, nil, options)
367	if err != nil {
368		return nil, err
369	}
370
371	return s.client.Do(req, nil)
372}
373
374// JiraService represents Jira service settings.
375//
376// GitLab API docs:
377// https://docs.gitlab.com/ce/api/services.html#jira
378type JiraService struct {
379	Service
380	Properties *JiraServiceProperties `json:"properties"`
381}
382
383// JiraServiceProperties represents Jira specific properties.
384//
385// GitLab API docs:
386// https://docs.gitlab.com/ce/api/services.html#jira
387type JiraServiceProperties struct {
388	URL                   string `json:"url,omitempty"`
389	APIURL                string `json:"api_url,omitempty"`
390	ProjectKey            string `json:"project_key,omitempty" `
391	Username              string `json:"username,omitempty" `
392	Password              string `json:"password,omitempty" `
393	JiraIssueTransitionID string `json:"jira_issue_transition_id,omitempty"`
394}
395
396// UnmarshalJSON decodes the Jira Service Properties.
397//
398// This allows support of JiraIssueTransitionID for both type string (>11.9) and float64 (<11.9)
399func (p *JiraServiceProperties) UnmarshalJSON(b []byte) error {
400	type Alias JiraServiceProperties
401	raw := struct {
402		*Alias
403		JiraIssueTransitionID interface{} `json:"jira_issue_transition_id"`
404	}{
405		Alias: (*Alias)(p),
406	}
407
408	if err := json.Unmarshal(b, &raw); err != nil {
409		return err
410	}
411
412	switch id := raw.JiraIssueTransitionID.(type) {
413	case nil:
414		// No action needed.
415	case string:
416		p.JiraIssueTransitionID = id
417	case float64:
418		p.JiraIssueTransitionID = strconv.Itoa(int(id))
419	default:
420		return fmt.Errorf("failed to unmarshal JiraTransitionID of type: %T", id)
421	}
422
423	return nil
424}
425
426// GetJiraService gets Jira service settings for a project.
427//
428// GitLab API docs:
429// https://docs.gitlab.com/ce/api/services.html#get-jira-service-settings
430func (s *ServicesService) GetJiraService(pid interface{}, options ...OptionFunc) (*JiraService, *Response, error) {
431	project, err := parseID(pid)
432	if err != nil {
433		return nil, nil, err
434	}
435	u := fmt.Sprintf("projects/%s/services/jira", pathEscape(project))
436
437	req, err := s.client.NewRequest("GET", u, nil, options)
438	if err != nil {
439		return nil, nil, err
440	}
441
442	svc := new(JiraService)
443	resp, err := s.client.Do(req, svc)
444	if err != nil {
445		return nil, resp, err
446	}
447
448	return svc, resp, err
449}
450
451// SetJiraServiceOptions represents the available SetJiraService()
452// options.
453//
454// GitLab API docs:
455// https://docs.gitlab.com/ce/api/services.html#edit-jira-service
456type SetJiraServiceOptions struct {
457	URL                   *string `url:"url,omitempty" json:"url,omitempty"`
458	APIURL                *string `url:"api_url,omitempty" json:"api_url,omitempty"`
459	ProjectKey            *string `url:"project_key,omitempty" json:"project_key,omitempty" `
460	Username              *string `url:"username,omitempty" json:"username,omitempty" `
461	Password              *string `url:"password,omitempty" json:"password,omitempty" `
462	JiraIssueTransitionID *string `url:"jira_issue_transition_id,omitempty" json:"jira_issue_transition_id,omitempty"`
463}
464
465// SetJiraService sets Jira service for a project
466//
467// GitLab API docs:
468// https://docs.gitlab.com/ce/api/services.html#edit-jira-service
469func (s *ServicesService) SetJiraService(pid interface{}, opt *SetJiraServiceOptions, options ...OptionFunc) (*Response, error) {
470	project, err := parseID(pid)
471	if err != nil {
472		return nil, err
473	}
474	u := fmt.Sprintf("projects/%s/services/jira", pathEscape(project))
475
476	req, err := s.client.NewRequest("PUT", u, opt, options)
477	if err != nil {
478		return nil, err
479	}
480
481	return s.client.Do(req, nil)
482}
483
484// DeleteJiraService deletes Jira service for project.
485//
486// GitLab API docs:
487// https://docs.gitlab.com/ce/api/services.html#delete-jira-service
488func (s *ServicesService) DeleteJiraService(pid interface{}, options ...OptionFunc) (*Response, error) {
489	project, err := parseID(pid)
490	if err != nil {
491		return nil, err
492	}
493	u := fmt.Sprintf("projects/%s/services/jira", pathEscape(project))
494
495	req, err := s.client.NewRequest("DELETE", u, nil, options)
496	if err != nil {
497		return nil, err
498	}
499
500	return s.client.Do(req, nil)
501}
502
503// JenkinsCIService represents Jenkins CI service settings.
504//
505// GitLab API docs:
506// https://docs.gitlab.com/ee/api/services.html#jenkins-ci
507type JenkinsCIService struct {
508	Service
509	Properties *JenkinsCIServiceProperties `json:"properties"`
510}
511
512// JenkinsCIServiceProperties represents Jenkins CI specific properties.
513//
514// GitLab API docs:
515// https://docs.gitlab.com/ee/api/services.html#jenkins-ci
516type JenkinsCIServiceProperties struct {
517	URL         string `json:"jenkins_url,omitempty"`
518	ProjectName string `json:"project_name,omitempty"`
519	Username    string `json:"username,omitempty"`
520}
521
522// GetJenkinsCIService gets Jenkins CI service settings for a project.
523//
524// GitLab API docs:
525// https://docs.gitlab.com/ee/api/services.html#get-jenkins-ci-service-settings
526func (s *ServicesService) GetJenkinsCIService(pid interface{}, options ...OptionFunc) (*JenkinsCIService, *Response, error) {
527	project, err := parseID(pid)
528	if err != nil {
529		return nil, nil, err
530	}
531	u := fmt.Sprintf("projects/%s/services/jenkins", pathEscape(project))
532
533	req, err := s.client.NewRequest("GET", u, nil, options)
534	if err != nil {
535		return nil, nil, err
536	}
537
538	svc := new(JenkinsCIService)
539	resp, err := s.client.Do(req, svc)
540	if err != nil {
541		return nil, resp, err
542	}
543
544	return svc, resp, err
545}
546
547// SetJenkinsCIServiceOptions represents the available SetJenkinsCIService()
548// options.
549//
550// GitLab API docs:
551// https://docs.gitlab.com/ee/api/services.html#jenkins-ci
552type SetJenkinsCIServiceOptions struct {
553	URL         *string `url:"jenkins_url,omitempty" json:"jenkins_url,omitempty"`
554	ProjectName *string `url:"project_name,omitempty" json:"project_name,omitempty"`
555	Username    *string `url:"username,omitempty" json:"username,omitempty"`
556	Password    *string `url:"password,omitempty" json:"password,omitempty"`
557}
558
559// SetJenkinsCIService sets Jenkins service for a project
560//
561// GitLab API docs:
562// https://docs.gitlab.com/ee/api/services.html#create-edit-jenkins-ci-service
563func (s *ServicesService) SetJenkinsCIService(pid interface{}, opt *SetJenkinsCIServiceOptions, options ...OptionFunc) (*Response, error) {
564	project, err := parseID(pid)
565	if err != nil {
566		return nil, err
567	}
568	u := fmt.Sprintf("projects/%s/services/jenkins", pathEscape(project))
569
570	req, err := s.client.NewRequest("PUT", u, opt, options)
571	if err != nil {
572		return nil, err
573	}
574
575	return s.client.Do(req, nil)
576}
577
578// DeleteJenkinsCIService deletes Jenkins CI service for project.
579//
580// GitLab API docs:
581// https://docs.gitlab.com/ce/api/services.html#delete-jira-service
582func (s *ServicesService) DeleteJenkinsCIService(pid interface{}, options ...OptionFunc) (*Response, error) {
583	project, err := parseID(pid)
584	if err != nil {
585		return nil, err
586	}
587	u := fmt.Sprintf("projects/%s/services/jenkins", pathEscape(project))
588
589	req, err := s.client.NewRequest("DELETE", u, nil, options)
590	if err != nil {
591		return nil, err
592	}
593
594	return s.client.Do(req, nil)
595}
596
597// MicrosoftTeamsService represents Microsoft Teams service settings.
598//
599// GitLab API docs:
600// https://docs.gitlab.com/ce/api/services.html#microsoft-teams
601type MicrosoftTeamsService struct {
602	Service
603	Properties *MicrosoftTeamsServiceProperties `json:"properties"`
604}
605
606// MicrosoftTeamsServiceProperties represents Microsoft Teams specific properties.
607//
608// GitLab API docs:
609// https://docs.gitlab.com/ce/api/services.html#microsoft-teams
610type MicrosoftTeamsServiceProperties struct {
611	WebHook string `json:"webhook"`
612}
613
614// GetMicrosoftTeamsService gets MicrosoftTeams service settings for a project.
615//
616// GitLab API docs:
617// https://docs.gitlab.com/ce/api/services.html#get-microsoft-teams-service-settings
618func (s *ServicesService) GetMicrosoftTeamsService(pid interface{}, options ...OptionFunc) (*MicrosoftTeamsService, *Response, error) {
619	project, err := parseID(pid)
620	if err != nil {
621		return nil, nil, err
622	}
623	u := fmt.Sprintf("projects/%s/services/microsoft-teams", pathEscape(project))
624
625	req, err := s.client.NewRequest("GET", u, nil, options)
626	if err != nil {
627		return nil, nil, err
628	}
629
630	svc := new(MicrosoftTeamsService)
631	resp, err := s.client.Do(req, svc)
632	if err != nil {
633		return nil, resp, err
634	}
635
636	return svc, resp, err
637}
638
639// SetMicrosoftTeamsServiceOptions represents the available SetMicrosoftTeamsService()
640// options.
641//
642// GitLab API docs:
643// https://docs.gitlab.com/ce/api/services.html#create-edit-microsoft-teams-service
644type SetMicrosoftTeamsServiceOptions struct {
645	WebHook *string `url:"webhook,omitempty" json:"webhook,omitempty"`
646}
647
648// SetMicrosoftTeamsService sets Microsoft Teams service for a project
649//
650// GitLab API docs:
651// https://docs.gitlab.com/ce/api/services.html#create-edit-microsoft-teams-service
652func (s *ServicesService) SetMicrosoftTeamsService(pid interface{}, opt *SetMicrosoftTeamsServiceOptions, options ...OptionFunc) (*Response, error) {
653	project, err := parseID(pid)
654	if err != nil {
655		return nil, err
656	}
657	u := fmt.Sprintf("projects/%s/services/microsoft-teams", pathEscape(project))
658
659	req, err := s.client.NewRequest("PUT", u, opt, options)
660	if err != nil {
661		return nil, err
662	}
663	return s.client.Do(req, nil)
664}
665
666// DeleteMicrosoftTeamsService deletes Microsoft Teams service for project.
667//
668// GitLab API docs:
669// https://docs.gitlab.com/ce/api/services.html#delete-microsoft-teams-service
670func (s *ServicesService) DeleteMicrosoftTeamsService(pid interface{}, options ...OptionFunc) (*Response, error) {
671	project, err := parseID(pid)
672	if err != nil {
673		return nil, err
674	}
675	u := fmt.Sprintf("projects/%s/services/microsoft-teams", pathEscape(project))
676
677	req, err := s.client.NewRequest("DELETE", u, nil, options)
678	if err != nil {
679		return nil, err
680	}
681
682	return s.client.Do(req, nil)
683}
684
685// ExternalWikiService represents External Wiki service settings.
686//
687// GitLab API docs:
688// https://docs.gitlab.com/ce/api/services.html#external-wiki
689type ExternalWikiService struct {
690	Service
691	Properties *ExternalWikiServiceProperties `json:"properties"`
692}
693
694// ExternalWikiServiceProperties represents External Wiki specific properties.
695//
696// GitLab API docs:
697// https://docs.gitlab.com/ce/api/services.html#external-wiki
698type ExternalWikiServiceProperties struct {
699	ExternalWikiURL string `json:"external_wiki_url"`
700}
701
702// GetExternalWikiService gets External Wiki service settings for a project.
703//
704// GitLab API docs:
705// https://docs.gitlab.com/ce/api/services.html#get-external-wiki-service-settings
706func (s *ServicesService) GetExternalWikiService(pid interface{}, options ...OptionFunc) (*ExternalWikiService, *Response, error) {
707	project, err := parseID(pid)
708	if err != nil {
709		return nil, nil, err
710	}
711	u := fmt.Sprintf("projects/%s/services/external-wiki", pathEscape(project))
712
713	req, err := s.client.NewRequest("GET", u, nil, options)
714	if err != nil {
715		return nil, nil, err
716	}
717
718	svc := new(ExternalWikiService)
719	resp, err := s.client.Do(req, svc)
720	if err != nil {
721		return nil, resp, err
722	}
723
724	return svc, resp, err
725}
726
727// SetExternalWikiServiceOptions represents the available SetExternalWikiService()
728// options.
729//
730// GitLab API docs:
731// https://docs.gitlab.com/ce/api/services.html#createedit-external-wiki-service
732type SetExternalWikiServiceOptions struct {
733	ExternalWikiURL *string `url:"external_wiki_url,omitempty" json:"external_wiki_url,omitempty"`
734}
735
736// SetExternalWikiService sets External Wiki service for a project.
737//
738// GitLab API docs:
739// https://docs.gitlab.com/ce/api/services.html#createedit-external-wiki-service
740func (s *ServicesService) SetExternalWikiService(pid interface{}, opt *SetExternalWikiServiceOptions, options ...OptionFunc) (*Response, error) {
741	project, err := parseID(pid)
742	if err != nil {
743		return nil, err
744	}
745	u := fmt.Sprintf("projects/%s/services/external-wiki", pathEscape(project))
746
747	req, err := s.client.NewRequest("PUT", u, opt, options)
748	if err != nil {
749		return nil, err
750	}
751
752	return s.client.Do(req, nil)
753}
754
755// DeleteExternalWikiService deletes External Wiki service for project.
756//
757// GitLab API docs:
758// https://docs.gitlab.com/ce/api/services.html#delete-external-wiki-service
759func (s *ServicesService) DeleteExternalWikiService(pid interface{}, options ...OptionFunc) (*Response, error) {
760	project, err := parseID(pid)
761	if err != nil {
762		return nil, err
763	}
764	u := fmt.Sprintf("projects/%s/services/external-wiki", pathEscape(project))
765
766	req, err := s.client.NewRequest("DELETE", u, nil, options)
767	if err != nil {
768		return nil, err
769	}
770
771	return s.client.Do(req, nil)
772}