func (s *ServicesService) SetExternalWikiService(pid interface{}, opt *SetExternalWikiServiceOptions, options ...OptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/services/external-wiki", pathEscape(project))
	req, err := s.client.NewRequest("PUT", u, opt, options)
	if err != nil {
		return nil, err
	}
	return s.client.Do(req, nil)
}
SetExternalWikiService sets External Wiki service for a project.

GitLab API docs:
https://docs.gitlab.com/ce/api/services.html#createedit-external-wiki-service
package gitlab
import (
	"encoding/json"
	"fmt"
	"strconv"
	"time"
)
type ServicesService struct {
	client *Client
}
type Service struct {
	ID                       int        `json:"id"`
	Title                    string     `json:"title"`
	CreatedAt                *time.Time `json:"created_at"`
	UpdatedAt                *time.Time `json:"updated_at"`
	Active                   bool       `json:"active"`
	PushEvents               bool       `json:"push_events"`
	IssuesEvents             bool       `json:"issues_events"`
	ConfidentialIssuesEvents bool       `json:"confidential_issues_events"`
	MergeRequestsEvents      bool       `json:"merge_requests_events"`
	TagPushEvents            bool       `json:"tag_push_events"`
	NoteEvents               bool       `json:"note_events"`
	ConfidentialNoteEvents   bool       `json:"confidential_note_events"`
	PipelineEvents           bool       `json:"pipeline_events"`
	JobEvents                bool       `json:"job_events"`
	WikiPageEvents           bool       `json:"wiki_page_events"`
}
type SetGitLabCIServiceOptions struct {
	Token      *string `url:"token,omitempty" json:"token,omitempty"`
	ProjectURL *string `url:"project_url,omitempty" json:"project_url,omitempty"`
}
func (s *ServicesService) SetGitLabCIService(pid interface{}, opt *SetGitLabCIServiceOptions, options ...OptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/services/gitlab-ci", pathEscape(project))
	req, err := s.client.NewRequest("PUT", u, opt, options)
	if err != nil {
		return nil, err
	}
	return s.client.Do(req, nil)
}
func (s *ServicesService) DeleteGitLabCIService(pid interface{}, options ...OptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/services/gitlab-ci", pathEscape(project))
	req, err := s.client.NewRequest("DELETE", u, nil, options)
	if err != nil {
		return nil, err
	}
	return s.client.Do(req, nil)
}
type SetHipChatServiceOptions struct {
	Token *string `url:"token,omitempty" json:"token,omitempty" `
	Room  *string `url:"room,omitempty" json:"room,omitempty"`
}
func (s *ServicesService) SetHipChatService(pid interface{}, opt *SetHipChatServiceOptions, options ...OptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/services/hipchat", pathEscape(project))
	req, err := s.client.NewRequest("PUT", u, opt, options)
	if err != nil {
		return nil, err
	}
	return s.client.Do(req, nil)
}
func (s *ServicesService) DeleteHipChatService(pid interface{}, options ...OptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/services/hipchat", pathEscape(project))
	req, err := s.client.NewRequest("DELETE", u, nil, options)
	if err != nil {
		return nil, err
	}
	return s.client.Do(req, nil)
}
type DroneCIService struct {
	Service
	Properties *DroneCIServiceProperties `json:"properties"`
}
type DroneCIServiceProperties struct {
	Token                 string `json:"token"`
	DroneURL              string `json:"drone_url"`
	EnableSSLVerification bool   `json:"enable_ssl_verification"`
}
func (s *ServicesService) GetDroneCIService(pid interface{}, options ...OptionFunc) (*DroneCIService, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/services/drone-ci", pathEscape(project))
	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}
	svc := new(DroneCIService)
	resp, err := s.client.Do(req, svc)
	if err != nil {
		return nil, resp, err
	}
	return svc, resp, err
}
type SetDroneCIServiceOptions struct {
	Token                 *string `url:"token" json:"token" `
	DroneURL              *string `url:"drone_url" json:"drone_url"`
	EnableSSLVerification *bool   `url:"enable_ssl_verification,omitempty" json:"enable_ssl_verification,omitempty"`
}
func (s *ServicesService) SetDroneCIService(pid interface{}, opt *SetDroneCIServiceOptions, options ...OptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/services/drone-ci", pathEscape(project))
	req, err := s.client.NewRequest("PUT", u, opt, options)
	if err != nil {
		return nil, err
	}
	return s.client.Do(req, nil)
}
func (s *ServicesService) DeleteDroneCIService(pid interface{}, options ...OptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/services/drone-ci", pathEscape(project))
	req, err := s.client.NewRequest("DELETE", u, nil, options)
	if err != nil {
		return nil, err
	}
	return s.client.Do(req, nil)
}
type SlackService struct {
	Service
	Properties *SlackServiceProperties `json:"properties"`
}
type SlackServiceProperties struct {
	NotifyOnlyBrokenPipelines BoolValue `json:"notify_only_broken_pipelines,omitempty"`
	NotifyOnlyDefaultBranch   BoolValue `json:"notify_only_default_branch,omitempty"`
	WebHook                   string    `json:"webhook,omitempty"`
	Username                  string    `json:"username,omitempty"`
	Channel                   string    `json:"channel,omitempty"`
	PushChannel               string    `json:"push_channel,omitempty"`
	IssueChannel              string    `json:"issue_channel,omitempty"`
	ConfidentialIssueChannel  string    `json:"confidential_issue_channel,omitempty"`
	MergeRequestChannel       string    `json:"merge_request_channel,omitempty"`
	NoteChannel               string    `json:"note_channel,omitempty"`
	ConfidentialNoteChannel   string    `json:"confidential_note_channel,omitempty"`
	TagPushChannel            string    `json:"tag_push_channel,omitempty"`
	PipelineChannel           string    `json:"pipeline_channel,omitempty"`
	WikiPageChannel           string    `json:"wiki_page_channel,omitempty"`
}
func (s *ServicesService) GetSlackService(pid interface{}, options ...OptionFunc) (*SlackService, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/services/slack", pathEscape(project))
	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}
	svc := new(SlackService)
	resp, err := s.client.Do(req, svc)
	if err != nil {
		return nil, resp, err
	}
	return svc, resp, err
}
type SetSlackServiceOptions struct {
	WebHook                   *string `url:"webhook,omitempty" json:"webhook,omitempty"`
	Username                  *string `url:"username,omitempty" json:"username,omitempty"`
	Channel                   *string `url:"channel,omitempty" json:"channel,omitempty"`
	NotifyOnlyBrokenPipelines *bool   `url:"notify_only_broken_pipelines,omitempty" json:"notify_only_broken_pipelines,omitempty"`
	NotifyOnlyDefaultBranch   *bool   `url:"notify_only_default_branch,omitempty" json:"notify_only_default_branch,omitempty"`
	PushEvents                *bool   `url:"push_events,omitempty" json:"push_events,omitempty"`
	PushChannel               *string `url:"push_channel,omitempty" json:"push_channel,omitempty"`
	IssuesEvents              *bool   `url:"issues_events,omitempty" json:"issues_events,omitempty"`
	IssueChannel              *string `url:"issue_channel,omitempty" json:"issue_channel,omitempty"`
	ConfidentialIssuesEvents  *bool   `url:"confidential_issues_events,omitempty" json:"confidential_issues_events,omitempty"`
	ConfidentialIssueChannel  *string `url:"confidential_issue_channel,omitempty" json:"confidential_issue_channel,omitempty"`
	MergeRequestsEvents       *bool   `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"`
	MergeRequestChannel       *string `url:"merge_request_channel,omitempty" json:"merge_request_channel,omitempty"`
	TagPushEvents             *bool   `url:"tag_push_events,omitempty" json:"tag_push_events,omitempty"`
	TagPushChannel            *string `url:"tag_push_channel,omitempty" json:"tag_push_channel,omitempty"`
	NoteEvents                *bool   `url:"note_events,omitempty" json:"note_events,omitempty"`
	NoteChannel               *string `url:"note_channel,omitempty" json:"note_channel,omitempty"`
	ConfidentialNoteEvents    *bool   `url:"confidential_note_events" json:"confidential_note_events"`
	PipelineEvents  *bool   `url:"pipeline_events,omitempty" json:"pipeline_events,omitempty"`
	PipelineChannel *string `url:"pipeline_channel,omitempty" json:"pipeline_channel,omitempty"`
	WikiPageChannel *string `url:"wiki_page_channel,omitempty" json:"wiki_page_channel,omitempty"`
	WikiPageEvents  *bool   `url:"wiki_page_events" json:"wiki_page_events"`
}
func (s *ServicesService) SetSlackService(pid interface{}, opt *SetSlackServiceOptions, options ...OptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/services/slack", pathEscape(project))
	req, err := s.client.NewRequest("PUT", u, opt, options)
	if err != nil {
		return nil, err
	}
	return s.client.Do(req, nil)
}
func (s *ServicesService) DeleteSlackService(pid interface{}, options ...OptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/services/slack", pathEscape(project))
	req, err := s.client.NewRequest("DELETE", u, nil, options)
	if err != nil {
		return nil, err
	}
	return s.client.Do(req, nil)
}
type JiraService struct {
	Service
	Properties *JiraServiceProperties `json:"properties"`
}
type JiraServiceProperties struct {
	URL                   string `json:"url,omitempty"`
	APIURL                string `json:"api_url,omitempty"`
	ProjectKey            string `json:"project_key,omitempty" `
	Username              string `json:"username,omitempty" `
	Password              string `json:"password,omitempty" `
	JiraIssueTransitionID string `json:"jira_issue_transition_id,omitempty"`
}
func (p *JiraServiceProperties) UnmarshalJSON(b []byte) error {
	type Alias JiraServiceProperties
	raw := struct {
		*Alias
		JiraIssueTransitionID interface{} `json:"jira_issue_transition_id"`
	}{
		Alias: (*Alias)(p),
	}
	if err := json.Unmarshal(b, &raw); err != nil {
		return err
	}
	switch id := raw.JiraIssueTransitionID.(type) {
	case nil:
	case string:
		p.JiraIssueTransitionID = id
	case float64:
		p.JiraIssueTransitionID = strconv.Itoa(int(id))
	default:
		return fmt.Errorf("failed to unmarshal JiraTransitionID of type: %T", id)
	}
	return nil
}
func (s *ServicesService) GetJiraService(pid interface{}, options ...OptionFunc) (*JiraService, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/services/jira", pathEscape(project))
	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}
	svc := new(JiraService)
	resp, err := s.client.Do(req, svc)
	if err != nil {
		return nil, resp, err
	}
	return svc, resp, err
}
type SetJiraServiceOptions struct {
	URL                   *string `url:"url,omitempty" json:"url,omitempty"`
	APIURL                *string `url:"api_url,omitempty" json:"api_url,omitempty"`
	ProjectKey            *string `url:"project_key,omitempty" json:"project_key,omitempty" `
	Username              *string `url:"username,omitempty" json:"username,omitempty" `
	Password              *string `url:"password,omitempty" json:"password,omitempty" `
	JiraIssueTransitionID *string `url:"jira_issue_transition_id,omitempty" json:"jira_issue_transition_id,omitempty"`
}
func (s *ServicesService) SetJiraService(pid interface{}, opt *SetJiraServiceOptions, options ...OptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/services/jira", pathEscape(project))
	req, err := s.client.NewRequest("PUT", u, opt, options)
	if err != nil {
		return nil, err
	}
	return s.client.Do(req, nil)
}
func (s *ServicesService) DeleteJiraService(pid interface{}, options ...OptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/services/jira", pathEscape(project))
	req, err := s.client.NewRequest("DELETE", u, nil, options)
	if err != nil {
		return nil, err
	}
	return s.client.Do(req, nil)
}
type JenkinsCIService struct {
	Service
	Properties *JenkinsCIServiceProperties `json:"properties"`
}
type JenkinsCIServiceProperties struct {
	URL         string `json:"jenkins_url,omitempty"`
	ProjectName string `json:"project_name,omitempty"`
	Username    string `json:"username,omitempty"`
}
func (s *ServicesService) GetJenkinsCIService(pid interface{}, options ...OptionFunc) (*JenkinsCIService, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/services/jenkins", pathEscape(project))
	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}
	svc := new(JenkinsCIService)
	resp, err := s.client.Do(req, svc)
	if err != nil {
		return nil, resp, err
	}
	return svc, resp, err
}
type SetJenkinsCIServiceOptions struct {
	URL         *string `url:"jenkins_url,omitempty" json:"jenkins_url,omitempty"`
	ProjectName *string `url:"project_name,omitempty" json:"project_name,omitempty"`
	Username    *string `url:"username,omitempty" json:"username,omitempty"`
	Password    *string `url:"password,omitempty" json:"password,omitempty"`
}
func (s *ServicesService) SetJenkinsCIService(pid interface{}, opt *SetJenkinsCIServiceOptions, options ...OptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/services/jenkins", pathEscape(project))
	req, err := s.client.NewRequest("PUT", u, opt, options)
	if err != nil {
		return nil, err
	}
	return s.client.Do(req, nil)
}
func (s *ServicesService) DeleteJenkinsCIService(pid interface{}, options ...OptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/services/jenkins", pathEscape(project))
	req, err := s.client.NewRequest("DELETE", u, nil, options)
	if err != nil {
		return nil, err
	}
	return s.client.Do(req, nil)
}
type MicrosoftTeamsService struct {
	Service
	Properties *MicrosoftTeamsServiceProperties `json:"properties"`
}
type MicrosoftTeamsServiceProperties struct {
	WebHook string `json:"webhook"`
}
func (s *ServicesService) GetMicrosoftTeamsService(pid interface{}, options ...OptionFunc) (*MicrosoftTeamsService, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/services/microsoft-teams", pathEscape(project))
	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}
	svc := new(MicrosoftTeamsService)
	resp, err := s.client.Do(req, svc)
	if err != nil {
		return nil, resp, err
	}
	return svc, resp, err
}
type SetMicrosoftTeamsServiceOptions struct {
	WebHook *string `url:"webhook,omitempty" json:"webhook,omitempty"`
}
func (s *ServicesService) SetMicrosoftTeamsService(pid interface{}, opt *SetMicrosoftTeamsServiceOptions, options ...OptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/services/microsoft-teams", pathEscape(project))
	req, err := s.client.NewRequest("PUT", u, opt, options)
	if err != nil {
		return nil, err
	}
	return s.client.Do(req, nil)
}
func (s *ServicesService) DeleteMicrosoftTeamsService(pid interface{}, options ...OptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/services/microsoft-teams", pathEscape(project))
	req, err := s.client.NewRequest("DELETE", u, nil, options)
	if err != nil {
		return nil, err
	}
	return s.client.Do(req, nil)
}
type ExternalWikiService struct {
	Service
	Properties *ExternalWikiServiceProperties `json:"properties"`
}
type ExternalWikiServiceProperties struct {
	ExternalWikiURL string `json:"external_wiki_url"`
}
func (s *ServicesService) GetExternalWikiService(pid interface{}, options ...OptionFunc) (*ExternalWikiService, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/services/external-wiki", pathEscape(project))
	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}
	svc := new(ExternalWikiService)
	resp, err := s.client.Do(req, svc)
	if err != nil {
		return nil, resp, err
	}
	return svc, resp, err
}
type SetExternalWikiServiceOptions struct {
	ExternalWikiURL *string `url:"external_wiki_url,omitempty" json:"external_wiki_url,omitempty"`
}