diff --git a/vendor/github.com/xanzy/go-gitlab/CHANGELOG.md b/vendor/github.com/xanzy/go-gitlab/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..89580627be641c06875306f185d7020a53f09fc4
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/CHANGELOG.md
@@ -0,0 +1,14 @@
+go-github CHANGELOG
+===================
+
+0.3.0
+-----
+- Moved the tags related API calls to their own service, following the Gitlab API structure.
+
+0.2.0
+-----
+- Convert all Option structs to use pointers for their fields.
+
+0.1.0
+-----
+- Initial release.
diff --git a/vendor/github.com/xanzy/go-gitlab/LICENSE b/vendor/github.com/xanzy/go-gitlab/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..e06d2081865a766a8668acc12878f98b27fc9ea0
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/LICENSE
@@ -0,0 +1,202 @@
+Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
diff --git a/vendor/github.com/xanzy/go-gitlab/README.md b/vendor/github.com/xanzy/go-gitlab/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..a56b0d1162be9d3270530aa6bd594eea3f9ff872
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/README.md
@@ -0,0 +1,127 @@
+# go-gitlab
+
+A GitLab API client enabling Go programs to interact with GitLab in a simple and uniform way
+
+**Documentation:** [![GoDoc](https://godoc.org/github.com/xanzy/go-gitlab?status.svg)](https://godoc.org/github.com/xanzy/go-gitlab)
+**Build Status:** [![Build Status](https://travis-ci.org/xanzy/go-gitlab.svg?branch=master)](https://travis-ci.org/xanzy/go-gitlab)
+
+## NOTE
+
+Release v0.2.0 (released on 26-07-2016), is unfortunately backwards incompatible. We 
+understand very well that this will cause some additional work in order to get your
+code working again, but we believe this is a necessary eval to improve functionality
+and fix some use cases (see [GH-29](https://github.com/xanzy/go-gitlab/issues/29) and
+[GH-53](https://github.com/xanzy/go-gitlab/issues/53)).
+
+## Coverage
+
+This API client package covers **100%** of the existing GitLab API calls! So this
+includes all calls to the following services:
+
+- [x] Users
+- [x] Session
+- [x] Projects (including setting Webhooks)
+- [x] Project Snippets
+- [x] Services
+- [x] Repositories
+- [x] Repository Files
+- [x] Commits
+- [x] Branches
+- [x] Merge Requests
+- [x] Issues
+- [x] Labels
+- [x] Milestones
+- [x] Notes (comments)
+- [x] Deploy Keys
+- [x] System Hooks
+- [x] Groups
+- [x] Namespaces
+- [x] Settings
+
+## Usage
+
+```go
+import "github.com/xanzy/go-gitlab"
+```
+
+Construct a new GitLab client, then use the various services on the client to
+access different parts of the GitLab API. For example, to list all
+users:
+
+```go
+git := gitlab.NewClient(nil, "yourtokengoeshere")
+//git.SetBaseURL("https://git.mydomain.com/api/v3")
+users, _, err := git.Users.ListUsers()
+```
+
+Some API methods have optional parameters that can be passed. For example,
+to list all projects for user "svanharmelen":
+
+```go
+git := gitlab.NewClient(nil)
+opt := &ListProjectsOptions{Search: gitlab.String("svanharmelen")})
+projects, _, err := git.Projects.ListProjects(opt)
+```
+
+### Examples
+
+The [examples](https://github.com/xanzy/go-gitlab/tree/master/examples) directory
+contains a couple for clear examples, of which one is partially listed here as well:
+
+```go
+package main
+
+import (
+	"log"
+
+	"github.com/xanzy/go-gitlab"
+)
+
+func main() {
+	git := gitlab.NewClient(nil, "yourtokengoeshere")
+
+	// Create new project
+	p := &gitlab.CreateProjectOptions{
+		Name:                 gitlab.String("My Project"),
+		Description:          gitlab.String("Just a test project to play with"),
+		MergeRequestsEnabled: gitlab.Bool(true),
+		SnippetsEnabled:      gitlab.Bool(true),
+		VisibilityLevel:      gitlab.VisibilityLevel(gitlab.PublicVisibility),
+	}
+	project, _, err := git.Projects.CreateProject(p)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	// Add a new snippet
+	s := &gitlab.CreateSnippetOptions{
+		Title:           gitlab.String("Dummy Snippet"),
+		FileName:        gitlab.String("snippet.go"),
+		Code:            gitlab.String("package main...."),
+		VisibilityLevel: gitlab.VisibilityLevel(gitlab.PublicVisibility),
+	}
+	_, _, err = git.ProjectSnippets.CreateSnippet(project.ID, s)
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+
+```
+
+For complete usage of go-gitlab, see the full [package docs](https://godoc.org/github.com/xanzy/go-gitlab).
+
+## ToDo
+
+- The biggest thing this package still needs is tests :disappointed:
+
+## Issues
+
+- If you have an issue: report it on the [issue tracker](https://github.com/xanzy/go-gitlab/issues)
+
+## Author
+
+Sander van Harmelen (<sander@xanzy.io>)
+
+## License
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>
diff --git a/vendor/github.com/xanzy/go-gitlab/branches.go b/vendor/github.com/xanzy/go-gitlab/branches.go
new file mode 100644
index 0000000000000000000000000000000000000000..b8fa45d1212f1bf0d5816607f6467c73752e4736
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/branches.go
@@ -0,0 +1,205 @@
+//
+// Copyright 2015, Sander van Harmelen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package gitlab
+
+import (
+	"fmt"
+	"net/url"
+)
+
+// BranchesService handles communication with the branch related methods
+// of the GitLab API.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/branches.html
+type BranchesService struct {
+	client *Client
+}
+
+// Branch represents a GitLab branch.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/branches.html
+type Branch struct {
+	Commit    *Commit `json:"commit"`
+	Name      string  `json:"name"`
+	Protected bool    `json:"protected"`
+}
+
+func (b Branch) String() string {
+	return Stringify(b)
+}
+
+// ListBranches gets a list of repository branches from a project, sorted by
+// name alphabetically.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/branches.html#list-repository-branches
+func (s *BranchesService) ListBranches(pid interface{}) ([]*Branch, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/branches", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var b []*Branch
+	resp, err := s.client.Do(req, &b)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return b, resp, err
+}
+
+// GetBranch gets a single project repository branch.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/branches.html#get-single-repository-branch
+func (s *BranchesService) GetBranch(pid interface{}, branch string) (*Branch, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/branches/%s", url.QueryEscape(project), branch)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	b := new(Branch)
+	resp, err := s.client.Do(req, b)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return b, resp, err
+}
+
+// ProtectBranch protects a single project repository branch. This is an
+// idempotent function, protecting an already protected repository branch
+// still returns a 200 OK status code.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/branches.html#protect-repository-branch
+func (s *BranchesService) ProtectBranch(pid interface{}, branch string) (*Branch, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/branches/%s/protect", url.QueryEscape(project), branch)
+
+	req, err := s.client.NewRequest("PUT", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	b := new(Branch)
+	resp, err := s.client.Do(req, b)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return b, resp, err
+}
+
+// UnprotectBranch unprotects a single project repository branch. This is an
+// idempotent function, unprotecting an already unprotected repository branch
+// still returns a 200 OK status code.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/branches.html#unprotect-repository-branch
+func (s *BranchesService) UnprotectBranch(
+	pid interface{},
+	branch string) (*Branch, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/branches/%s/unprotect", url.QueryEscape(project), branch)
+
+	req, err := s.client.NewRequest("PUT", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	b := new(Branch)
+	resp, err := s.client.Do(req, b)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return b, resp, err
+}
+
+// CreateBranchOptions represents the available CreateBranch() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/branches.html#create-repository-branch
+type CreateBranchOptions struct {
+	BranchName *string `url:"branch_name,omitempty" json:"branch_name,omitempty"`
+	Ref        *string `url:"ref,omitempty" json:"ref,omitempty"`
+}
+
+// CreateBranch creates branch from commit SHA or existing branch.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/branches.html#create-repository-branch
+func (s *BranchesService) CreateBranch(
+	pid interface{},
+	opt *CreateBranchOptions) (*Branch, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/branches", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("POST", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	b := new(Branch)
+	resp, err := s.client.Do(req, b)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return b, resp, err
+}
+
+// DeleteBranch deletes an existing branch.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/branches.html#delete-repository-branch
+func (s *BranchesService) DeleteBranch(pid interface{}, branch string) (*Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/branches/%s", url.QueryEscape(project), branch)
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
diff --git a/vendor/github.com/xanzy/go-gitlab/build_variables.go b/vendor/github.com/xanzy/go-gitlab/build_variables.go
new file mode 100644
index 0000000000000000000000000000000000000000..5234a01d52c34e4c6b1be184e4c4aebf908d829b
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/build_variables.go
@@ -0,0 +1,146 @@
+package gitlab
+
+import (
+	"fmt"
+	"net/url"
+)
+
+// BuildVariablesService handles communication with the project variables related methods
+// of the Gitlab API
+//
+// Gitlab API Docs : https://docs.gitlab.com/ce/api/build_variables.html
+type BuildVariablesService struct {
+	client *Client
+}
+
+// BuildVariable represents a variable available for each build of the given project
+//
+// Gitlab API Docs : https://docs.gitlab.com/ce/api/build_variables.html
+type BuildVariable struct {
+	Key   string `json:"key"`
+	Value string `json:"value"`
+}
+
+func (v BuildVariable) String() string {
+	return Stringify(v)
+}
+
+// ListBuildVariables gets the a list of project variables in a project
+//
+// Gitlab API Docs:
+// https://docs.gitlab.com/ce/api/build_variables.html#list-project-variables
+func (s *BuildVariablesService) ListBuildVariables(pid interface{}) ([]*BuildVariable, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/variables", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var v []*BuildVariable
+	resp, err := s.client.Do(req, &v)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return v, resp, err
+}
+
+// GetBuildVariable gets a single project variable of a project
+//
+// Gitlab API Docs:
+// https://docs.gitlab.com/ce/api/build_variables.html#show-variable-details
+func (s *BuildVariablesService) GetBuildVariable(pid interface{}, key string) (*BuildVariable, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/variables/%s", url.QueryEscape(project), key)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	v := new(BuildVariable)
+	resp, err := s.client.Do(req, v)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return v, resp, err
+}
+
+// CreateBuildVariable creates a variable for a given project
+//
+// Gitlab API Docs:
+// https://docs.gitlab.com/ce/api/build_variables.html#create-variable
+func (s *BuildVariablesService) CreateBuildVariable(pid interface{}, key, value string) (*BuildVariable, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/variables", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("POST", u, BuildVariable{key, value})
+	if err != nil {
+		return nil, nil, err
+	}
+
+	v := new(BuildVariable)
+	resp, err := s.client.Do(req, v)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return v, resp, err
+}
+
+// UpdateBuildVariable updates an existing project variable
+// The variable key must exist
+//
+// Gitlab API Docs:
+// https://docs.gitlab.com/ce/api/build_variables.html#update-variable
+func (s *BuildVariablesService) UpdateBuildVariable(pid interface{}, key, value string) (*BuildVariable, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/variables/%s", url.QueryEscape(project), key)
+
+	req, err := s.client.NewRequest("PUT", u, BuildVariable{key, value})
+	if err != nil {
+		return nil, nil, err
+	}
+
+	v := new(BuildVariable)
+	resp, err := s.client.Do(req, v)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return v, resp, err
+}
+
+// RemoveBuildVariable removes a project variable of a given project identified by its key
+//
+// Gitlab API Docs:
+// https://docs.gitlab.com/ce/api/build_variables.html#remove-variable
+func (s *BuildVariablesService) RemoveBuildVariable(pid interface{}, key string) (*Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, err
+	}
+	u := fmt.Sprintf("projects/%s/variables/%s", url.QueryEscape(project), key)
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
diff --git a/vendor/github.com/xanzy/go-gitlab/builds.go b/vendor/github.com/xanzy/go-gitlab/builds.go
new file mode 100644
index 0000000000000000000000000000000000000000..a26ead508a53762f2f5cda52ea41ef8b7a3ab89c
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/builds.go
@@ -0,0 +1,349 @@
+//
+// Copyright 2016, Arkbriar
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package gitlab
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"net/url"
+	"time"
+)
+
+// ListBuildsOptions are options for two list apis
+type ListBuildsOptions struct {
+	ListOptions
+	Scope []BuildState `url:"scope,omitempty" json:"scope,omitempty"`
+}
+
+// BuildsService handles communication with the ci builds related methods
+// of the GitLab API.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/builds.html
+type BuildsService struct {
+	client *Client
+}
+
+// Build represents a ci build.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/builds.html
+type Build struct {
+	Commit        *Commit    `json:"commit"`
+	CreatedAt     *time.Time `json:"created_at"`
+	ArtifactsFile struct {
+		Filename string `json:"filename"`
+		Size     int    `json:"size"`
+	} `json:"artifacts_file"`
+	FinishedAt *time.Time `json:"finished_at"`
+	ID         int        `json:"id"`
+	Name       string     `json:"name"`
+	Ref        string     `json:"ref"`
+	Runner     struct {
+		ID          int    `json:"id"`
+		Description string `json:"description"`
+		Active      bool   `json:"active"`
+		IsShared    bool   `json:"is_shared"`
+		Name        string `json:"name"`
+	} `json:"runner"`
+	Stage     string     `json:"stage"`
+	StartedAt *time.Time `json:"started_at"`
+	Status    string     `json:"status"`
+	Tag       bool       `json:"tag"`
+	User      *User      `json:"user"`
+}
+
+// ListProjectBuilds gets a list of builds in a project.
+//
+// The scope of builds to show, one or array of: pending, running,
+// failed, success, canceled; showing all builds if none provided.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/builds.html#list-project-builds
+func (s *BuildsService) ListProjectBuilds(pid interface{}, opts *ListBuildsOptions) ([]Build, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/builds", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("GET", u, opts)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var builds []Build
+	resp, err := s.client.Do(req, &builds)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return builds, resp, err
+}
+
+// ListCommitBuilds gets a list of builds for specific commit in a
+// project. If the commit SHA is not found, it will respond with 404.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/builds.html#list-commit-builds
+func (s *BuildsService) ListCommitBuilds(pid interface{}, sha string, opts *ListBuildsOptions) ([]Build, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/commits/%s/builds", project, sha)
+
+	req, err := s.client.NewRequest("GET", u, opts)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var builds []Build
+	resp, err := s.client.Do(req, &builds)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return builds, resp, err
+}
+
+// GetBuild gets a single build of a project.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/builds.html#get-a-single-build
+func (s *BuildsService) GetBuild(pid interface{}, buildID int) (*Build, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/builds/%d", project, buildID)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	build := new(Build)
+	resp, err := s.client.Do(req, build)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return build, resp, err
+}
+
+// GetBuildArtifacts get builds artifacts of a project
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/builds.html#get-build-artifacts
+func (s *BuildsService) GetBuildArtifacts(pid interface{}, buildID int) (io.Reader, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/builds/%d/artifacts", project, buildID)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	artifactsBuf := new(bytes.Buffer)
+	resp, err := s.client.Do(req, artifactsBuf)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return artifactsBuf, resp, err
+}
+
+// DownloadArtifactsFile download the artifacts file from the given
+// reference name and job provided the build finished successfully.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/builds.html#download-the-artifacts-file
+func (s *BuildsService) DownloadArtifactsFile(pid interface{}, refName string, job string) (io.Reader, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/builds/artifacts/%s/download?job=%s", project, refName, job)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	artifactsBuf := new(bytes.Buffer)
+	resp, err := s.client.Do(req, artifactsBuf)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return artifactsBuf, resp, err
+}
+
+// GetTraceFile gets a trace of a specific build of a project
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/builds.html#get-a-trace-file
+func (s *BuildsService) GetTraceFile(pid interface{}, buildID int) (io.Reader, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/builds/%d/trace", project, buildID)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	traceBuf := new(bytes.Buffer)
+	resp, err := s.client.Do(req, traceBuf)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return traceBuf, resp, err
+}
+
+// CancelBuild cancels a single build of a project.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/builds.html#cancel-a-build
+func (s *BuildsService) CancelBuild(pid interface{}, buildID int) (*Build, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/builds/%d/cancel", project, buildID)
+
+	req, err := s.client.NewRequest("POST", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	build := new(Build)
+	resp, err := s.client.Do(req, build)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return build, resp, err
+}
+
+// RetryBuild retries a single build of a project
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/builds.html#retry-a-build
+func (s *BuildsService) RetryBuild(pid interface{}, buildID int) (*Build, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/builds/%d/retry", project, buildID)
+
+	req, err := s.client.NewRequest("POST", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	build := new(Build)
+	resp, err := s.client.Do(req, build)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return build, resp, err
+}
+
+// EraseBuild erases a single build of a project, removes a build
+// artifacts and a build trace.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/builds.html#erase-a-build
+func (s *BuildsService) EraseBuild(pid interface{}, buildID int) (*Build, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/builds/%d/erase", project, buildID)
+
+	req, err := s.client.NewRequest("POST", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	build := new(Build)
+	resp, err := s.client.Do(req, build)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return build, resp, err
+}
+
+// KeepArtifacts prevents artifacts from being deleted when
+// expiration is set.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/builds.html#keep-artifacts
+func (s *BuildsService) KeepArtifacts(pid interface{}, buildID int) (*Build, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/builds/%d/artifacts/keep", project, buildID)
+
+	req, err := s.client.NewRequest("POST", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	build := new(Build)
+	resp, err := s.client.Do(req, build)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return build, resp, err
+}
+
+// PlayBuild triggers a nanual action to start a build.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/builds.html#play-a-build
+func (s *BuildsService) PlayBuild(pid interface{}, buildID int) (*Build, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/builds/%d/play", project, buildID)
+
+	req, err := s.client.NewRequest("POST", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	build := new(Build)
+	resp, err := s.client.Do(req, build)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return build, resp, err
+}
diff --git a/vendor/github.com/xanzy/go-gitlab/commits.go b/vendor/github.com/xanzy/go-gitlab/commits.go
new file mode 100644
index 0000000000000000000000000000000000000000..c61a6b7f390e729d64b3ecf3fd6267269dc5046d
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/commits.go
@@ -0,0 +1,359 @@
+//
+// Copyright 2015, Sander van Harmelen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package gitlab
+
+import (
+	"fmt"
+	"net/url"
+	"time"
+)
+
+// CommitsService handles communication with the commit related methods
+// of the GitLab API.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html
+type CommitsService struct {
+	client *Client
+}
+
+// Commit represents a GitLab commit.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html
+type Commit struct {
+	ID            string     `json:"id"`
+	ShortID       string     `json:"short_id"`
+	Title         string     `json:"title"`
+	AuthorName    string     `json:"author_name"`
+	AuthorEmail   string     `json:"author_email"`
+	AuthoredDate  *time.Time `json:"authored_date"`
+	CommittedDate *time.Time `json:"committed_date"`
+	CreatedAt     *time.Time `json:"created_at"`
+	Message       string     `json:"message"`
+	ParentsIds    []string   `json:"parents_ids"`
+}
+
+func (c Commit) String() string {
+	return Stringify(c)
+}
+
+// ListCommitsOptions represents the available ListCommits() options.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#list-repository-commits
+type ListCommitsOptions struct {
+	ListOptions
+	RefName *string   `url:"ref_name,omitempty" json:"ref_name,omitempty"`
+	Since   time.Time `url:"since,omitempty" json:"since,omitempty"`
+	Until   time.Time `url:"until,omitempty" json:"until,omitempty"`
+}
+
+// ListCommits gets a list of repository commits in a project.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#list-commits
+func (s *CommitsService) ListCommits(
+	pid interface{},
+	opt *ListCommitsOptions) ([]*Commit, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/commits", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("GET", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var c []*Commit
+	resp, err := s.client.Do(req, &c)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return c, resp, err
+}
+
+// GetCommit gets a specific commit identified by the commit hash or name of a
+// branch or tag.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#get-a-single-commit
+func (s *CommitsService) GetCommit(
+	pid interface{},
+	sha string) (*Commit, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/commits/%s", url.QueryEscape(project), sha)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	c := new(Commit)
+	resp, err := s.client.Do(req, c)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return c, resp, err
+}
+
+// Diff represents a GitLab diff.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html
+type Diff struct {
+	Diff        string `json:"diff"`
+	NewPath     string `json:"new_path"`
+	OldPath     string `json:"old_path"`
+	AMode       string `json:"a_mode"`
+	BMode       string `json:"b_mode"`
+	NewFile     bool   `json:"new_file"`
+	RenamedFile bool   `json:"renamed_file"`
+	DeletedFile bool   `json:"deleted_file"`
+}
+
+func (d Diff) String() string {
+	return Stringify(d)
+}
+
+// GetCommitDiff gets the diff of a commit in a project..
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/commits.html#get-the-diff-of-a-commit
+func (s *CommitsService) GetCommitDiff(
+	pid interface{},
+	sha string) ([]*Diff, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/commits/%s/diff", url.QueryEscape(project), sha)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var d []*Diff
+	resp, err := s.client.Do(req, &d)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return d, resp, err
+}
+
+// CommitComment represents a GitLab commit comment.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html
+type CommitComment struct {
+	Note     string `json:"note"`
+	Path     string `json:"path"`
+	Line     int    `json:"line"`
+	LineType string `json:"line_type"`
+	Author   Author `json:"author"`
+}
+
+// Author represents a GitLab commit author
+type Author struct {
+	ID        int        `json:"id"`
+	Username  string     `json:"username"`
+	Email     string     `json:"email"`
+	Name      string     `json:"name"`
+	State     string     `json:"state"`
+	Blocked   bool       `json:"blocked"`
+	CreatedAt *time.Time `json:"created_at"`
+}
+
+func (c CommitComment) String() string {
+	return Stringify(c)
+}
+
+// GetCommitComments gets the comments of a commit in a project.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/commits.html#get-the-comments-of-a-commit
+func (s *CommitsService) GetCommitComments(
+	pid interface{},
+	sha string) ([]*CommitComment, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/commits/%s/comments", url.QueryEscape(project), sha)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var c []*CommitComment
+	resp, err := s.client.Do(req, &c)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return c, resp, err
+}
+
+// PostCommitCommentOptions represents the available PostCommitComment()
+// options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/commits.html#post-comment-to-commit
+type PostCommitCommentOptions struct {
+	Note     *string `url:"note,omitempty" json:"note,omitempty"`
+	Path     *string `url:"path" json:"path"`
+	Line     *int    `url:"line" json:"line"`
+	LineType *string `url:"line_type" json:"line_type"`
+}
+
+// PostCommitComment adds a comment to a commit. Optionally you can post
+// comments on a specific line of a commit. Therefor both path, line_new and
+// line_old are required.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/commits.html#post-comment-to-commit
+func (s *CommitsService) PostCommitComment(
+	pid interface{},
+	sha string,
+	opt *PostCommitCommentOptions) (*CommitComment, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/commits/%s/comments", url.QueryEscape(project), sha)
+
+	req, err := s.client.NewRequest("POST", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	c := new(CommitComment)
+	resp, err := s.client.Do(req, c)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return c, resp, err
+}
+
+// GetCommitStatusesOptions represents the available GetCommitStatuses() options.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#get-the-status-of-a-commit
+type GetCommitStatusesOptions struct {
+	Ref   *string `url:"ref,omitempty" json:"ref,omitempty"`
+	Stage *string `url:"stage,omitempty" json:"stage,omitempty"`
+	Name  *string `url:"name,omitempty" json:"name,omitempty"`
+	All   *bool   `url:"all,omitempty" json:"all,omitempty"`
+}
+
+// CommitStatus represents a GitLab commit status.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#get-the-status-of-a-commit
+type CommitStatus struct {
+	ID          int        `json:"id"`
+	SHA         string     `json:"sha"`
+	Ref         string     `json:"ref"`
+	Status      string     `json:"status"`
+	Name        string     `json:"name"`
+	TargetURL   string     `json:"target_url"`
+	Description string     `json:"description"`
+	CreatedAt   *time.Time `json:"created_at"`
+	StartedAt   *time.Time `json:"started_at"`
+	FinishedAt  *time.Time `json:"finished_at"`
+	Author      Author     `json:"author"`
+}
+
+// GetCommitStatuses gets the statuses of a commit in a project.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#get-the-status-of-a-commit
+func (s *CommitsService) GetCommitStatuses(
+	pid interface{},
+	sha string,
+	opt *GetCommitStatusesOptions) ([]*CommitStatus, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/commits/%s/statuses", url.QueryEscape(project), sha)
+
+	req, err := s.client.NewRequest("GET", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var cs []*CommitStatus
+	resp, err := s.client.Do(req, &cs)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return cs, resp, err
+}
+
+// SetCommitStatusOptions represents the available SetCommitStatus() options.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#post-the-status-to-commit
+type SetCommitStatusOptions struct {
+	State       BuildState `url:"state" json:"state"`
+	Ref         *string    `url:"ref,omitempty" json:"ref,omitempty"`
+	Name        *string    `url:"name,omitempty" json:"name,omitempty"`
+	Context     *string    `url:"context,omitempty" json:"context,omitempty"`
+	TargetURL   *string    `url:"target_url,omitempty" json:"target_url,omitempty"`
+	Description *string    `url:"description,omitempty" json:"description,omitempty"`
+}
+
+// BuildState represents a GitLab build state
+type BuildState string
+
+// These constants represent all valid build states
+const (
+	Pending  BuildState = "pending"
+	Running  BuildState = "running"
+	Success  BuildState = "success"
+	Failed   BuildState = "failed"
+	Canceled BuildState = "canceled"
+)
+
+// SetCommitStatus sets the status of a commit in a project.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#post-the-status-to-commit
+func (s *CommitsService) SetCommitStatus(
+	pid interface{},
+	sha string,
+	opt *SetCommitStatusOptions) (*CommitStatus, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/statuses/%s", url.QueryEscape(project), sha)
+
+	req, err := s.client.NewRequest("POST", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var cs *CommitStatus
+	resp, err := s.client.Do(req, &cs)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return cs, resp, err
+}
diff --git a/vendor/github.com/xanzy/go-gitlab/deploy_keys.go b/vendor/github.com/xanzy/go-gitlab/deploy_keys.go
new file mode 100644
index 0000000000000000000000000000000000000000..1dcf99cbb8f87c38bb95dfe227cc2615e6982af5
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/deploy_keys.go
@@ -0,0 +1,152 @@
+//
+// Copyright 2015, Sander van Harmelen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package gitlab
+
+import (
+	"fmt"
+	"net/url"
+	"time"
+)
+
+// DeployKeysService handles communication with the keys related methods
+// of the GitLab API.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/deploy_keys.html
+type DeployKeysService struct {
+	client *Client
+}
+
+// DeployKey represents a GitLab deploy key.
+type DeployKey struct {
+	ID        int        `json:"id"`
+	Title     string     `json:"title"`
+	Key       string     `json:"key"`
+	CreatedAt *time.Time `json:"created_at"`
+}
+
+func (k DeployKey) String() string {
+	return Stringify(k)
+}
+
+// ListDeployKeys gets a list of a project's deploy keys
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/deploy_keys.html#list-deploy-keys
+func (s *DeployKeysService) ListDeployKeys(pid interface{}) ([]*DeployKey, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/keys", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var k []*DeployKey
+	resp, err := s.client.Do(req, &k)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return k, resp, err
+}
+
+// GetDeployKey gets a single deploy key.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/deploy_keys.html#single-deploy-key
+func (s *DeployKeysService) GetDeployKey(
+	pid interface{},
+	deployKey int) (*DeployKey, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/keys/%d", url.QueryEscape(project), deployKey)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	k := new(DeployKey)
+	resp, err := s.client.Do(req, k)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return k, resp, err
+}
+
+// AddDeployKeyOptions represents the available ADDDeployKey() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/deploy_keys.html#add-deploy-key
+type AddDeployKeyOptions struct {
+	Title *string `url:"title,omitempty" json:"title,omitempty"`
+	Key   *string `url:"key,omitempty" json:"key,omitempty"`
+}
+
+// AddDeployKey creates a new deploy key for a project. If deploy key already
+// exists in another project - it will be joined to project but only if
+// original one was is accessible by same user.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/deploy_keys.html#add-deploy-key
+func (s *DeployKeysService) AddDeployKey(
+	pid interface{},
+	opt *AddDeployKeyOptions) (*DeployKey, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/keys", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("POST", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	k := new(DeployKey)
+	resp, err := s.client.Do(req, k)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return k, resp, err
+}
+
+// DeleteDeployKey deletes a deploy key from a project.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/deploy_keys.html#delete-deploy-key
+func (s *DeployKeysService) DeleteDeployKey(pid interface{}, deployKey int) (*Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, err
+	}
+	u := fmt.Sprintf("projects/%s/keys/%d", url.QueryEscape(project), deployKey)
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
diff --git a/vendor/github.com/xanzy/go-gitlab/events.go b/vendor/github.com/xanzy/go-gitlab/events.go
new file mode 100644
index 0000000000000000000000000000000000000000..ef334592e821151ee7f07b5c6e3b81b69e4b0ffc
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/events.go
@@ -0,0 +1,557 @@
+//
+// Copyright 2015, Sander van Harmelen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package gitlab
+
+import "time"
+
+// PushEvent represents a push event.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#push-events
+type PushEvent struct {
+	ObjectKind  string `json:"object_kind"`
+	Before      string `json:"before"`
+	After       string `json:"after"`
+	Ref         string `json:"ref"`
+	CheckoutSha string `json:"checkout_sha"`
+	UserID      int    `json:"user_id"`
+	UserName    string `json:"user_name"`
+	UserEmail   string `json:"user_email"`
+	UserAvatar  string `json:"user_avatar"`
+	ProjectID   int    `json:"project_id"`
+	Project     struct {
+		Name              string               `json:"name"`
+		Description       string               `json:"description"`
+		AvatarURL         string               `json:"avatar_url"`
+		GitSSHURL         string               `json:"git_ssh_url"`
+		GitHTTPURL        string               `json:"git_http_url"`
+		Namespace         string               `json:"namespace"`
+		PathWithNamespace string               `json:"path_with_namespace"`
+		DefaultBranch     string               `json:"default_branch"`
+		Homepage          string               `json:"homepage"`
+		URL               string               `json:"url"`
+		SSHURL            string               `json:"ssh_url"`
+		HTTPURL           string               `json:"http_url"`
+		WebURL            string               `json:"web_url"`
+		VisibilityLevel   VisibilityLevelValue `json:"visibility_level"`
+	} `json:"project"`
+	Repository        *Repository `json:"repository"`
+	Commits           []*Commit   `json:"commits"`
+	TotalCommitsCount int         `json:"total_commits_count"`
+}
+
+// TagEvent represents a tag event.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#tag-events
+type TagEvent struct {
+	ObjectKind  string `json:"object_kind"`
+	Before      string `json:"before"`
+	After       string `json:"after"`
+	Ref         string `json:"ref"`
+	CheckoutSha string `json:"checkout_sha"`
+	UserID      int    `json:"user_id"`
+	UserName    string `json:"user_name"`
+	UserAvatar  string `json:"user_avatar"`
+	ProjectID   int    `json:"project_id"`
+	Project     struct {
+		Name              string               `json:"name"`
+		Description       string               `json:"description"`
+		AvatarURL         string               `json:"avatar_url"`
+		GitSSHURL         string               `json:"git_ssh_url"`
+		GitHTTPURL        string               `json:"git_http_url"`
+		Namespace         string               `json:"namespace"`
+		PathWithNamespace string               `json:"path_with_namespace"`
+		DefaultBranch     string               `json:"default_branch"`
+		Homepage          string               `json:"homepage"`
+		URL               string               `json:"url"`
+		SSHURL            string               `json:"ssh_url"`
+		HTTPURL           string               `json:"http_url"`
+		WebURL            string               `json:"web_url"`
+		VisibilityLevel   VisibilityLevelValue `json:"visibility_level"`
+	} `json:"project"`
+	Repository        *Repository `json:"repository"`
+	Commits           []*Commit   `json:"commits"`
+	TotalCommitsCount int         `json:"total_commits_count"`
+}
+
+// IssueEvent represents a issue event.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#issues-events
+type IssueEvent struct {
+	ObjectKind string `json:"object_kind"`
+	User       *User  `json:"user"`
+	Project    struct {
+		Name              string               `json:"name"`
+		Description       string               `json:"description"`
+		AvatarURL         string               `json:"avatar_url"`
+		GitSSHURL         string               `json:"git_ssh_url"`
+		GitHTTPURL        string               `json:"git_http_url"`
+		Namespace         string               `json:"namespace"`
+		PathWithNamespace string               `json:"path_with_namespace"`
+		DefaultBranch     string               `json:"default_branch"`
+		Homepage          string               `json:"homepage"`
+		URL               string               `json:"url"`
+		SSHURL            string               `json:"ssh_url"`
+		HTTPURL           string               `json:"http_url"`
+		WebURL            string               `json:"web_url"`
+		VisibilityLevel   VisibilityLevelValue `json:"visibility_level"`
+	} `json:"project"`
+	Repository       *Repository `json:"repository"`
+	ObjectAttributes struct {
+		ID          int    `json:"id"`
+		Title       string `json:"title"`
+		AssigneeID  int    `json:"assignee_id"`
+		AuthorID    int    `json:"author_id"`
+		ProjectID   int    `json:"project_id"`
+		CreatedAt   string `json:"created_at"` // Should be *time.Time (see Gitlab issue #21468)
+		UpdatedAt   string `json:"updated_at"` // Should be *time.Time (see Gitlab issue #21468)
+		Position    int    `json:"position"`
+		BranchName  string `json:"branch_name"`
+		Description string `json:"description"`
+		MilestoneID int    `json:"milestone_id"`
+		State       string `json:"state"`
+		Iid         int    `json:"iid"`
+		URL         string `json:"url"`
+		Action      string `json:"action"`
+	} `json:"object_attributes"`
+	Assignee struct {
+		Name      string `json:"name"`
+		Username  string `json:"username"`
+		AvatarURL string `json:"avatar_url"`
+	} `json:"assignee"`
+}
+
+// CommitCommentEvent represents a comment on a commit event.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#comment-on-commit
+type CommitCommentEvent struct {
+	ObjectKind string `json:"object_kind"`
+	User       *User  `json:"user"`
+	ProjectID  int    `json:"project_id"`
+	Project    struct {
+		Name              string               `json:"name"`
+		Description       string               `json:"description"`
+		AvatarURL         string               `json:"avatar_url"`
+		GitSSHURL         string               `json:"git_ssh_url"`
+		GitHTTPURL        string               `json:"git_http_url"`
+		Namespace         string               `json:"namespace"`
+		PathWithNamespace string               `json:"path_with_namespace"`
+		DefaultBranch     string               `json:"default_branch"`
+		Homepage          string               `json:"homepage"`
+		URL               string               `json:"url"`
+		SSHURL            string               `json:"ssh_url"`
+		HTTPURL           string               `json:"http_url"`
+		WebURL            string               `json:"web_url"`
+		VisibilityLevel   VisibilityLevelValue `json:"visibility_level"`
+	} `json:"project"`
+	Repository       *Repository `json:"repository"`
+	ObjectAttributes struct {
+		ID           int    `json:"id"`
+		Note         string `json:"note"`
+		NoteableType string `json:"noteable_type"`
+		AuthorID     int    `json:"author_id"`
+		CreatedAt    string `json:"created_at"`
+		UpdatedAt    string `json:"updated_at"`
+		ProjectID    int    `json:"project_id"`
+		Attachment   string `json:"attachment"`
+		LineCode     string `json:"line_code"`
+		CommitID     string `json:"commit_id"`
+		NoteableID   int    `json:"noteable_id"`
+		System       bool   `json:"system"`
+		StDiff       struct {
+			Diff        string `json:"diff"`
+			NewPath     string `json:"new_path"`
+			OldPath     string `json:"old_path"`
+			AMode       string `json:"a_mode"`
+			BMode       string `json:"b_mode"`
+			NewFile     bool   `json:"new_file"`
+			RenamedFile bool   `json:"renamed_file"`
+			DeletedFile bool   `json:"deleted_file"`
+		} `json:"st_diff"`
+	} `json:"object_attributes"`
+	Commit *Commit `json:"commit"`
+}
+
+// MergeCommentEvent represents a comment on a merge event.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#comment-on-merge-request
+type MergeCommentEvent struct {
+	ObjectKind string `json:"object_kind"`
+	User       *User  `json:"user"`
+	ProjectID  int    `json:"project_id"`
+	Project    struct {
+		Name              string               `json:"name"`
+		Description       string               `json:"description"`
+		AvatarURL         string               `json:"avatar_url"`
+		GitSSHURL         string               `json:"git_ssh_url"`
+		GitHTTPURL        string               `json:"git_http_url"`
+		Namespace         string               `json:"namespace"`
+		PathWithNamespace string               `json:"path_with_namespace"`
+		DefaultBranch     string               `json:"default_branch"`
+		Homepage          string               `json:"homepage"`
+		URL               string               `json:"url"`
+		SSHURL            string               `json:"ssh_url"`
+		HTTPURL           string               `json:"http_url"`
+		WebURL            string               `json:"web_url"`
+		VisibilityLevel   VisibilityLevelValue `json:"visibility_level"`
+	} `json:"project"`
+	Repository       *Repository `json:"repository"`
+	ObjectAttributes struct {
+		ID           int    `json:"id"`
+		Note         string `json:"note"`
+		NoteableType string `json:"noteable_type"`
+		AuthorID     int    `json:"author_id"`
+		CreatedAt    string `json:"created_at"`
+		UpdatedAt    string `json:"updated_at"`
+		ProjectID    int    `json:"project_id"`
+		Attachment   string `json:"attachment"`
+		LineCode     string `json:"line_code"`
+		CommitID     string `json:"commit_id"`
+		NoteableID   int    `json:"noteable_id"`
+		System       bool   `json:"system"`
+		StDiff       *Diff  `json:"st_diff"`
+		URL          string `json:"url"`
+	} `json:"object_attributes"`
+	MergeRequest *MergeRequest `json:"merge_request"`
+}
+
+// IssueCommentEvent represents a comment on an issue event.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#comment-on-issue
+type IssueCommentEvent struct {
+	ObjectKind string `json:"object_kind"`
+	User       *User  `json:"user"`
+	ProjectID  int    `json:"project_id"`
+	Project    struct {
+		Name              string               `json:"name"`
+		Description       string               `json:"description"`
+		AvatarURL         string               `json:"avatar_url"`
+		GitSSHURL         string               `json:"git_ssh_url"`
+		GitHTTPURL        string               `json:"git_http_url"`
+		Namespace         string               `json:"namespace"`
+		PathWithNamespace string               `json:"path_with_namespace"`
+		DefaultBranch     string               `json:"default_branch"`
+		Homepage          string               `json:"homepage"`
+		URL               string               `json:"url"`
+		SSHURL            string               `json:"ssh_url"`
+		HTTPURL           string               `json:"http_url"`
+		WebURL            string               `json:"web_url"`
+		VisibilityLevel   VisibilityLevelValue `json:"visibility_level"`
+	} `json:"project"`
+	Repository       *Repository `json:"repository"`
+	ObjectAttributes struct {
+		ID           int     `json:"id"`
+		Note         string  `json:"note"`
+		NoteableType string  `json:"noteable_type"`
+		AuthorID     int     `json:"author_id"`
+		CreatedAt    string  `json:"created_at"`
+		UpdatedAt    string  `json:"updated_at"`
+		ProjectID    int     `json:"project_id"`
+		Attachment   string  `json:"attachment"`
+		LineCode     string  `json:"line_code"`
+		CommitID     string  `json:"commit_id"`
+		NoteableID   int     `json:"noteable_id"`
+		System       bool    `json:"system"`
+		StDiff       []*Diff `json:"st_diff"`
+		URL          string  `json:"url"`
+	} `json:"object_attributes"`
+	Issue *Issue `json:"issue"`
+}
+
+// SnippetCommentEvent represents a comment on a snippet event.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#comment-on-code-snippet
+type SnippetCommentEvent struct {
+	ObjectKind string `json:"object_kind"`
+	User       *User  `json:"user"`
+	ProjectID  int    `json:"project_id"`
+	Project    struct {
+		Name              string               `json:"name"`
+		Description       string               `json:"description"`
+		AvatarURL         string               `json:"avatar_url"`
+		GitSSHURL         string               `json:"git_ssh_url"`
+		GitHTTPURL        string               `json:"git_http_url"`
+		Namespace         string               `json:"namespace"`
+		PathWithNamespace string               `json:"path_with_namespace"`
+		DefaultBranch     string               `json:"default_branch"`
+		Homepage          string               `json:"homepage"`
+		URL               string               `json:"url"`
+		SSHURL            string               `json:"ssh_url"`
+		HTTPURL           string               `json:"http_url"`
+		WebURL            string               `json:"web_url"`
+		VisibilityLevel   VisibilityLevelValue `json:"visibility_level"`
+	} `json:"project"`
+	Repository       *Repository `json:"repository"`
+	ObjectAttributes struct {
+		ID           int    `json:"id"`
+		Note         string `json:"note"`
+		NoteableType string `json:"noteable_type"`
+		AuthorID     int    `json:"author_id"`
+		CreatedAt    string `json:"created_at"`
+		UpdatedAt    string `json:"updated_at"`
+		ProjectID    int    `json:"project_id"`
+		Attachment   string `json:"attachment"`
+		LineCode     string `json:"line_code"`
+		CommitID     string `json:"commit_id"`
+		NoteableID   int    `json:"noteable_id"`
+		System       bool   `json:"system"`
+		StDiff       *Diff  `json:"st_diff"`
+		URL          string `json:"url"`
+	} `json:"object_attributes"`
+	Snippet *Snippet `json:"snippet"`
+}
+
+// MergeEvent represents a merge event.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#merge-request-events
+type MergeEvent struct {
+	ObjectKind string `json:"object_kind"`
+	User       *User  `json:"user"`
+	Project    struct {
+		Name              string               `json:"name"`
+		Description       string               `json:"description"`
+		AvatarURL         string               `json:"avatar_url"`
+		GitSSHURL         string               `json:"git_ssh_url"`
+		GitHTTPURL        string               `json:"git_http_url"`
+		Namespace         string               `json:"namespace"`
+		PathWithNamespace string               `json:"path_with_namespace"`
+		DefaultBranch     string               `json:"default_branch"`
+		Homepage          string               `json:"homepage"`
+		URL               string               `json:"url"`
+		SSHURL            string               `json:"ssh_url"`
+		HTTPURL           string               `json:"http_url"`
+		WebURL            string               `json:"web_url"`
+		VisibilityLevel   VisibilityLevelValue `json:"visibility_level"`
+	} `json:"project"`
+	ObjectAttributes struct {
+		ID              int       `json:"id"`
+		TargetBranch    string    `json:"target_branch"`
+		SourceBranch    string    `json:"source_branch"`
+		SourceProjectID int       `json:"source_project_id"`
+		AuthorID        int       `json:"author_id"`
+		AssigneeID      int       `json:"assignee_id"`
+		Title           string    `json:"title"`
+		CreatedAt       string    `json:"created_at"` // Should be *time.Time (see Gitlab issue #21468)
+		UpdatedAt       string    `json:"updated_at"` // Should be *time.Time (see Gitlab issue #21468)
+		StCommits       []*Commit `json:"st_commits"`
+		StDiffs         []*Diff   `json:"st_diffs"`
+		MilestoneID     int       `json:"milestone_id"`
+		State           string    `json:"state"`
+		MergeStatus     string    `json:"merge_status"`
+		TargetProjectID int       `json:"target_project_id"`
+		Iid             int       `json:"iid"`
+		Description     string    `json:"description"`
+		Position        int       `json:"position"`
+		LockedAt        string    `json:"locked_at"`
+		UpdatedByID     int       `json:"updated_by_id"`
+		MergeError      string    `json:"merge_error"`
+		MergeParams     struct {
+			ForceRemoveSourceBranch string `json:"force_remove_source_branch"`
+		} `json:"merge_params"`
+		MergeWhenBuildSucceeds   bool        `json:"merge_when_build_succeeds"`
+		MergeUserID              int         `json:"merge_user_id"`
+		MergeCommitSha           string      `json:"merge_commit_sha"`
+		DeletedAt                string      `json:"deleted_at"`
+		ApprovalsBeforeMerge     string      `json:"approvals_before_merge"`
+		RebaseCommitSha          string      `json:"rebase_commit_sha"`
+		InProgressMergeCommitSha string      `json:"in_progress_merge_commit_sha"`
+		LockVersion              int         `json:"lock_version"`
+		TimeEstimate             int         `json:"time_estimate"`
+		Source                   *Repository `json:"source"`
+		Target                   *Repository `json:"target"`
+		LastCommit               struct {
+			ID        string     `json:"id"`
+			Message   string     `json:"message"`
+			Timestamp *time.Time `json:"timestamp"`
+			URL       string     `json:"url"`
+			Author    *Author    `json:"author"`
+		} `json:"last_commit"`
+		WorkInProgress bool   `json:"work_in_progress"`
+		URL            string `json:"url"`
+		Action         string `json:"action"`
+		Assignee       struct {
+			Name      string `json:"name"`
+			Username  string `json:"username"`
+			AvatarURL string `json:"avatar_url"`
+		} `json:"assignee"`
+	} `json:"object_attributes"`
+	Repository *Repository `json:"repository"`
+	Assignee   struct {
+		Name      string `json:"name"`
+		Username  string `json:"username"`
+		AvatarURL string `json:"avatar_url"`
+	} `json:"assignee"`
+}
+
+// WikiPageEvent represents a wiki page event.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#wiki-page-events
+type WikiPageEvent struct {
+	ObjectKind string `json:"object_kind"`
+	User       *User  `json:"user"`
+	Project    struct {
+		Name              string               `json:"name"`
+		Description       string               `json:"description"`
+		AvatarURL         string               `json:"avatar_url"`
+		GitSSHURL         string               `json:"git_ssh_url"`
+		GitHTTPURL        string               `json:"git_http_url"`
+		Namespace         string               `json:"namespace"`
+		PathWithNamespace string               `json:"path_with_namespace"`
+		DefaultBranch     string               `json:"default_branch"`
+		Homepage          string               `json:"homepage"`
+		URL               string               `json:"url"`
+		SSHURL            string               `json:"ssh_url"`
+		HTTPURL           string               `json:"http_url"`
+		WebURL            string               `json:"web_url"`
+		VisibilityLevel   VisibilityLevelValue `json:"visibility_level"`
+	} `json:"project"`
+	Wiki struct {
+		WebURL            string `json:"web_url"`
+		GitSSHURL         string `json:"git_ssh_url"`
+		GitHTTPURL        string `json:"git_http_url"`
+		PathWithNamespace string `json:"path_with_namespace"`
+		DefaultBranch     string `json:"default_branch"`
+	} `json:"wiki"`
+	ObjectAttributes struct {
+		Title   string `json:"title"`
+		Content string `json:"content"`
+		Format  string `json:"format"`
+		Message string `json:"message"`
+		Slug    string `json:"slug"`
+		URL     string `json:"url"`
+		Action  string `json:"action"`
+	} `json:"object_attributes"`
+}
+
+// PipelineEvent represents a pipeline event.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#pipeline-events
+type PipelineEvent struct {
+	ObjectKind       string `json:"object_kind"`
+	ObjectAttributes struct {
+		ID         int      `json:"id"`
+		Ref        string   `json:"ref"`
+		Tag        bool     `json:"tag"`
+		Sha        string   `json:"sha"`
+		BeforeSha  string   `json:"before_sha"`
+		Status     string   `json:"status"`
+		Stages     []string `json:"stages"`
+		CreatedAt  string   `json:"created_at"`
+		FinishedAt string   `json:"finished_at"`
+		Duration   int      `json:"duration"`
+	} `json:"object_attributes"`
+	User struct {
+		Name      string `json:"name"`
+		Username  string `json:"username"`
+		AvatarURL string `json:"avatar_url"`
+	} `json:"user"`
+	Project struct {
+		Name              string               `json:"name"`
+		Description       string               `json:"description"`
+		AvatarURL         string               `json:"avatar_url"`
+		GitSSHURL         string               `json:"git_ssh_url"`
+		GitHTTPURL        string               `json:"git_http_url"`
+		Namespace         string               `json:"namespace"`
+		PathWithNamespace string               `json:"path_with_namespace"`
+		DefaultBranch     string               `json:"default_branch"`
+		Homepage          string               `json:"homepage"`
+		URL               string               `json:"url"`
+		SSHURL            string               `json:"ssh_url"`
+		HTTPURL           string               `json:"http_url"`
+		WebURL            string               `json:"web_url"`
+		VisibilityLevel   VisibilityLevelValue `json:"visibility_level"`
+	} `json:"project"`
+	Commit struct {
+		ID        string    `json:"id"`
+		Message   string    `json:"message"`
+		Timestamp time.Time `json:"timestamp"`
+		URL       string    `json:"url"`
+		Author    struct {
+			Name  string `json:"name"`
+			Email string `json:"email"`
+		} `json:"author"`
+	} `json:"commit"`
+	Builds []struct {
+		ID         int    `json:"id"`
+		Stage      string `json:"stage"`
+		Name       string `json:"name"`
+		Status     string `json:"status"`
+		CreatedAt  string `json:"created_at"`
+		StartedAt  string `json:"started_at"`
+		FinishedAt string `json:"finished_at"`
+		When       string `json:"when"`
+		Manual     bool   `json:"manual"`
+		User       struct {
+			Name      string `json:"name"`
+			Username  string `json:"username"`
+			AvatarURL string `json:"avatar_url"`
+		} `json:"user"`
+		Runner        string `json:"runner"`
+		ArtifactsFile struct {
+			Filename string `json:"filename"`
+			Size     string `json:"size"`
+		} `json:"artifacts_file"`
+	} `json:"builds"`
+}
+
+//BuildEvent represents a build event
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#build-events
+type BuildEvent struct {
+	ObjectKind        string `json:"object_kind"`
+	Ref               string `json:"ref"`
+	Tag               bool   `json:"tag"`
+	BeforeSha         string `json:"before_sha"`
+	Sha               string `json:"sha"`
+	BuildID           int    `json:"build_id"`
+	BuildName         string `json:"build_name"`
+	BuildStage        string `json:"build_stage"`
+	BuildStatus       string `json:"build_status"`
+	BuildStartedAt    string `json:"build_started_at"`
+	BuildFinishedAt   string `json:"build_finished_at"`
+	BuildDuration     string `json:"build_duration"`
+	BuildAllowFailure bool   `json:"build_allow_failure"`
+	ProjectID         int    `json:"project_id"`
+	ProjectName       string `json:"project_name"`
+	User              struct {
+		ID    int    `json:"id"`
+		Name  string `json:"name"`
+		Email string `json:"email"`
+	} `json:"user"`
+	Commit struct {
+		ID          int    `json:"id"`
+		Sha         string `json:"sha"`
+		Message     string `json:"message"`
+		AuthorName  string `json:"author_name"`
+		AuthorEmail string `json:"author_email"`
+		Status      string `json:"status"`
+		Duration    string `json:"duration"`
+		StartedAt   string `json:"started_at"`
+		FinishedAt  string `json:"finished_at"`
+	} `json:"commit"`
+	Repository *Repository `json:"repository"`
+}
diff --git a/vendor/github.com/xanzy/go-gitlab/gitlab.go b/vendor/github.com/xanzy/go-gitlab/gitlab.go
new file mode 100644
index 0000000000000000000000000000000000000000..c8f092e078b45957cdf3276fceba5f523d9dc534
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/gitlab.go
@@ -0,0 +1,490 @@
+//
+// Copyright 2015, Sander van Harmelen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package gitlab
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"net/http"
+	"net/url"
+	"strconv"
+	"strings"
+
+	"github.com/google/go-querystring/query"
+)
+
+const (
+	libraryVersion = "0.1.1"
+	defaultBaseURL = "https://gitlab.com/api/v3/"
+	userAgent      = "go-gitlab/" + libraryVersion
+)
+
+// tokenType represents a token type within GitLab.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/
+type tokenType int
+
+// List of available token type
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/
+const (
+	privateToken tokenType = iota
+	oAuthToken
+)
+
+// AccessLevelValue represents a permission level within GitLab.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/permissions/permissions.html
+type AccessLevelValue int
+
+// List of available access levels
+//
+// GitLab API docs: https://docs.gitlab.com/ce/permissions/permissions.html
+const (
+	GuestPermissions     AccessLevelValue = 10
+	ReporterPermissions  AccessLevelValue = 20
+	DeveloperPermissions AccessLevelValue = 30
+	MasterPermissions    AccessLevelValue = 40
+	OwnerPermission      AccessLevelValue = 50
+)
+
+// NotificationLevelValue represents a notification level within Gitlab.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/
+type NotificationLevelValue int
+
+// List of available notification levels
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/
+const (
+	DisabledNotifications NotificationLevelValue = iota
+	ParticipatingNotifications
+	WatchNotifications
+	GlobalNotifications
+	MentionNotifications
+)
+
+// VisibilityLevelValue represents a visibility level within GitLab.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/
+type VisibilityLevelValue int
+
+// List of available visibility levels
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/
+const (
+	PrivateVisibility  VisibilityLevelValue = 0
+	InternalVisibility VisibilityLevelValue = 10
+	PublicVisibility   VisibilityLevelValue = 20
+)
+
+// A Client manages communication with the GitLab API.
+type Client struct {
+	// HTTP client used to communicate with the API.
+	client *http.Client
+
+	// Base URL for API requests. Defaults to the public GitLab API, but can be
+	// set to a domain endpoint to use with aself hosted GitLab server. baseURL
+	// should always be specified with a trailing slash.
+	baseURL *url.URL
+
+	// token type used to make authenticated API calls.
+	tokenType tokenType
+
+	// token used to make authenticated API calls.
+	token string
+
+	// User agent used when communicating with the GitLab API.
+	UserAgent string
+
+	// Services used for talking to different parts of the GitLab API.
+	Branches        *BranchesService
+	BuildVariables  *BuildVariablesService
+	Builds          *BuildsService
+	Commits         *CommitsService
+	DeployKeys      *DeployKeysService
+	Groups          *GroupsService
+	Issues          *IssuesService
+	Labels          *LabelsService
+	MergeRequests   *MergeRequestsService
+	Milestones      *MilestonesService
+	Namespaces      *NamespacesService
+	Notes           *NotesService
+	Projects        *ProjectsService
+	ProjectSnippets *ProjectSnippetsService
+	Repositories    *RepositoriesService
+	RepositoryFiles *RepositoryFilesService
+	Services        *ServicesService
+	Session         *SessionService
+	Settings        *SettingsService
+	SystemHooks     *SystemHooksService
+	Tags            *TagsService
+	Users           *UsersService
+}
+
+// ListOptions specifies the optional parameters to various List methods that
+// support pagination.
+type ListOptions struct {
+	// For paginated result sets, page of results to retrieve.
+	Page int `url:"page,omitempty" json:"page,omitempty"`
+
+	// For paginated result sets, the number of results to include per page.
+	PerPage int `url:"per_page,omitempty" json:"per_page,omitempty"`
+}
+
+// NewClient returns a new GitLab API client. If a nil httpClient is
+// provided, http.DefaultClient will be used. To use API methods which require
+// authentication, provide a valid private token.
+func NewClient(httpClient *http.Client, token string) *Client {
+	return newClient(httpClient, privateToken, token)
+}
+
+// NewOAuthClient returns a new GitLab API client. If a nil httpClient is
+// provided, http.DefaultClient will be used. To use API methods which require
+// authentication, provide a valid oauth token.
+func NewOAuthClient(httpClient *http.Client, token string) *Client {
+	return newClient(httpClient, oAuthToken, token)
+}
+
+func newClient(httpClient *http.Client, tokenType tokenType, token string) *Client {
+	if httpClient == nil {
+		httpClient = http.DefaultClient
+	}
+
+	c := &Client{client: httpClient, tokenType: tokenType, token: token, UserAgent: userAgent}
+	if err := c.SetBaseURL(defaultBaseURL); err != nil {
+		// should never happen since defaultBaseURL is our constant
+		panic(err)
+	}
+
+	c.Branches = &BranchesService{client: c}
+	c.BuildVariables = &BuildVariablesService{client: c}
+	c.Builds = &BuildsService{client: c}
+	c.Commits = &CommitsService{client: c}
+	c.DeployKeys = &DeployKeysService{client: c}
+	c.Groups = &GroupsService{client: c}
+	c.Issues = &IssuesService{client: c}
+	c.Labels = &LabelsService{client: c}
+	c.MergeRequests = &MergeRequestsService{client: c}
+	c.Milestones = &MilestonesService{client: c}
+	c.Notes = &NotesService{client: c}
+	c.Namespaces = &NamespacesService{client: c}
+	c.Projects = &ProjectsService{client: c}
+	c.ProjectSnippets = &ProjectSnippetsService{client: c}
+	c.Repositories = &RepositoriesService{client: c}
+	c.RepositoryFiles = &RepositoryFilesService{client: c}
+	c.Services = &ServicesService{client: c}
+	c.Session = &SessionService{client: c}
+	c.Settings = &SettingsService{client: c}
+	c.SystemHooks = &SystemHooksService{client: c}
+	c.Tags = &TagsService{client: c}
+	c.Users = &UsersService{client: c}
+
+	return c
+}
+
+// BaseURL return a copy of the baseURL.
+func (c *Client) BaseURL() *url.URL {
+	u := *c.baseURL
+	return &u
+}
+
+// SetBaseURL sets the base URL for API requests to a custom endpoint. urlStr
+// should always be specified with a trailing slash.
+func (c *Client) SetBaseURL(urlStr string) error {
+	// Make sure the given URL end with a slash
+	if !strings.HasSuffix(urlStr, "/") {
+		urlStr += "/"
+	}
+
+	var err error
+	c.baseURL, err = url.Parse(urlStr)
+	return err
+}
+
+// NewRequest creates an API request. A relative URL path can be provided in
+// urlStr, in which case it is resolved relative to the base URL of the Client.
+// Relative URL paths should always be specified without a preceding slash. If
+// specified, the value pointed to by body is JSON encoded and included as the
+// request body.
+func (c *Client) NewRequest(method, path string, opt interface{}) (*http.Request, error) {
+	u := *c.baseURL
+	// Set the encoded opaque data
+	u.Opaque = c.baseURL.Path + path
+
+	if opt != nil {
+		q, err := query.Values(opt)
+		if err != nil {
+			return nil, err
+		}
+		u.RawQuery = q.Encode()
+	}
+
+	req := &http.Request{
+		Method:     method,
+		URL:        &u,
+		Proto:      "HTTP/1.1",
+		ProtoMajor: 1,
+		ProtoMinor: 1,
+		Header:     make(http.Header),
+		Host:       u.Host,
+	}
+
+	if method == "POST" || method == "PUT" {
+		bodyBytes, err := json.Marshal(opt)
+		if err != nil {
+			return nil, err
+		}
+		bodyReader := bytes.NewReader(bodyBytes)
+
+		u.RawQuery = ""
+		req.Body = ioutil.NopCloser(bodyReader)
+		req.ContentLength = int64(bodyReader.Len())
+		req.Header.Set("Content-Type", "application/json")
+	}
+
+	req.Header.Set("Accept", "application/json")
+
+	switch c.tokenType {
+	case privateToken:
+		req.Header.Set("PRIVATE-TOKEN", c.token)
+	case oAuthToken:
+		req.Header.Set("Authorization", "Bearer "+c.token)
+	}
+
+	if c.UserAgent != "" {
+		req.Header.Set("User-Agent", c.UserAgent)
+	}
+
+	return req, nil
+}
+
+// Response is a GitLab API response. This wraps the standard http.Response
+// returned from GitLab and provides convenient access to things like
+// pagination links.
+type Response struct {
+	*http.Response
+
+	// These fields provide the page values for paginating through a set of
+	// results.  Any or all of these may be set to the zero value for
+	// responses that are not part of a paginated set, or for which there
+	// are no additional pages.
+
+	NextPage  int
+	PrevPage  int
+	FirstPage int
+	LastPage  int
+}
+
+// newResponse creats a new Response for the provided http.Response.
+func newResponse(r *http.Response) *Response {
+	response := &Response{Response: r}
+	response.populatePageValues()
+	return response
+}
+
+// populatePageValues parses the HTTP Link response headers and populates the
+// various pagination link values in the Reponse.
+func (r *Response) populatePageValues() {
+	if links, ok := r.Response.Header["Link"]; ok && len(links) > 0 {
+		for _, link := range strings.Split(links[0], ",") {
+			segments := strings.Split(strings.TrimSpace(link), ";")
+
+			// link must at least have href and rel
+			if len(segments) < 2 {
+				continue
+			}
+
+			// ensure href is properly formatted
+			if !strings.HasPrefix(segments[0], "<") || !strings.HasSuffix(segments[0], ">") {
+				continue
+			}
+
+			// try to pull out page parameter
+			url, err := url.Parse(segments[0][1 : len(segments[0])-1])
+			if err != nil {
+				continue
+			}
+			page := url.Query().Get("page")
+			if page == "" {
+				continue
+			}
+
+			for _, segment := range segments[1:] {
+				switch strings.TrimSpace(segment) {
+				case `rel="next"`:
+					r.NextPage, _ = strconv.Atoi(page)
+				case `rel="prev"`:
+					r.PrevPage, _ = strconv.Atoi(page)
+				case `rel="first"`:
+					r.FirstPage, _ = strconv.Atoi(page)
+				case `rel="last"`:
+					r.LastPage, _ = strconv.Atoi(page)
+				}
+
+			}
+		}
+	}
+}
+
+// Do sends an API request and returns the API response. The API response is
+// JSON decoded and stored in the value pointed to by v, or returned as an
+// error if an API error has occurred. If v implements the io.Writer
+// interface, the raw response body will be written to v, without attempting to
+// first decode it.
+func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
+	resp, err := c.client.Do(req)
+	if err != nil {
+		return nil, err
+	}
+	defer resp.Body.Close()
+
+	response := newResponse(resp)
+
+	err = CheckResponse(resp)
+	if err != nil {
+		// even though there was an error, we still return the response
+		// in case the caller wants to inspect it further
+		return response, err
+	}
+
+	if v != nil {
+		if w, ok := v.(io.Writer); ok {
+			_, err = io.Copy(w, resp.Body)
+		} else {
+			err = json.NewDecoder(resp.Body).Decode(v)
+		}
+	}
+	return response, err
+}
+
+// Helper function to accept and format both the project ID or name as project
+// identifier for all API calls.
+func parseID(id interface{}) (string, error) {
+	switch v := id.(type) {
+	case int:
+		return strconv.Itoa(v), nil
+	case string:
+		return v, nil
+	default:
+		return "", fmt.Errorf("invalid ID type %#v, the ID must be an int or a string", id)
+	}
+}
+
+// An ErrorResponse reports one or more errors caused by an API request.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/README.html#data-validation-and-error-reporting
+type ErrorResponse struct {
+	Response *http.Response // HTTP response that caused this error
+	Message  string         `json:"message"` // error message
+	Errors   []Error        `json:"errors"`  // more detail on individual errors
+}
+
+func (r *ErrorResponse) Error() string {
+	path, _ := url.QueryUnescape(r.Response.Request.URL.Opaque)
+	ru := fmt.Sprintf("%s://%s%s", r.Response.Request.URL.Scheme, r.Response.Request.URL.Host, path)
+
+	return fmt.Sprintf("%v %s: %d %v %+v",
+		r.Response.Request.Method, ru, r.Response.StatusCode, r.Message, r.Errors)
+}
+
+// An Error reports more details on an individual error in an ErrorResponse.
+// These are the possible validation error codes:
+//
+//     missing:
+//         resource does not exist
+//     missing_field:
+//         a required field on a resource has not been set
+//     invalid:
+//         the formatting of a field is invalid
+//     already_exists:
+//         another resource has the same valid as this field
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/README.html#data-validation-and-error-reporting
+type Error struct {
+	Resource string `json:"resource"` // resource on which the error occurred
+	Field    string `json:"field"`    // field on which the error occurred
+	Code     string `json:"code"`     // validation error code
+}
+
+func (e *Error) Error() string {
+	return fmt.Sprintf("%v error caused by %v field on %v resource",
+		e.Code, e.Field, e.Resource)
+}
+
+// CheckResponse checks the API response for errors, and returns them if
+// present.  A response is considered an error if it has a status code outside
+// the 200 range.  API error responses are expected to have either no response
+// body, or a JSON response body that maps to ErrorResponse.  Any other
+// response body will be silently ignored.
+func CheckResponse(r *http.Response) error {
+	if c := r.StatusCode; 200 <= c && c <= 299 {
+		return nil
+	}
+	errorResponse := &ErrorResponse{Response: r}
+	data, err := ioutil.ReadAll(r.Body)
+	if err == nil && data != nil {
+		json.Unmarshal(data, errorResponse)
+	}
+	return errorResponse
+}
+
+// Bool is a helper routine that allocates a new bool value
+// to store v and returns a pointer to it.
+func Bool(v bool) *bool {
+	p := new(bool)
+	*p = v
+	return p
+}
+
+// Int is a helper routine that allocates a new int32 value
+// to store v and returns a pointer to it, but unlike Int32
+// its argument value is an int.
+func Int(v int) *int {
+	p := new(int)
+	*p = v
+	return p
+}
+
+// String is a helper routine that allocates a new string value
+// to store v and returns a pointer to it.
+func String(v string) *string {
+	p := new(string)
+	*p = v
+	return p
+}
+
+// AccessLevel is a helper routine that allocates a new AccessLevelValue
+// to store v and returns a pointer to it.
+func AccessLevel(v AccessLevelValue) *AccessLevelValue {
+	p := new(AccessLevelValue)
+	*p = v
+	return p
+}
+
+// VisibilityLevel is a helper routine that allocates a new VisibilityLevelValue
+// to store v and returns a pointer to it.
+func VisibilityLevel(v VisibilityLevelValue) *VisibilityLevelValue {
+	p := new(VisibilityLevelValue)
+	*p = v
+	return p
+}
diff --git a/vendor/github.com/xanzy/go-gitlab/groups.go b/vendor/github.com/xanzy/go-gitlab/groups.go
new file mode 100644
index 0000000000000000000000000000000000000000..c73e863acc772804997ed527ee3602da2d0b204d
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/groups.go
@@ -0,0 +1,343 @@
+//
+// Copyright 2015, Sander van Harmelen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package gitlab
+
+import (
+	"fmt"
+	"time"
+)
+
+// GroupsService handles communication with the group related methods of
+// the GitLab API.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html
+type GroupsService struct {
+	client *Client
+}
+
+// Group represents a GitLab group.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html
+type Group struct {
+	ID          int        `json:"id"`
+	Name        string     `json:"name"`
+	Path        string     `json:"path"`
+	Description string     `json:"description"`
+	Projects    *[]Project `json:"projects,omitempty"`
+}
+
+// ListGroupsOptions represents the available ListGroups() options.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#list-project-groups
+type ListGroupsOptions struct {
+	ListOptions
+	Search *string `url:"search,omitempty" json:"search,omitempty"`
+}
+
+// ListGroups gets a list of groups. (As user: my groups, as admin: all groups)
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/groups.html#list-project-groups
+func (s *GroupsService) ListGroups(opt *ListGroupsOptions) ([]*Group, *Response, error) {
+	req, err := s.client.NewRequest("GET", "groups", opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var g []*Group
+	resp, err := s.client.Do(req, &g)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return g, resp, err
+}
+
+// GetGroup gets all details of a group.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#details-of-a-group
+func (s *GroupsService) GetGroup(gid interface{}) (*Group, *Response, error) {
+	group, err := parseID(gid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("groups/%s", group)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	g := new(Group)
+	resp, err := s.client.Do(req, g)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return g, resp, err
+}
+
+// CreateGroupOptions represents the available CreateGroup() options.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#new-group
+type CreateGroupOptions struct {
+	Name            *string               `url:"name,omitempty" json:"name,omitempty"`
+	Path            *string               `url:"path,omitempty" json:"path,omitempty"`
+	Description     *string               `url:"description,omitempty" json:"description,omitempty"`
+	VisibilityLevel *VisibilityLevelValue `url:"visibility_level" json:"visibility_level,omitempty"`
+}
+
+// CreateGroup creates a new project group. Available only for users who can
+// create groups.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#new-group
+func (s *GroupsService) CreateGroup(opt *CreateGroupOptions) (*Group, *Response, error) {
+	req, err := s.client.NewRequest("POST", "groups", opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	g := new(Group)
+	resp, err := s.client.Do(req, g)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return g, resp, err
+}
+
+// TransferGroup transfers a project to the Group namespace. Available only
+// for admin.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/groups.html#transfer-project-to-group
+func (s *GroupsService) TransferGroup(gid interface{}, project int) (*Group, *Response, error) {
+	group, err := parseID(gid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("groups/%s/projects/%d", group, project)
+
+	req, err := s.client.NewRequest("POST", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	g := new(Group)
+	resp, err := s.client.Do(req, g)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return g, resp, err
+}
+
+// DeleteGroup removes group with all projects inside.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#remove-group
+func (s *GroupsService) DeleteGroup(gid interface{}) (*Response, error) {
+	group, err := parseID(gid)
+	if err != nil {
+		return nil, err
+	}
+	u := fmt.Sprintf("groups/%s", group)
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
+
+// SearchGroup get all groups that match your string in their name or path.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#search-for-group
+func (s *GroupsService) SearchGroup(query string) ([]*Group, *Response, error) {
+	var q struct {
+		Search string `url:"search,omitempty" json:"search,omitempty"`
+	}
+	q.Search = query
+
+	req, err := s.client.NewRequest("GET", "groups", &q)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var g []*Group
+	resp, err := s.client.Do(req, &g)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return g, resp, err
+}
+
+// GroupMember represents a GitLab group member.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html
+type GroupMember struct {
+	ID          int              `json:"id"`
+	Username    string           `json:"username"`
+	Email       string           `json:"email"`
+	Name        string           `json:"name"`
+	State       string           `json:"state"`
+	CreatedAt   *time.Time       `json:"created_at"`
+	AccessLevel AccessLevelValue `json:"access_level"`
+}
+
+// ListGroupMembers get a list of group members viewable by the authenticated
+// user.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/groups.html#list-group-members
+func (s *GroupsService) ListGroupMembers(gid interface{}) ([]*GroupMember, *Response, error) {
+	group, err := parseID(gid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("groups/%s/members", group)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var g []*GroupMember
+	resp, err := s.client.Do(req, &g)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return g, resp, err
+}
+
+// ListGroupProjects get a list of group projects
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/groups.html#list-a-group-s-projects
+func (s *GroupsService) ListGroupProjects(gid interface{}) ([]*Project, *Response, error) {
+	group, err := parseID(gid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("groups/%s/projects", group)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var p []*Project
+	resp, err := s.client.Do(req, &p)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return p, resp, err
+}
+
+// AddGroupMemberOptions represents the available AddGroupMember() options.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#add-group-member
+type AddGroupMemberOptions struct {
+	UserID      *int              `url:"user_id,omitempty" json:"user_id,omitempty"`
+	AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"`
+}
+
+// AddGroupMember adds a user to the list of group members.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/groups.html#list-group-members
+func (s *GroupsService) AddGroupMember(
+	gid interface{},
+	opt *AddGroupMemberOptions) (*GroupMember, *Response, error) {
+	group, err := parseID(gid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("groups/%s/members", group)
+
+	req, err := s.client.NewRequest("POST", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	g := new(GroupMember)
+	resp, err := s.client.Do(req, g)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return g, resp, err
+}
+
+// UpdateGroupMemberOptions represents the available UpdateGroupMember()
+// options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/groups.html#edit-group-team-member
+type UpdateGroupMemberOptions struct {
+	AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"`
+}
+
+// UpdateGroupMember updates a group team member to a specified access level.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/groups.html#list-group-members
+func (s *GroupsService) UpdateGroupMember(
+	gid interface{},
+	user int,
+	opt *UpdateGroupMemberOptions) (*GroupMember, *Response, error) {
+	group, err := parseID(gid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("groups/%s/members/%d", group, user)
+
+	req, err := s.client.NewRequest("PUT", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	g := new(GroupMember)
+	resp, err := s.client.Do(req, g)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return g, resp, err
+}
+
+// RemoveGroupMember removes user from user team.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/groups.html#remove-user-from-user-team
+func (s *GroupsService) RemoveGroupMember(gid interface{}, user int) (*Response, error) {
+	group, err := parseID(gid)
+	if err != nil {
+		return nil, err
+	}
+	u := fmt.Sprintf("groups/%s/members/%d", group, user)
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
diff --git a/vendor/github.com/xanzy/go-gitlab/issues.go b/vendor/github.com/xanzy/go-gitlab/issues.go
new file mode 100644
index 0000000000000000000000000000000000000000..176628c2eb227d441586dfbcb3bf784dc1aaedfe
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/issues.go
@@ -0,0 +1,271 @@
+//
+// Copyright 2015, Sander van Harmelen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package gitlab
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/url"
+	"strings"
+	"time"
+)
+
+// IssuesService handles communication with the issue related methods
+// of the GitLab API.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html
+type IssuesService struct {
+	client *Client
+}
+
+// Issue represents a GitLab issue.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html
+type Issue struct {
+	ID          int        `json:"id"`
+	IID         int        `json:"iid"`
+	ProjectID   int        `json:"project_id"`
+	Title       string     `json:"title"`
+	Description string     `json:"description"`
+	Labels      []string   `json:"labels"`
+	Milestone   *Milestone `json:"milestone"`
+	Assignee    struct {
+		ID        int        `json:"id"`
+		Username  string     `json:"username"`
+		Email     string     `json:"email"`
+		Name      string     `json:"name"`
+		State     string     `json:"state"`
+		CreatedAt *time.Time `json:"created_at"`
+	} `json:"assignee"`
+	Author struct {
+		ID        int        `json:"id"`
+		Username  string     `json:"username"`
+		Email     string     `json:"email"`
+		Name      string     `json:"name"`
+		State     string     `json:"state"`
+		CreatedAt *time.Time `json:"created_at"`
+	} `json:"author"`
+	State          string     `json:"state"`
+	UpdatedAt      *time.Time `json:"updated_at"`
+	CreatedAt      *time.Time `json:"created_at"`
+	Subscribed     bool       `json:"subscribed"`
+	UserNotesCount int        `json:"user_notes_count"`
+	Confidential   bool       `json:"confidential"`
+	DueDate        string     `json:"due_date"`
+	WebURL         string     `json:"web_url"`
+}
+
+func (i Issue) String() string {
+	return Stringify(i)
+}
+
+// Labels is a custom type with specific marshaling characteristics.
+type Labels []string
+
+// MarshalJSON implements the json.Marshaler interface.
+func (l *Labels) MarshalJSON() ([]byte, error) {
+	return json.Marshal(strings.Join(*l, ","))
+}
+
+// ListIssuesOptions represents the available ListIssues() options.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-issues
+type ListIssuesOptions struct {
+	ListOptions
+	State   *string `url:"state,omitempty" json:"state,omitempty"`
+	Labels  Labels  `url:"labels,comma,omitempty" json:"labels,omitempty"`
+	OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"`
+	Sort    *string `url:"sort,omitempty" json:"sort,omitempty"`
+}
+
+// ListIssues gets all issues created by authenticated user. This function
+// takes pagination parameters page and per_page to restrict the list of issues.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-issues
+func (s *IssuesService) ListIssues(opt *ListIssuesOptions) ([]*Issue, *Response, error) {
+	req, err := s.client.NewRequest("GET", "issues", opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var i []*Issue
+	resp, err := s.client.Do(req, &i)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return i, resp, err
+}
+
+// ListProjectIssuesOptions represents the available ListProjectIssues() options.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-issues
+type ListProjectIssuesOptions struct {
+	ListOptions
+	IID       *int    `url:"iid,omitempty" json:"iid,omitempty"`
+	State     *string `url:"state,omitempty" json:"state,omitempty"`
+	Labels    Labels  `url:"labels,comma,omitempty" json:"labels,omitempty"`
+	Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"`
+	OrderBy   *string `url:"order_by,omitempty" json:"order_by,omitempty"`
+	Sort      *string `url:"sort,omitempty" json:"sort,omitempty"`
+}
+
+// ListProjectIssues gets a list of project issues. This function accepts
+// pagination parameters page and per_page to return the list of project issues.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-project-issues
+func (s *IssuesService) ListProjectIssues(
+	pid interface{},
+	opt *ListProjectIssuesOptions) ([]*Issue, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/issues", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("GET", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var i []*Issue
+	resp, err := s.client.Do(req, &i)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return i, resp, err
+}
+
+// GetIssue gets a single project issue.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#single-issues
+func (s *IssuesService) GetIssue(pid interface{}, issue int) (*Issue, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/issues/%d", url.QueryEscape(project), issue)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	i := new(Issue)
+	resp, err := s.client.Do(req, i)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return i, resp, err
+}
+
+// CreateIssueOptions represents the available CreateIssue() options.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#new-issues
+type CreateIssueOptions struct {
+	Title       *string `url:"title,omitempty" json:"title,omitempty"`
+	Description *string `url:"description,omitempty" json:"description,omitempty"`
+	AssigneeID  *int    `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
+	MilestoneID *int    `url:"milestone_id,omitempty" json:"milestone_id,omitempty"`
+	Labels      Labels  `url:"labels,comma,omitempty" json:"labels,omitempty"`
+}
+
+// CreateIssue creates a new project issue.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#new-issues
+func (s *IssuesService) CreateIssue(
+	pid interface{},
+	opt *CreateIssueOptions) (*Issue, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/issues", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("POST", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	i := new(Issue)
+	resp, err := s.client.Do(req, i)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return i, resp, err
+}
+
+// UpdateIssueOptions represents the available UpdateIssue() options.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#edit-issues
+type UpdateIssueOptions struct {
+	Title       *string `url:"title,omitempty" json:"title,omitempty"`
+	Description *string `url:"description,omitempty" json:"description,omitempty"`
+	AssigneeID  *int    `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
+	MilestoneID *int    `url:"milestone_id,omitempty" json:"milestone_id,omitempty"`
+	Labels      Labels  `url:"labels,comma,omitempty" json:"labels,omitempty"`
+	StateEvent  *string `url:"state_event,omitempty" json:"state_event,omitempty"`
+}
+
+// UpdateIssue updates an existing project issue. This function is also used
+// to mark an issue as closed.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#edit-issues
+func (s *IssuesService) UpdateIssue(
+	pid interface{},
+	issue int,
+	opt *UpdateIssueOptions) (*Issue, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/issues/%d", url.QueryEscape(project), issue)
+
+	req, err := s.client.NewRequest("PUT", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	i := new(Issue)
+	resp, err := s.client.Do(req, i)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return i, resp, err
+}
+
+// DeleteIssue deletes a single project issue.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#delete-an-issue
+func (s *IssuesService) DeleteIssue(pid interface{}, issue int) (*Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, err
+	}
+	u := fmt.Sprintf("projects/%s/issues/%d", url.QueryEscape(project), issue)
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
diff --git a/vendor/github.com/xanzy/go-gitlab/labels.go b/vendor/github.com/xanzy/go-gitlab/labels.go
new file mode 100644
index 0000000000000000000000000000000000000000..7063da91b785ff335e22093f2cc6faede0dc653c
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/labels.go
@@ -0,0 +1,168 @@
+//
+// Copyright 2015, Sander van Harmelen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package gitlab
+
+import (
+	"fmt"
+	"net/url"
+)
+
+// LabelsService handles communication with the label related methods
+// of the GitLab API.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html
+type LabelsService struct {
+	client *Client
+}
+
+// Label represents a GitLab label.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html
+type Label struct {
+	Name                   string `json:"name"`
+	Color                  string `json:"color"`
+	Description            string `json:"description"`
+	OpenIssuesCount        int    `json:"open_issues_count"`
+	ClosedIssuesCount      int    `json:"closed_issues_count"`
+	OpenMergeRequestsCount int    `json:"open_merge_requests_count"`
+}
+
+func (l Label) String() string {
+	return Stringify(l)
+}
+
+// ListLabels gets all labels for given project.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#list-labels
+func (s *LabelsService) ListLabels(pid interface{}) ([]*Label, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/labels", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var l []*Label
+	resp, err := s.client.Do(req, &l)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return l, resp, err
+}
+
+// CreateLabelOptions represents the available CreateLabel() options.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#create-a-new-label
+type CreateLabelOptions struct {
+	Name        *string `url:"name,omitempty" json:"name,omitempty"`
+	Color       *string `url:"color,omitempty" json:"color,omitempty"`
+	Description *string `url:"description,omitempty" json:"description,omitempty"`
+}
+
+// CreateLabel creates a new label for given repository with given name and
+// color.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#create-a-new-label
+func (s *LabelsService) CreateLabel(
+	pid interface{},
+	opt *CreateLabelOptions) (*Label, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/labels", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("POST", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	l := new(Label)
+	resp, err := s.client.Do(req, l)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return l, resp, err
+}
+
+// DeleteLabelOptions represents the available DeleteLabel() options.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#delete-a-label
+type DeleteLabelOptions struct {
+	Name *string `url:"name,omitempty" json:"name,omitempty"`
+}
+
+// DeleteLabel deletes a label given by its name.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#delete-a-label
+func (s *LabelsService) DeleteLabel(pid interface{}, opt *DeleteLabelOptions) (*Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, err
+	}
+	u := fmt.Sprintf("projects/%s/labels", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("DELETE", u, opt)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
+
+// UpdateLabelOptions represents the available UpdateLabel() options.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#delete-a-label
+type UpdateLabelOptions struct {
+	Name        *string `url:"name,omitempty" json:"name,omitempty"`
+	NewName     *string `url:"new_name,omitempty" json:"new_name,omitempty"`
+	Color       *string `url:"color,omitempty" json:"color,omitempty"`
+	Description *string `url:"description,omitempty" json:"description,omitempty"`
+}
+
+// UpdateLabel updates an existing label with new name or now color. At least
+// one parameter is required, to update the label.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#edit-an-existing-label
+func (s *LabelsService) UpdateLabel(
+	pid interface{},
+	opt *UpdateLabelOptions) (*Label, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/labels", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("PUT", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	l := new(Label)
+	resp, err := s.client.Do(req, l)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return l, resp, err
+}
diff --git a/vendor/github.com/xanzy/go-gitlab/merge_requests.go b/vendor/github.com/xanzy/go-gitlab/merge_requests.go
new file mode 100644
index 0000000000000000000000000000000000000000..a419f921e011669c7471a783413fa9ae29a0d647
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/merge_requests.go
@@ -0,0 +1,415 @@
+//
+// Copyright 2015, Sander van Harmelen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package gitlab
+
+import (
+	"fmt"
+	"net/url"
+	"time"
+)
+
+// MergeRequestsService handles communication with the merge requests related
+// methods of the GitLab API.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/merge_requests.html
+type MergeRequestsService struct {
+	client *Client
+}
+
+// MergeRequest represents a GitLab merge request.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/merge_requests.html
+type MergeRequest struct {
+	ID             int        `json:"id"`
+	IID            int        `json:"iid"`
+	ProjectID      int        `json:"project_id"`
+	Title          string     `json:"title"`
+	Description    string     `json:"description"`
+	WorkInProgress bool       `json:"work_in_progress"`
+	State          string     `json:"state"`
+	CreatedAt      *time.Time `json:"created_at"`
+	UpdatedAt      *time.Time `json:"updated_at"`
+	TargetBranch   string     `json:"target_branch"`
+	SourceBranch   string     `json:"source_branch"`
+	Upvotes        int        `json:"upvotes"`
+	Downvotes      int        `json:"downvotes"`
+	Author         struct {
+		Name      string `json:"name"`
+		Username  string `json:"username"`
+		ID        int    `json:"id"`
+		State     string `json:"state"`
+		AvatarURL string `json:"avatar_url"`
+	} `json:"author"`
+	Assignee struct {
+		Name      string `json:"name"`
+		Username  string `json:"username"`
+		ID        int    `json:"id"`
+		State     string `json:"state"`
+		AvatarURL string `json:"avatar_url"`
+	} `json:"assignee"`
+	SourceProjectID int      `json:"source_project_id"`
+	TargetProjectID int      `json:"target_project_id"`
+	Labels          []string `json:"labels"`
+	Milestone       struct {
+		ID          int        `json:"id"`
+		Iid         int        `json:"iid"`
+		ProjectID   int        `json:"project_id"`
+		Title       string     `json:"title"`
+		Description string     `json:"description"`
+		State       string     `json:"state"`
+		CreatedAt   *time.Time `json:"created_at"`
+		UpdatedAt   *time.Time `json:"updated_at"`
+		DueDate     string     `json:"due_date"`
+	} `json:"milestone"`
+	MergeWhenBuildSucceeds  bool   `json:"merge_when_build_succeeds"`
+	MergeStatus             string `json:"merge_status"`
+	Subscribed              bool   `json:"subscribed"`
+	UserNotesCount          int    `json:"user_notes_count"`
+	SouldRemoveSourceBranch bool   `json:"should_remove_source_branch"`
+	ForceRemoveSourceBranch bool   `json:"force_remove_source_branch"`
+	Changes                 []struct {
+		OldPath     string `json:"old_path"`
+		NewPath     string `json:"new_path"`
+		AMode       string `json:"a_mode"`
+		BMode       string `json:"b_mode"`
+		Diff        string `json:"diff"`
+		NewFile     bool   `json:"new_file"`
+		RenamedFile bool   `json:"renamed_file"`
+		DeletedFile bool   `json:"deleted_file"`
+	} `json:"changes"`
+}
+
+func (m MergeRequest) String() string {
+	return Stringify(m)
+}
+
+// ListMergeRequestsOptions represents the available ListMergeRequests()
+// options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/merge_requests.html#list-merge-requests
+type ListMergeRequestsOptions struct {
+	ListOptions
+	IID     *int    `url:"iid,omitempty" json:"iid,omitempty"`
+	State   *string `url:"state,omitempty" json:"state,omitempty"`
+	OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"`
+	Sort    *string `url:"sort,omitempty" json:"sort,omitempty"`
+}
+
+// ListMergeRequests gets all merge requests for this project. The state
+// parameter can be used to get only merge requests with a given state (opened,
+// closed, or merged) or all of them (all). The pagination parameters page and
+// per_page can be used to restrict the list of merge requests.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/merge_requests.html#list-merge-requests
+func (s *MergeRequestsService) ListMergeRequests(
+	pid interface{},
+	opt *ListMergeRequestsOptions) ([]*MergeRequest, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/merge_requests", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("GET", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var m []*MergeRequest
+	resp, err := s.client.Do(req, &m)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return m, resp, err
+}
+
+// GetMergeRequest shows information about a single merge request.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/merge_requests.html#get-single-mr
+func (s *MergeRequestsService) GetMergeRequest(
+	pid interface{},
+	mergeRequest int) (*MergeRequest, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/merge_request/%d", url.QueryEscape(project), mergeRequest)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	m := new(MergeRequest)
+	resp, err := s.client.Do(req, m)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return m, resp, err
+}
+
+// GetMergeRequestChanges shows information about the merge request including
+// its files and changes.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/merge_requests.html#get-single-mr-changes
+func (s *MergeRequestsService) GetMergeRequestChanges(
+	pid interface{},
+	mergeRequest int) (*MergeRequest, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/merge_request/%d/changes", url.QueryEscape(project), mergeRequest)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	m := new(MergeRequest)
+	resp, err := s.client.Do(req, m)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return m, resp, err
+}
+
+// CreateMergeRequestOptions represents the available CreateMergeRequest()
+// options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/merge_requests.html#create-mr
+type CreateMergeRequestOptions struct {
+	Title           *string `url:"title,omitempty" json:"title,omitempty"`
+	Description     *string `url:"description,omitempty" json:"description,omitempty"`
+	SourceBranch    *string `url:"source_branch,omitemtpy" json:"source_branch,omitemtpy"`
+	TargetBranch    *string `url:"target_branch,omitemtpy" json:"target_branch,omitemtpy"`
+	AssigneeID      *int    `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
+	TargetProjectID *int    `url:"target_project_id,omitempty" json:"target_project_id,omitempty"`
+}
+
+// CreateMergeRequest creates a new merge request.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/merge_requests.html#create-mr
+func (s *MergeRequestsService) CreateMergeRequest(
+	pid interface{},
+	opt *CreateMergeRequestOptions) (*MergeRequest, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/merge_requests", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("POST", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	m := new(MergeRequest)
+	resp, err := s.client.Do(req, m)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return m, resp, err
+}
+
+// UpdateMergeRequestOptions represents the available UpdateMergeRequest()
+// options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/merge_requests.html#update-mr
+type UpdateMergeRequestOptions struct {
+	Title        *string `url:"title,omitempty" json:"title,omitempty"`
+	Description  *string `url:"description,omitempty" json:"description,omitempty"`
+	TargetBranch *string `url:"target_branch,omitemtpy" json:"target_branch,omitemtpy"`
+	AssigneeID   *int    `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
+	StateEvent   *string `url:"state_event,omitempty" json:"state_event,omitempty"`
+}
+
+// UpdateMergeRequest updates an existing project milestone.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/merge_requests.html#update-mr
+func (s *MergeRequestsService) UpdateMergeRequest(
+	pid interface{},
+	mergeRequest int,
+	opt *UpdateMergeRequestOptions) (*MergeRequest, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/merge_request/%d", url.QueryEscape(project), mergeRequest)
+
+	req, err := s.client.NewRequest("PUT", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	m := new(MergeRequest)
+	resp, err := s.client.Do(req, m)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return m, resp, err
+}
+
+// AcceptMergeRequestOptions represents the available AcceptMergeRequest()
+// options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/merge_requests.html#accept-mr
+type AcceptMergeRequestOptions struct {
+	MergeCommitMessage       *string `url:"merge_commit_message,omitempty" json:"merge_commit_message,omitempty"`
+	ShouldRemoveSourceBranch *bool   `url:"should_remove_source_branch,omitempty" json:"should_remove_source_branch,omitempty"`
+	MergeWhenBuildSucceeds   *bool   `url:"merge_when_build_succeeds,omitempty" json:"merge_when_build_succeeds,omitempty"`
+	Sha                      *string `url:"sha,omitempty" json:"sha,omitempty"`
+}
+
+// AcceptMergeRequest merges changes submitted with MR using this API. If merge
+// success you get 200 OK. If it has some conflicts and can not be merged - you
+// get 405 and error message 'Branch cannot be merged'. If merge request is
+// already merged or closed - you get 405 and error message 'Method Not Allowed'
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/merge_requests.html#accept-mr
+func (s *MergeRequestsService) AcceptMergeRequest(
+	pid interface{},
+	mergeRequest int,
+	opt *AcceptMergeRequestOptions) (*MergeRequest, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/merge_request/%d/merge", url.QueryEscape(project), mergeRequest)
+
+	req, err := s.client.NewRequest("PUT", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	m := new(MergeRequest)
+	resp, err := s.client.Do(req, m)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return m, resp, err
+}
+
+// MergeRequestComment represents a GitLab merge request comment.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/merge_requests.html
+type MergeRequestComment struct {
+	Note   string `json:"note"`
+	Author struct {
+		ID        int        `json:"id"`
+		Username  string     `json:"username"`
+		Email     string     `json:"email"`
+		Name      string     `json:"name"`
+		State     string     `json:"state"`
+		CreatedAt *time.Time `json:"created_at"`
+	} `json:"author"`
+}
+
+func (m MergeRequestComment) String() string {
+	return Stringify(m)
+}
+
+// GetMergeRequestCommentsOptions represents the available GetMergeRequestComments()
+// options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/merge_requests.html#get-the-comments-on-a-mr
+type GetMergeRequestCommentsOptions struct {
+	ListOptions
+}
+
+// GetMergeRequestComments gets all the comments associated with a merge
+// request.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/merge_requests.html#get-the-comments-on-a-mr
+func (s *MergeRequestsService) GetMergeRequestComments(
+	pid interface{},
+	mergeRequest int,
+	opt *GetMergeRequestCommentsOptions) ([]*MergeRequestComment, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/merge_request/%d/comments", url.QueryEscape(project), mergeRequest)
+
+	req, err := s.client.NewRequest("GET", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var c []*MergeRequestComment
+	resp, err := s.client.Do(req, &c)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return c, resp, err
+}
+
+// PostMergeRequestCommentOptions represents the available
+// PostMergeRequestComment() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/commits.html#post-comment-to-mr
+type PostMergeRequestCommentOptions struct {
+	Note *string `url:"note,omitempty" json:"note,omitempty"`
+}
+
+// PostMergeRequestComment dds a comment to a merge request.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/commits.html#post-comment-to-mr
+func (s *MergeRequestsService) PostMergeRequestComment(
+	pid interface{},
+	mergeRequest int,
+	opt *PostMergeRequestCommentOptions) (*MergeRequestComment, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/merge_request/%d/comments", url.QueryEscape(project), mergeRequest)
+
+	req, err := s.client.NewRequest("POST", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	c := new(MergeRequestComment)
+	resp, err := s.client.Do(req, c)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return c, resp, err
+}
diff --git a/vendor/github.com/xanzy/go-gitlab/milestones.go b/vendor/github.com/xanzy/go-gitlab/milestones.go
new file mode 100644
index 0000000000000000000000000000000000000000..e570ca5c0974619b55e49adcde766213e04c1e2b
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/milestones.go
@@ -0,0 +1,228 @@
+//
+// Copyright 2015, Sander van Harmelen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package gitlab
+
+import (
+	"fmt"
+	"net/url"
+	"time"
+)
+
+// MilestonesService handles communication with the milestone related methods
+// of the GitLab API.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/milestones.html
+type MilestonesService struct {
+	client *Client
+}
+
+// Milestone represents a GitLab milestone.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/milestones.html
+type Milestone struct {
+	ID          int        `json:"id"`
+	Iid         int        `json:"iid"`
+	ProjectID   int        `json:"project_id"`
+	Title       string     `json:"title"`
+	Description string     `json:"description"`
+	StartDate   string     `json:"start_date"`
+	DueDate     string     `json:"due_date"`
+	State       string     `json:"state"`
+	UpdatedAt   *time.Time `json:"updated_at"`
+	CreatedAt   *time.Time `json:"created_at"`
+}
+
+func (m Milestone) String() string {
+	return Stringify(m)
+}
+
+// ListMilestonesOptions represents the available ListMilestones() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/milestones.html#list-project-milestones
+type ListMilestonesOptions struct {
+	ListOptions
+	IID *int `url:"iid,omitempty" json:"iid,omitempty"`
+}
+
+// ListMilestones returns a list of project milestones.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/milestones.html#list-project-milestones
+func (s *MilestonesService) ListMilestones(
+	pid interface{},
+	opt *ListMilestonesOptions) ([]*Milestone, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/milestones", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("GET", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var m []*Milestone
+	resp, err := s.client.Do(req, &m)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return m, resp, err
+}
+
+// GetMilestone gets a single project milestone.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/milestones.html#get-single-milestone
+func (s *MilestonesService) GetMilestone(
+	pid interface{},
+	milestone int) (*Milestone, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/milestones/%d", url.QueryEscape(project), milestone)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	m := new(Milestone)
+	resp, err := s.client.Do(req, m)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return m, resp, err
+}
+
+// CreateMilestoneOptions represents the available CreateMilestone() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/milestones.html#create-new-milestone
+type CreateMilestoneOptions struct {
+	Title       *string `url:"title,omitempty" json:"title,omitempty"`
+	Description *string `url:"description,omitempty" json:"description,omitempty"`
+	StartDate   *string `url:"start_date,omitempty" json:"start_date,omitempty"`
+	DueDate     *string `url:"due_date,omitempty" json:"due_date,omitempty"`
+}
+
+// CreateMilestone creates a new project milestone.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/milestones.html#create-new-milestone
+func (s *MilestonesService) CreateMilestone(
+	pid interface{},
+	opt *CreateMilestoneOptions) (*Milestone, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/milestones", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("POST", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	m := new(Milestone)
+	resp, err := s.client.Do(req, m)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return m, resp, err
+}
+
+// UpdateMilestoneOptions represents the available UpdateMilestone() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/milestones.html#edit-milestone
+type UpdateMilestoneOptions struct {
+	Title       *string `url:"title,omitempty" json:"title,omitempty"`
+	Description *string `url:"description,omitempty" json:"description,omitempty"`
+	StartDate   *string `url:"start_date,omitempty" json:"start_date,omitempty"`
+	DueDate     *string `url:"due_date,omitempty" json:"due_date,omitempty"`
+	StateEvent  *string `url:"state_event,omitempty" json:"state_event,omitempty"`
+}
+
+// UpdateMilestone updates an existing project milestone.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/milestones.html#edit-milestone
+func (s *MilestonesService) UpdateMilestone(
+	pid interface{},
+	milestone int,
+	opt *UpdateMilestoneOptions) (*Milestone, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/milestones/%d", url.QueryEscape(project), milestone)
+
+	req, err := s.client.NewRequest("PUT", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	m := new(Milestone)
+	resp, err := s.client.Do(req, m)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return m, resp, err
+}
+
+// GetMilestoneIssuesOptions represents the available GetMilestoneIssues() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/milestones.html#get-all-issues-assigned-to-a-single-milestone
+type GetMilestoneIssuesOptions struct {
+	ListOptions
+}
+
+// GetMilestoneIssues gets all issues assigned to a single project milestone.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/milestones.html#get-all-issues-assigned-to-a-single-milestone
+func (s *MilestonesService) GetMilestoneIssues(
+	pid interface{},
+	milestone int,
+	opt *GetMilestoneIssuesOptions) ([]*Issue, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/milestones/%d/issues", url.QueryEscape(project), milestone)
+
+	req, err := s.client.NewRequest("GET", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var i []*Issue
+	resp, err := s.client.Do(req, &i)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return i, resp, err
+}
diff --git a/vendor/github.com/xanzy/go-gitlab/namespaces.go b/vendor/github.com/xanzy/go-gitlab/namespaces.go
new file mode 100644
index 0000000000000000000000000000000000000000..b849cbf1b6fe51b5326e437fe44edf6dafc4d744
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/namespaces.go
@@ -0,0 +1,89 @@
+//
+// Copyright 2015, Sander van Harmelen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package gitlab
+
+// NamespacesService handles communication with the namespace related methods
+// of the GitLab API.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/namespaces.html
+type NamespacesService struct {
+	client *Client
+}
+
+// Namespace represents a GitLab namespace.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/namespaces.html
+type Namespace struct {
+	ID   int    `json:"id"`
+	Path string `json:"path"`
+	Kind string `json:"kind"`
+}
+
+func (n Namespace) String() string {
+	return Stringify(n)
+}
+
+// ListNamespacesOptions represents the available ListNamespaces() options.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/namespaces.html#list-namespaces
+type ListNamespacesOptions struct {
+	ListOptions
+	Search *string `url:"search,omitempty" json:"search,omitempty"`
+}
+
+// ListNamespaces gets a list of projects accessible by the authenticated user.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/namespaces.html#list-namespaces
+func (s *NamespacesService) ListNamespaces(opt *ListNamespacesOptions) ([]*Namespace, *Response, error) {
+	req, err := s.client.NewRequest("GET", "namespaces", opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var n []*Namespace
+	resp, err := s.client.Do(req, &n)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return n, resp, err
+}
+
+// SearchNamespace gets all namespaces that match your string in their name
+// or path.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/namespaces.html#search-for-namespace
+func (s *NamespacesService) SearchNamespace(query string) ([]*Namespace, *Response, error) {
+	var q struct {
+		Search string `url:"search,omitempty" json:"search,omitempty"`
+	}
+	q.Search = query
+
+	req, err := s.client.NewRequest("GET", "namespaces", &q)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var n []*Namespace
+	resp, err := s.client.Do(req, &n)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return n, resp, err
+}
diff --git a/vendor/github.com/xanzy/go-gitlab/notes.go b/vendor/github.com/xanzy/go-gitlab/notes.go
new file mode 100644
index 0000000000000000000000000000000000000000..04e8a64f9d455710c7adfcc57f2e55c38eb76153
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/notes.go
@@ -0,0 +1,454 @@
+//
+// Copyright 2015, Sander van Harmelen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package gitlab
+
+import (
+	"fmt"
+	"net/url"
+	"time"
+)
+
+// NotesService handles communication with the notes related methods
+// of the GitLab API.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/notes.html
+type NotesService struct {
+	client *Client
+}
+
+// Note represents a GitLab note.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/notes.html
+type Note struct {
+	ID         int    `json:"id"`
+	Body       string `json:"body"`
+	Attachment string `json:"attachment"`
+	Title      string `json:"title"`
+	FileName   string `json:"file_name"`
+	Author     struct {
+		ID        int        `json:"id"`
+		Username  string     `json:"username"`
+		Email     string     `json:"email"`
+		Name      string     `json:"name"`
+		State     string     `json:"state"`
+		CreatedAt *time.Time `json:"created_at"`
+	} `json:"author"`
+	ExpiresAt *time.Time `json:"expires_at"`
+	UpdatedAt *time.Time `json:"updated_at"`
+	CreatedAt *time.Time `json:"created_at"`
+}
+
+func (n Note) String() string {
+	return Stringify(n)
+}
+
+// ListIssueNotesOptions represents the available ListIssueNotes() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/notes.html#list-project-issue-notes
+type ListIssueNotesOptions struct {
+	ListOptions
+}
+
+// ListIssueNotes gets a list of all notes for a single issue.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/notes.html#list-project-issue-notes
+func (s *NotesService) ListIssueNotes(
+	pid interface{},
+	issue int,
+	opt *ListIssueNotesOptions) ([]*Note, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/issues/%d/notes", url.QueryEscape(project), issue)
+
+	req, err := s.client.NewRequest("GET", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var n []*Note
+	resp, err := s.client.Do(req, &n)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return n, resp, err
+}
+
+// GetIssueNote returns a single note for a specific project issue.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/notes.html#get-single-issue-note
+func (s *NotesService) GetIssueNote(
+	pid interface{},
+	issue int,
+	note int) (*Note, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/issues/%d/notes/%d", url.QueryEscape(project), issue, note)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	n := new(Note)
+	resp, err := s.client.Do(req, n)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return n, resp, err
+}
+
+// CreateIssueNoteOptions represents the available CreateIssueNote()
+// options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/notes.html#create-new-issue-note
+type CreateIssueNoteOptions struct {
+	Body *string `url:"body,omitempty" json:"body,omitempty"`
+}
+
+// CreateIssueNote creates a new note to a single project issue.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/notes.html#create-new-issue-note
+func (s *NotesService) CreateIssueNote(
+	pid interface{},
+	issue int,
+	opt *CreateIssueNoteOptions) (*Note, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/issues/%d/notes", url.QueryEscape(project), issue)
+
+	req, err := s.client.NewRequest("POST", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	n := new(Note)
+	resp, err := s.client.Do(req, n)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return n, resp, err
+}
+
+// UpdateIssueNoteOptions represents the available UpdateIssueNote()
+// options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/notes.html#modify-existing-issue-note
+type UpdateIssueNoteOptions struct {
+	Body *string `url:"body,omitempty" json:"body,omitempty"`
+}
+
+// UpdateIssueNote modifies existing note of an issue.
+//
+// https://docs.gitlab.com/ce/api/notes.html#modify-existing-issue-note
+func (s *NotesService) UpdateIssueNote(
+	pid interface{},
+	issue int,
+	note int,
+	opt *UpdateIssueNoteOptions) (*Note, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/issues/%d/notes/%d", url.QueryEscape(project), issue, note)
+
+	req, err := s.client.NewRequest("PUT", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	n := new(Note)
+	resp, err := s.client.Do(req, n)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return n, resp, err
+}
+
+// ListSnippetNotes gets a list of all notes for a single snippet. Snippet
+// notes are comments users can post to a snippet.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/notes.html#list-all-snippet-notes
+func (s *NotesService) ListSnippetNotes(pid interface{}, snippet int) ([]*Note, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/snippets/%d/notes", url.QueryEscape(project), snippet)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var n []*Note
+	resp, err := s.client.Do(req, &n)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return n, resp, err
+}
+
+// GetSnippetNote returns a single note for a given snippet.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/notes.html#get-single-snippet-note
+func (s *NotesService) GetSnippetNote(
+	pid interface{},
+	snippet int,
+	note int) (*Note, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/snippets/%d/notes/%d", url.QueryEscape(project), snippet, note)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	n := new(Note)
+	resp, err := s.client.Do(req, n)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return n, resp, err
+}
+
+// CreateSnippetNoteOptions represents the available CreateSnippetNote()
+// options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/notes.html#create-new-snippet-note
+type CreateSnippetNoteOptions struct {
+	Body *string `url:"body,omitempty" json:"body,omitempty"`
+}
+
+// CreateSnippetNote creates a new note for a single snippet. Snippet notes are
+// comments users can post to a snippet.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/notes.html#create-new-snippet-note
+func (s *NotesService) CreateSnippetNote(
+	pid interface{},
+	snippet int,
+	opt *CreateSnippetNoteOptions) (*Note, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/snippets/%d/notes", url.QueryEscape(project), snippet)
+
+	req, err := s.client.NewRequest("POST", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	n := new(Note)
+	resp, err := s.client.Do(req, n)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return n, resp, err
+}
+
+// UpdateSnippetNoteOptions represents the available UpdateSnippetNote()
+// options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/notes.html#modify-existing-snippet-note
+type UpdateSnippetNoteOptions struct {
+	Body *string `url:"body,omitempty" json:"body,omitempty"`
+}
+
+// UpdateSnippetNote modifies existing note of a snippet.
+//
+// https://docs.gitlab.com/ce/api/notes.html#modify-existing-snippet-note
+func (s *NotesService) UpdateSnippetNote(
+	pid interface{},
+	snippet int,
+	note int,
+	opt *UpdateSnippetNoteOptions) (*Note, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/snippets/%d/notes/%d", url.QueryEscape(project), snippet, note)
+
+	req, err := s.client.NewRequest("PUT", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	n := new(Note)
+	resp, err := s.client.Do(req, n)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return n, resp, err
+}
+
+// ListMergeRequestNotes gets a list of all notes for a single merge request.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/notes.html#list-all-merge-request-notes
+func (s *NotesService) ListMergeRequestNotes(
+	pid interface{},
+	mergeRequest int) ([]*Note, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/merge_requests/%d/notes", url.QueryEscape(project), mergeRequest)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var n []*Note
+	resp, err := s.client.Do(req, &n)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return n, resp, err
+}
+
+// GetMergeRequestNote returns a single note for a given merge request.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/notes.html#get-single-merge-request-note
+func (s *NotesService) GetMergeRequestNote(
+	pid interface{},
+	mergeRequest int,
+	note int) (*Note, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/merge_requests/%d/notes/%d", url.QueryEscape(project), mergeRequest, note)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	n := new(Note)
+	resp, err := s.client.Do(req, n)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return n, resp, err
+}
+
+// CreateMergeRequestNoteOptions represents the available
+// CreateMergeRequestNote() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/notes.html#create-new-merge-request-note
+type CreateMergeRequestNoteOptions struct {
+	Body *string `url:"body,omitempty" json:"body,omitempty"`
+}
+
+// CreateMergeRequestNote creates a new note for a single merge request.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/notes.html#create-new-merge-request-note
+func (s *NotesService) CreateMergeRequestNote(
+	pid interface{},
+	mergeRequest int,
+	opt *CreateMergeRequestNoteOptions) (*Note, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/merge_requests/%d/notes", url.QueryEscape(project), mergeRequest)
+
+	req, err := s.client.NewRequest("POST", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	n := new(Note)
+	resp, err := s.client.Do(req, n)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return n, resp, err
+}
+
+// UpdateMergeRequestNoteOptions represents the available
+// UpdateMergeRequestNote() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/notes.html#modify-existing-merge-request-note
+type UpdateMergeRequestNoteOptions struct {
+	Body *string `url:"body,omitempty" json:"body,omitempty"`
+}
+
+// UpdateMergeRequestNote modifies existing note of a merge request.
+//
+// https://docs.gitlab.com/ce/api/notes.html#modify-existing-merge-request-note
+func (s *NotesService) UpdateMergeRequestNote(
+	pid interface{},
+	mergeRequest int,
+	note int,
+	opt *UpdateMergeRequestNoteOptions) (*Note, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf(
+		"projects/%s/merge_requests/%d/notes/%d", url.QueryEscape(project), mergeRequest, note)
+
+	req, err := s.client.NewRequest("PUT", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	n := new(Note)
+	resp, err := s.client.Do(req, n)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return n, resp, err
+}
diff --git a/vendor/github.com/xanzy/go-gitlab/project_snippets.go b/vendor/github.com/xanzy/go-gitlab/project_snippets.go
new file mode 100644
index 0000000000000000000000000000000000000000..6716b5c8dd1d3e16e63f700b4683dec22a3c6fa7
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/project_snippets.go
@@ -0,0 +1,243 @@
+//
+// Copyright 2015, Sander van Harmelen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package gitlab
+
+import (
+	"bytes"
+	"fmt"
+	"net/url"
+	"time"
+)
+
+// ProjectSnippetsService handles communication with the project snippets
+// related methods of the GitLab API.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/project_snippets.html
+type ProjectSnippetsService struct {
+	client *Client
+}
+
+// Snippet represents a GitLab project snippet.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/project_snippets.html
+type Snippet struct {
+	ID       int    `json:"id"`
+	Title    string `json:"title"`
+	FileName string `json:"file_name"`
+	Author   struct {
+		ID        int        `json:"id"`
+		Username  string     `json:"username"`
+		Email     string     `json:"email"`
+		Name      string     `json:"name"`
+		State     string     `json:"state"`
+		CreatedAt *time.Time `json:"created_at"`
+	} `json:"author"`
+	ExpiresAt *time.Time `json:"expires_at"`
+	UpdatedAt *time.Time `json:"updated_at"`
+	CreatedAt *time.Time `json:"created_at"`
+}
+
+func (s Snippet) String() string {
+	return Stringify(s)
+}
+
+// ListSnippetsOptions represents the available ListSnippets() options.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/project_snippets.html#list-snippets
+type ListSnippetsOptions struct {
+	ListOptions
+}
+
+// ListSnippets gets a list of project snippets.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/project_snippets.html#list-snippets
+func (s *ProjectSnippetsService) ListSnippets(
+	pid interface{},
+	opt *ListSnippetsOptions) ([]*Snippet, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/snippets", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("GET", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var ps []*Snippet
+	resp, err := s.client.Do(req, &ps)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return ps, resp, err
+}
+
+// GetSnippet gets a single project snippet
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/project_snippets.html#single-snippet
+func (s *ProjectSnippetsService) GetSnippet(
+	pid interface{},
+	snippet int) (*Snippet, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/snippets/%d", url.QueryEscape(project), snippet)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	ps := new(Snippet)
+	resp, err := s.client.Do(req, ps)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return ps, resp, err
+}
+
+// CreateSnippetOptions represents the available CreateSnippet() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/project_snippets.html#create-new-snippet
+type CreateSnippetOptions struct {
+	Title           *string               `url:"title,omitempty" json:"title,omitempty"`
+	FileName        *string               `url:"file_name,omitempty" json:"file_name,omitempty"`
+	Code            *string               `url:"code,omitempty" json:"code,omitempty"`
+	VisibilityLevel *VisibilityLevelValue `url:"visibility_level,omitempty" json:"visibility_level,omitempty"`
+}
+
+// CreateSnippet creates a new project snippet. The user must have permission
+// to create new snippets.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/project_snippets.html#create-new-snippet
+func (s *ProjectSnippetsService) CreateSnippet(
+	pid interface{},
+	opt *CreateSnippetOptions) (*Snippet, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/snippets", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("POST", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	ps := new(Snippet)
+	resp, err := s.client.Do(req, ps)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return ps, resp, err
+}
+
+// UpdateSnippetOptions represents the available UpdateSnippet() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/project_snippets.html#update-snippet
+type UpdateSnippetOptions struct {
+	Title           *string               `url:"title,omitempty" json:"title,omitempty"`
+	FileName        *string               `url:"file_name,omitempty" json:"file_name,omitempty"`
+	Code            *string               `url:"code,omitempty" json:"code,omitempty"`
+	VisibilityLevel *VisibilityLevelValue `url:"visibility_level,omitempty" json:"visibility_level,omitempty"`
+}
+
+// UpdateSnippet updates an existing project snippet. The user must have
+// permission to change an existing snippet.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/project_snippets.html#update-snippet
+func (s *ProjectSnippetsService) UpdateSnippet(
+	pid interface{},
+	snippet int,
+	opt *UpdateSnippetOptions) (*Snippet, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/snippets/%d", url.QueryEscape(project), snippet)
+
+	req, err := s.client.NewRequest("PUT", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	ps := new(Snippet)
+	resp, err := s.client.Do(req, ps)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return ps, resp, err
+}
+
+// DeleteSnippet deletes an existing project snippet. This is an idempotent
+// function and deleting a non-existent snippet still returns a 200 OK status
+// code.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/project_snippets.html#delete-snippet
+func (s *ProjectSnippetsService) DeleteSnippet(pid interface{}, snippet int) (*Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, err
+	}
+	u := fmt.Sprintf("projects/%s/snippets/%d", url.QueryEscape(project), snippet)
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
+
+// SnippetContent returns the raw project snippet as plain text.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/project_snippets.html#snippet-content
+func (s *ProjectSnippetsService) SnippetContent(
+	pid interface{},
+	snippet int) ([]byte, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/snippets/%d/raw", url.QueryEscape(project), snippet)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var b bytes.Buffer
+	resp, err := s.client.Do(req, &b)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return b.Bytes(), resp, err
+}
diff --git a/vendor/github.com/xanzy/go-gitlab/projects.go b/vendor/github.com/xanzy/go-gitlab/projects.go
new file mode 100644
index 0000000000000000000000000000000000000000..c3dcc793f63881632bb8039938b4a5714e325967
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/projects.go
@@ -0,0 +1,994 @@
+//
+// Copyright 2015, Sander van Harmelen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package gitlab
+
+import (
+	"fmt"
+	"net/url"
+	"time"
+)
+
+// ProjectsService handles communication with the repositories related methods
+// of the GitLab API.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html
+type ProjectsService struct {
+	client *Client
+}
+
+// Project represents a GitLab project.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html
+type Project struct {
+	ID                                        int                  `json:"id"`
+	Description                               string               `json:"description"`
+	DefaultBranch                             string               `json:"default_branch"`
+	Public                                    bool                 `json:"public"`
+	VisibilityLevel                           VisibilityLevelValue `json:"visibility_level"`
+	SSHURLToRepo                              string               `json:"ssh_url_to_repo"`
+	HTTPURLToRepo                             string               `json:"http_url_to_repo"`
+	WebURL                                    string               `json:"web_url"`
+	TagList                                   []string             `json:"tag_list"`
+	Owner                                     *User                `json:"owner"`
+	Name                                      string               `json:"name"`
+	NameWithNamespace                         string               `json:"name_with_namespace"`
+	Path                                      string               `json:"path"`
+	PathWithNamespace                         string               `json:"path_with_namespace"`
+	IssuesEnabled                             bool                 `json:"issues_enabled"`
+	OpenIssuesCount                           int                  `json:"open_issues_count"`
+	MergeRequestsEnabled                      bool                 `json:"merge_requests_enabled"`
+	ApprovalsBeforeMerge                      int                  `json:"approvals_before_merge"`
+	BuildsEnabled                             bool                 `json:"builds_enabled"`
+	WikiEnabled                               bool                 `json:"wiki_enabled"`
+	SnippetsEnabled                           bool                 `json:"snippets_enabled"`
+	ContainerRegistryEnabled                  bool                 `json:"container_registry_enabled"`
+	CreatedAt                                 *time.Time           `json:"created_at,omitempty"`
+	LastActivityAt                            *time.Time           `json:"last_activity_at,omitempty"`
+	CreatorID                                 int                  `json:"creator_id"`
+	Namespace                                 *ProjectNamespace    `json:"namespace"`
+	Permissions                               *Permissions         `json:"permissions"`
+	Archived                                  bool                 `json:"archived"`
+	AvatarURL                                 string               `json:"avatar_url"`
+	SharedRunnersEnabled                      bool                 `json:"shared_runners_enabled"`
+	ForksCount                                int                  `json:"forks_count"`
+	StarCount                                 int                  `json:"star_count"`
+	RunnersToken                              string               `json:"runners_token"`
+	PublicBuilds                              bool                 `json:"public_builds"`
+	OnlyAllowMergeIfBuildSucceeds             bool                 `json:"only_allow_merge_if_build_succeeds"`
+	OnlyAllowMergeIfAllDiscussionsAreResolved bool                 `json:"only_allow_merge_if_all_discussions_are_resolved"`
+	LFSEnabled                                bool                 `json:"lfs_enabled"`
+	RequestAccessEnabled                      bool                 `json:"request_access_enabled"`
+	SharedWithGroups                          []struct {
+		GroupID          int    `json:"group_id"`
+		GroupName        string `json:"group_name"`
+		GroupAccessLevel int    `json:"group_access_level"`
+	} `json:"shared_with_groups"`
+}
+
+// Repository represents a repository.
+type Repository struct {
+	Name              string `json:"name"`
+	Description       string `json:"description"`
+	WebURL            string `json:"web_url"`
+	AvatarURL         string `json:"avatar_url"`
+	GitSSHURL         string `json:"git_ssh_url"`
+	GitHTTPURL        string `json:"git_http_url"`
+	Namespace         string `json:"namespace"`
+	VisibilityLevel   int    `json:"visibility_level"`
+	PathWithNamespace string `json:"path_with_namespace"`
+	DefaultBranch     string `json:"default_branch"`
+	Homepage          string `json:"homepage"`
+	URL               string `json:"url"`
+	SSHURL            string `json:"ssh_url"`
+	HTTPURL           string `json:"http_url"`
+}
+
+// ProjectNamespace represents a project namespace.
+type ProjectNamespace struct {
+	CreatedAt   *time.Time `json:"created_at"`
+	Description string     `json:"description"`
+	ID          int        `json:"id"`
+	Name        string     `json:"name"`
+	OwnerID     int        `json:"owner_id"`
+	Path        string     `json:"path"`
+	UpdatedAt   *time.Time `json:"updated_at"`
+}
+
+// Permissions represents premissions.
+type Permissions struct {
+	ProjectAccess *ProjectAccess `json:"project_access"`
+	GroupAccess   *GroupAccess   `json:"group_access"`
+}
+
+// ProjectAccess represents project access.
+type ProjectAccess struct {
+	AccessLevel       AccessLevelValue       `json:"access_level"`
+	NotificationLevel NotificationLevelValue `json:"notification_level"`
+}
+
+// GroupAccess represents group access.
+type GroupAccess struct {
+	AccessLevel       AccessLevelValue       `json:"access_level"`
+	NotificationLevel NotificationLevelValue `json:"notification_level"`
+}
+
+func (s Project) String() string {
+	return Stringify(s)
+}
+
+// ListProjectsOptions represents the available ListProjects() options.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#list-projects
+type ListProjectsOptions struct {
+	ListOptions
+	Archived   *bool   `url:"archived,omitempty" json:"archived,omitempty"`
+	OrderBy    *string `url:"order_by,omitempty" json:"order_by,omitempty"`
+	Sort       *string `url:"sort,omitempty" json:"sort,omitempty"`
+	Search     *string `url:"search,omitempty" json:"search,omitempty"`
+	Simple     *bool   `url:"simple,omitempty" json:"simple,omitempty"`
+	Visibility *string `url:"visibility,omitempty" json:"visibility,omitempty"`
+}
+
+// ListProjects gets a list of projects accessible by the authenticated user.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#list-projects
+func (s *ProjectsService) ListProjects(opt *ListProjectsOptions) ([]*Project, *Response, error) {
+	req, err := s.client.NewRequest("GET", "projects", opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var p []*Project
+	resp, err := s.client.Do(req, &p)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return p, resp, err
+}
+
+// ListOwnedProjects gets a list of projects which are owned by the
+// authenticated user.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#list-owned-projects
+func (s *ProjectsService) ListOwnedProjects(
+	opt *ListProjectsOptions) ([]*Project, *Response, error) {
+	req, err := s.client.NewRequest("GET", "projects/owned", opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var p []*Project
+	resp, err := s.client.Do(req, &p)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return p, resp, err
+}
+
+// ListStarredProjects gets a list of projects which are starred by the
+// authenticated user.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#list-starred-projects
+func (s *ProjectsService) ListStarredProjects(
+	opt *ListProjectsOptions) ([]*Project, *Response, error) {
+	req, err := s.client.NewRequest("GET", "projects/starred", opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var p []*Project
+	resp, err := s.client.Do(req, &p)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return p, resp, err
+}
+
+// ListAllProjects gets a list of all GitLab projects (admin only).
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#list-all-projects
+func (s *ProjectsService) ListAllProjects(opt *ListProjectsOptions) ([]*Project, *Response, error) {
+	req, err := s.client.NewRequest("GET", "projects/all", opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var p []*Project
+	resp, err := s.client.Do(req, &p)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return p, resp, err
+}
+
+// GetProject gets a specific project, identified by project ID or
+// NAMESPACE/PROJECT_NAME, which is owned by the authenticated user.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#get-single-project
+func (s *ProjectsService) GetProject(pid interface{}) (*Project, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	p := new(Project)
+	resp, err := s.client.Do(req, p)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return p, resp, err
+}
+
+// SearchProjectsOptions represents the available SearchProjects() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#search-for-projects-by-name
+type SearchProjectsOptions struct {
+	ListOptions
+	OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"`
+	Sort    *string `url:"sort,omitempty" json:"sort,omitempty"`
+}
+
+// SearchProjects searches for projects by name which are accessible to the
+// authenticated user.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#search-for-projects-by-name
+func (s *ProjectsService) SearchProjects(
+	query string,
+	opt *SearchProjectsOptions) ([]*Project, *Response, error) {
+	u := fmt.Sprintf("projects/search/%s", query)
+
+	req, err := s.client.NewRequest("GET", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var p []*Project
+	resp, err := s.client.Do(req, &p)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return p, resp, err
+}
+
+// ProjectEvent represents a GitLab project event.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#get-project-events
+type ProjectEvent struct {
+	Title          interface{} `json:"title"`
+	ProjectID      int         `json:"project_id"`
+	ActionName     string      `json:"action_name"`
+	TargetID       interface{} `json:"target_id"`
+	TargetType     interface{} `json:"target_type"`
+	AuthorID       int         `json:"author_id"`
+	AuthorUsername string      `json:"author_username"`
+	Data           struct {
+		Before            string      `json:"before"`
+		After             string      `json:"after"`
+		Ref               string      `json:"ref"`
+		UserID            int         `json:"user_id"`
+		UserName          string      `json:"user_name"`
+		Repository        *Repository `json:"repository"`
+		Commits           []*Commit   `json:"commits"`
+		TotalCommitsCount int         `json:"total_commits_count"`
+	} `json:"data"`
+	TargetTitle interface{} `json:"target_title"`
+}
+
+func (s ProjectEvent) String() string {
+	return Stringify(s)
+}
+
+// GetProjectEventsOptions represents the available GetProjectEvents() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#get-project-events
+type GetProjectEventsOptions struct {
+	ListOptions
+}
+
+// GetProjectEvents gets the events for the specified project. Sorted from
+// newest to latest.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#get-project-events
+func (s *ProjectsService) GetProjectEvents(
+	pid interface{},
+	opt *GetProjectEventsOptions) ([]*ProjectEvent, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/events", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("GET", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var p []*ProjectEvent
+	resp, err := s.client.Do(req, &p)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return p, resp, err
+}
+
+// CreateProjectOptions represents the available CreateProjects() options.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#create-project
+type CreateProjectOptions struct {
+	Name                          *string               `url:"name,omitempty" json:"name,omitempty"`
+	Path                          *string               `url:"path,omitempty" json:"path,omitempty"`
+	NamespaceID                   *int                  `url:"namespace_id,omitempty" json:"namespace_id,omitempty"`
+	Description                   *string               `url:"description,omitempty" json:"description,omitempty"`
+	IssuesEnabled                 *bool                 `url:"issues_enabled,omitempty" json:"issues_enabled,omitempty"`
+	MergeRequestsEnabled          *bool                 `url:"merge_requests_enabled,omitempty" json:"merge_requests_enabled,omitempty"`
+	BuildsEnabled                 *bool                 `url:"builds_enabled,omitempty" json:"builds_enabled,omitempty"`
+	WikiEnabled                   *bool                 `url:"wiki_enabled,omitempty" json:"wiki_enabled,omitempty"`
+	SnippetsEnabled               *bool                 `url:"snippets_enabled,omitempty" json:"snippets_enabled,omitempty"`
+	ContainerRegistryEnabled      *bool                 `url:"container_registry_enabled,omitempty" json:"container_registry_enabled,omitempty"`
+	SharedRunnersEnabled          *bool                 `url:"shared_runners_enabled,omitempty" json:"shared_runners_enabled,omitempty"`
+	Public                        *bool                 `url:"public,omitempty" json:"public,omitempty"`
+	VisibilityLevel               *VisibilityLevelValue `url:"visibility_level,omitempty" json:"visibility_level,omitempty"`
+	ImportURL                     *string               `url:"import_url,omitempty" json:"import_url,omitempty"`
+	PublicBuilds                  *bool                 `url:"public_builds,omitempty" json:"public_builds,omitempty"`
+	OnlyAllowMergeIfBuildSucceeds *bool                 `url:"only_allow_merge_if_build_succeeds,omitempty" json:"only_allow_merge_if_build_succeeds,omitempty"`
+	LFSEnabled                    *bool                 `url:"lfs_enabled,omitempty" json:"lfs_enabled,omitempty"`
+	RequestAccessEnabled          *bool                 `url:"request_access_enabled,omitempty" json:"request_access_enabled,omitempty"`
+}
+
+// CreateProject creates a new project owned by the authenticated user.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#create-project
+func (s *ProjectsService) CreateProject(
+	opt *CreateProjectOptions) (*Project, *Response, error) {
+	req, err := s.client.NewRequest("POST", "projects", opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	p := new(Project)
+	resp, err := s.client.Do(req, p)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return p, resp, err
+}
+
+// CreateProjectForUserOptions represents the available CreateProjectForUser()
+// options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#create-project-for-user
+type CreateProjectForUserOptions struct {
+	Name                 *string               `url:"name,omitempty" json:"name,omitempty"`
+	Description          *string               `url:"description,omitempty" json:"description,omitempty"`
+	DefaultBranch        *string               `url:"default_branch,omitempty" json:"default_branch,omitempty"`
+	IssuesEnabled        *bool                 `url:"issues_enabled,omitempty" json:"issues_enabled,omitempty"`
+	MergeRequestsEnabled *bool                 `url:"merge_requests_enabled,omitempty" json:"merge_requests_enabled,omitempty"`
+	WikiEnabled          *bool                 `url:"wiki_enabled,omitempty" json:"wiki_enabled,omitempty"`
+	SnippetsEnabled      *bool                 `url:"snippets_enabled,omitempty" json:"snippets_enabled,omitempty"`
+	Public               *bool                 `url:"public,omitempty" json:"public,omitempty"`
+	VisibilityLevel      *VisibilityLevelValue `url:"visibility_level,omitempty" json:"visibility_level,omitempty"`
+	ImportURL            *string               `url:"import_url,omitempty" json:"import_url,omitempty"`
+}
+
+// CreateProjectForUser creates a new project owned by the specified user.
+// Available only for admins.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#create-project-for-user
+func (s *ProjectsService) CreateProjectForUser(
+	user int,
+	opt *CreateProjectForUserOptions) (*Project, *Response, error) {
+	u := fmt.Sprintf("projects/user/%d", user)
+
+	req, err := s.client.NewRequest("POST", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	p := new(Project)
+	resp, err := s.client.Do(req, p)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return p, resp, err
+}
+
+// EditProjectOptions represents the available EditProject() options.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#edit-project
+type EditProjectOptions struct {
+	Name                                      *string               `url:"name,omitempty" json:"name,omitempty"`
+	Path                                      *string               `url:"path,omitempty" json:"path,omitempty"`
+	Description                               *string               `url:"description,omitempty" json:"description,omitempty"`
+	DefaultBranch                             *string               `url:"default_branch,omitempty" json:"default_branch,omitempty"`
+	IssuesEnabled                             *bool                 `url:"issues_enabled,omitempty" json:"issues_enabled,omitempty"`
+	MergeRequestsEnabled                      *bool                 `url:"merge_requests_enabled,omitempty" json:"merge_requests_enabled,omitempty"`
+	ApprovalsBeforeMerge                      *int                  `url:"approvals_before_merge,omitempty" json:"approvals_before_merge,omitempty"`
+	BuildsEnabled                             *bool                 `url:"builds_enabled,omitempty" json:"builds_enabled,omitempty"`
+	WikiEnabled                               *bool                 `url:"wiki_enabled,omitempty" json:"wiki_enabled,omitempty"`
+	SnippetsEnabled                           *bool                 `url:"snippets_enabled,omitempty" json:"snippets_enabled,omitempty"`
+	ContainerRegistryEnabled                  *bool                 `url:"container_registry_enabled,omitempty" json:"container_registry_enabled,omitempty"`
+	SharedRunnersEnabled                      *bool                 `url:"shared_runners_enabled,omitempty" json:"shared_runners_enabled,omitempty"`
+	Public                                    *bool                 `url:"public,omitempty" json:"public,omitempty"`
+	VisibilityLevel                           *VisibilityLevelValue `url:"visibility_level,omitempty" json:"visibility_level,omitempty"`
+	ImportURL                                 *bool                 `url:"import_url,omitempty" json:"import_url,omitempty"`
+	PublicBuilds                              *bool                 `url:"public_builds,omitempty" json:"public_builds,omitempty"`
+	OnlyAllowMergeIfBuildSucceeds             *bool                 `url:"only_allow_merge_if_build_succeeds,omitempty" json:"only_allow_merge_if_build_succeeds,omitempty"`
+	OnlyAllowMergeIfAllDiscussionsAreResolved *bool                 `url:"only_allow_merge_if_all_discussions_are_resolved,omitempty" json:"only_allow_merge_if_all_discussions_are_resolved,omitempty"`
+	LFSEnabled                                *bool                 `url:"lfs_enabled,omitempty" json:"lfs_enabled,omitempty"`
+	RequestAccessEnabled                      *bool                 `url:"request_access_enabled,omitempty" json:"request_access_enabled,omitempty"`
+}
+
+// EditProject updates an existing project.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#edit-project
+func (s *ProjectsService) EditProject(
+	pid interface{},
+	opt *EditProjectOptions) (*Project, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("PUT", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	p := new(Project)
+	resp, err := s.client.Do(req, p)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return p, resp, err
+}
+
+// ForkProject forks a project into the user namespace of the authenticated
+// user.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#fork-project
+func (s *ProjectsService) ForkProject(pid interface{}) (*Project, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/fork/%s", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("POST", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	p := new(Project)
+	resp, err := s.client.Do(req, p)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return p, resp, err
+}
+
+// DeleteProject removes a project including all associated resources
+// (issues, merge requests etc.)
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#remove-project
+func (s *ProjectsService) DeleteProject(pid interface{}) (*Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, err
+	}
+	u := fmt.Sprintf("projects/%s", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
+
+// ProjectMember represents a project member.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#list-project-team-members
+type ProjectMember struct {
+	ID          int              `json:"id"`
+	Username    string           `json:"username"`
+	Email       string           `json:"email"`
+	Name        string           `json:"name"`
+	State       string           `json:"state"`
+	CreatedAt   *time.Time       `json:"created_at"`
+	AccessLevel AccessLevelValue `json:"access_level"`
+}
+
+// ListProjectMembersOptions represents the available ListProjectMembers()
+// options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#list-project-team-members
+type ListProjectMembersOptions struct {
+	ListOptions
+	Query *string `url:"query,omitempty" json:"query,omitempty"`
+}
+
+// ListProjectMembers gets a list of a project's team members.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#list-project-team-members
+func (s *ProjectsService) ListProjectMembers(
+	pid interface{},
+	opt *ListProjectMembersOptions) ([]*ProjectMember, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/members", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("GET", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var pm []*ProjectMember
+	resp, err := s.client.Do(req, &pm)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return pm, resp, err
+}
+
+// GetProjectMember gets a project team member.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#get-project-team-member
+func (s *ProjectsService) GetProjectMember(
+	pid interface{},
+	user int) (*ProjectMember, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/members/%d", url.QueryEscape(project), user)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	pm := new(ProjectMember)
+	resp, err := s.client.Do(req, pm)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return pm, resp, err
+}
+
+// AddProjectMemberOptions represents the available AddProjectMember() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#add-project-team-member
+type AddProjectMemberOptions struct {
+	UserID      *int              `url:"user_id,omitempty" json:"user_id,omitempty"`
+	AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"`
+}
+
+// AddProjectMember adds a user to a project team. This is an idempotent
+// method and can be called multiple times with the same parameters. Adding
+// team membership to a user that is already a member does not affect the
+// existing membership.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#add-project-team-member
+func (s *ProjectsService) AddProjectMember(
+	pid interface{},
+	opt *AddProjectMemberOptions) (*ProjectMember, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/members", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("POST", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	pm := new(ProjectMember)
+	resp, err := s.client.Do(req, pm)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return pm, resp, err
+}
+
+// EditProjectMemberOptions represents the available EditProjectMember() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#edit-project-team-member
+type EditProjectMemberOptions struct {
+	AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"`
+}
+
+// EditProjectMember updates a project team member to a specified access level..
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#edit-project-team-member
+func (s *ProjectsService) EditProjectMember(
+	pid interface{},
+	user int,
+	opt *EditProjectMemberOptions) (*ProjectMember, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/members/%d", url.QueryEscape(project), user)
+
+	req, err := s.client.NewRequest("PUT", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	pm := new(ProjectMember)
+	resp, err := s.client.Do(req, pm)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return pm, resp, err
+}
+
+// DeleteProjectMember removes a user from a project team.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#remove-project-team-member
+func (s *ProjectsService) DeleteProjectMember(pid interface{}, user int) (*Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, err
+	}
+	u := fmt.Sprintf("projects/%s/members/%d", url.QueryEscape(project), user)
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
+
+// ProjectHook represents a project hook.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#list-project-hooks
+type ProjectHook struct {
+	ID                    int        `json:"id"`
+	URL                   string     `json:"url"`
+	ProjectID             int        `json:"project_id"`
+	PushEvents            bool       `json:"push_events"`
+	IssuesEvents          bool       `json:"issues_events"`
+	MergeRequestsEvents   bool       `json:"merge_requests_events"`
+	TagPushEvents         bool       `json:"tag_push_events"`
+	NoteEvents            bool       `json:"note_events"`
+	BuildEvents           bool       `json:"build_events"`
+	PipelineEvents        bool       `json:"pipeline_events"`
+	WikiPageEvents        bool       `json:"wiki_page_events"`
+	EnableSSLVerification bool       `json:"enable_ssl_verification"`
+	CreatedAt             *time.Time `json:"created_at"`
+}
+
+// ListProjectHooksOptions represents the available ListProjectHooks() options.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#list-project-hooks
+type ListProjectHooksOptions struct {
+	ListOptions
+}
+
+// ListProjectHooks gets a list of project hooks.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#list-project-hooks
+func (s *ProjectsService) ListProjectHooks(
+	pid interface{},
+	opt *ListProjectHooksOptions) ([]*ProjectHook, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/hooks", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("GET", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var ph []*ProjectHook
+	resp, err := s.client.Do(req, &ph)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return ph, resp, err
+}
+
+// GetProjectHook gets a specific hook for a project.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#get-project-hook
+func (s *ProjectsService) GetProjectHook(
+	pid interface{},
+	hook int) (*ProjectHook, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/hooks/%d", url.QueryEscape(project), hook)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	ph := new(ProjectHook)
+	resp, err := s.client.Do(req, ph)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return ph, resp, err
+}
+
+// AddProjectHookOptions represents the available AddProjectHook() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#add-project-hook
+type AddProjectHookOptions struct {
+	URL                   *string `url:"url,omitempty" json:"url,omitempty"`
+	PushEvents            *bool   `url:"push_events,omitempty" json:"push_events,omitempty"`
+	IssuesEvents          *bool   `url:"issues_events,omitempty" json:"issues_events,omitempty"`
+	MergeRequestsEvents   *bool   `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"`
+	TagPushEvents         *bool   `url:"tag_push_events,omitempty" json:"tag_push_events,omitempty"`
+	NoteEvents            *bool   `url:"note_events,omitempty" json:"note_events,omitempty"`
+	BuildEvents           *bool   `url:"build_events,omitempty" json:"build_events,omitempty"`
+	PipelineEvents        *bool   `url:"pipeline_events,omitempty" json:"pipeline_events,omitempty"`
+	WikiPageEvents        *bool   `url:"wiki_page_events,omitempty" json:"wiki_page_events,omitempty"`
+	EnableSSLVerification *bool   `url:"enable_ssl_verification,omitempty" json:"enable_ssl_verification,omitempty"`
+}
+
+// AddProjectHook adds a hook to a specified project.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#add-project-hook
+func (s *ProjectsService) AddProjectHook(
+	pid interface{},
+	opt *AddProjectHookOptions) (*ProjectHook, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/hooks", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("POST", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	ph := new(ProjectHook)
+	resp, err := s.client.Do(req, ph)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return ph, resp, err
+}
+
+// EditProjectHookOptions represents the available EditProjectHook() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#edit-project-hook
+type EditProjectHookOptions struct {
+	URL                   *string `url:"url,omitempty" json:"url,omitempty"`
+	PushEvents            *bool   `url:"push_events,omitempty" json:"push_events,omitempty"`
+	IssuesEvents          *bool   `url:"issues_events,omitempty" json:"issues_events,omitempty"`
+	MergeRequestsEvents   *bool   `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"`
+	TagPushEvents         *bool   `url:"tag_push_events,omitempty" json:"tag_push_events,omitempty"`
+	NoteEvents            *bool   `url:"note_events,omitempty" json:"note_events,omitempty"`
+	BuildEvents           *bool   `url:"build_events,omitempty" json:"build_events,omitempty"`
+	PipelineEvents        *bool   `url:"pipeline_events,omitempty" json:"pipeline_events,omitempty"`
+	WikiPageEvents        *bool   `url:"wiki_page_events,omitempty" json:"wiki_page_events,omitempty"`
+	EnableSSLVerification *bool   `url:"enable_ssl_verification,omitempty" json:"enable_ssl_verification,omitempty"`
+}
+
+// EditProjectHook edits a hook for a specified project.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#edit-project-hook
+func (s *ProjectsService) EditProjectHook(
+	pid interface{},
+	hook int,
+	opt *EditProjectHookOptions) (*ProjectHook, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/hooks/%d", url.QueryEscape(project), hook)
+
+	req, err := s.client.NewRequest("PUT", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	ph := new(ProjectHook)
+	resp, err := s.client.Do(req, ph)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return ph, resp, err
+}
+
+// DeleteProjectHook removes a hook from a project. This is an idempotent
+// method and can be called multiple times. Either the hook is available or not.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#delete-project-hook
+func (s *ProjectsService) DeleteProjectHook(pid interface{}, hook int) (*Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, err
+	}
+	u := fmt.Sprintf("projects/%s/hooks/%d", url.QueryEscape(project), hook)
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
+
+// ProjectForkRelation represents a project fork relationship.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#admin-fork-relation
+type ProjectForkRelation struct {
+	ID                  int        `json:"id"`
+	ForkedToProjectID   int        `json:"forked_to_project_id"`
+	ForkedFromProjectID int        `json:"forked_from_project_id"`
+	CreatedAt           *time.Time `json:"created_at"`
+	UpdatedAt           *time.Time `json:"updated_at"`
+}
+
+// CreateProjectForkRelation creates a forked from/to relation between
+// existing projects.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#create-a-forked-fromto-relation-between-existing-projects.
+func (s *ProjectsService) CreateProjectForkRelation(
+	pid int,
+	fork int) (*ProjectForkRelation, *Response, error) {
+	u := fmt.Sprintf("projects/%d/fork/%d", pid, fork)
+
+	req, err := s.client.NewRequest("POST", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	pfr := new(ProjectForkRelation)
+	resp, err := s.client.Do(req, pfr)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return pfr, resp, err
+}
+
+// DeleteProjectForkRelation deletes an existing forked from relationship.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#delete-an-existing-forked-from-relationship
+func (s *ProjectsService) DeleteProjectForkRelation(pid int) (*Response, error) {
+	u := fmt.Sprintf("projects/%d/fork", pid)
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
+
+// ArchiveProject archives the project if the user is either admin or the
+// project owner of this project.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#archive-a-project
+func (s *ProjectsService) ArchiveProject(pid interface{}) (*Project, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/archive", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("POST", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	p := new(Project)
+	resp, err := s.client.Do(req, p)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return p, resp, err
+}
+
+// UnarchiveProject unarchives the project if the user is either admin or
+// the project owner of this project.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/projects.html#unarchive-a-project
+func (s *ProjectsService) UnarchiveProject(pid interface{}) (*Project, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/unarchive", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("POST", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	p := new(Project)
+	resp, err := s.client.Do(req, p)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return p, resp, err
+}
diff --git a/vendor/github.com/xanzy/go-gitlab/repositories.go b/vendor/github.com/xanzy/go-gitlab/repositories.go
new file mode 100644
index 0000000000000000000000000000000000000000..df2d10c9db4f63e0d5674a030c68d8655166fc4a
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/repositories.go
@@ -0,0 +1,270 @@
+//
+// Copyright 2015, Sander van Harmelen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package gitlab
+
+import (
+	"bytes"
+	"fmt"
+	"net/url"
+)
+
+// RepositoriesService handles communication with the repositories related
+// methods of the GitLab API.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/repositories.html
+type RepositoriesService struct {
+	client *Client
+}
+
+// TreeNode represents a GitLab repository file or directory.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/repositories.html
+type TreeNode struct {
+	ID   string `json:"id"`
+	Name string `json:"name"`
+	Type string `json:"type"`
+	Mode string `json:"mode"`
+}
+
+func (t TreeNode) String() string {
+	return Stringify(t)
+}
+
+// ListTreeOptions represents the available ListTree() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/repositories.html#list-repository-tree
+type ListTreeOptions struct {
+	Path    *string `url:"path,omitempty" json:"path,omitempty"`
+	RefName *string `url:"ref_name,omitempty" json:"ref_name,omitempty"`
+}
+
+// ListTree gets a list of repository files and directories in a project.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/repositories.html#list-repository-tree
+func (s *RepositoriesService) ListTree(
+	pid interface{},
+	opt *ListTreeOptions) ([]*TreeNode, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/tree", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("GET", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var t []*TreeNode
+	resp, err := s.client.Do(req, &t)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return t, resp, err
+}
+
+// RawFileContentOptions represents the available RawFileContent() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/repositories.html#raw-file-content
+type RawFileContentOptions struct {
+	FilePath *string `url:"filepath,omitempty" json:"filepath,omitempty"`
+}
+
+// RawFileContent gets the raw file contents for a file by commit SHA and path
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/repositories.html#raw-file-content
+func (s *RepositoriesService) RawFileContent(
+	pid interface{},
+	sha string,
+	opt *RawFileContentOptions) ([]byte, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/blobs/%s", url.QueryEscape(project), sha)
+
+	req, err := s.client.NewRequest("GET", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var b bytes.Buffer
+	resp, err := s.client.Do(req, &b)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return b.Bytes(), resp, err
+}
+
+// RawBlobContent gets the raw file contents for a blob by blob SHA.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/repositories.html#raw-blob-content
+func (s *RepositoriesService) RawBlobContent(
+	pid interface{},
+	sha string) ([]byte, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/raw_blobs/%s", url.QueryEscape(project), sha)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var b bytes.Buffer
+	resp, err := s.client.Do(req, &b)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return b.Bytes(), resp, err
+}
+
+// ArchiveOptions represents the available Archive() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/repositories.html#get-file-archive
+type ArchiveOptions struct {
+	SHA *string `url:"sha,omitempty" json:"sha,omitempty"`
+}
+
+// Archive gets an archive of the repository.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/repositories.html#get-file-archive
+func (s *RepositoriesService) Archive(
+	pid interface{},
+	opt *ArchiveOptions) ([]byte, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/archive", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("GET", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var b bytes.Buffer
+	resp, err := s.client.Do(req, &b)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return b.Bytes(), resp, err
+}
+
+// Compare represents the result of a comparison of branches, tags or commits.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/repositories.html#compare-branches-tags-or-commits
+type Compare struct {
+	Commit         *Commit   `json:"commit"`
+	Commits        []*Commit `json:"commits"`
+	Diffs          []*Diff   `json:"diffs"`
+	CompareTimeout bool      `json:"compare_timeout"`
+	CompareSameRef bool      `json:"compare_same_ref"`
+}
+
+func (c Compare) String() string {
+	return Stringify(c)
+}
+
+// CompareOptions represents the available Compare() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/repositories.html#compare-branches-tags-or-commits
+type CompareOptions struct {
+	From *string `url:"from,omitempty" json:"from,omitempty"`
+	To   *string `url:"to,omitempty" json:"to,omitempty"`
+}
+
+// Compare compares branches, tags or commits.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/repositories.html#compare-branches-tags-or-commits
+func (s *RepositoriesService) Compare(
+	pid interface{},
+	opt *CompareOptions) (*Compare, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/compare", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("GET", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	c := new(Compare)
+	resp, err := s.client.Do(req, c)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return c, resp, err
+}
+
+// Contributor represents a GitLap contributor.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/repositories.html#contributer
+type Contributor struct {
+	Name      string `json:"name,omitempty"`
+	Email     string `json:"email,omitempty"`
+	Commits   int    `json:"commits,omitempty"`
+	Additions int    `json:"additions,omitempty"`
+	Deletions int    `json:"deletions,omitempty"`
+}
+
+func (c Contributor) String() string {
+	return Stringify(c)
+}
+
+// Contributors gets the repository contributors list.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/repositories.html#contributer
+func (s *RepositoriesService) Contributors(pid interface{}) ([]*Contributor, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/contributors", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var c []*Contributor
+	resp, err := s.client.Do(req, &c)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return c, resp, err
+}
diff --git a/vendor/github.com/xanzy/go-gitlab/repository_files.go b/vendor/github.com/xanzy/go-gitlab/repository_files.go
new file mode 100644
index 0000000000000000000000000000000000000000..dbd77f40a84bfa082a22db6838e9b15dd0bd076d
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/repository_files.go
@@ -0,0 +1,218 @@
+//
+// Copyright 2015, Sander van Harmelen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package gitlab
+
+import (
+	"fmt"
+	"net/url"
+)
+
+// RepositoryFilesService handles communication with the repository files
+// related methods of the GitLab API.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/repository_files.html
+type RepositoryFilesService struct {
+	client *Client
+}
+
+// File represents a GitLab repository file.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/repository_files.html
+type File struct {
+	FileName string `json:"file_name"`
+	FilePath string `json:"file_path"`
+	Size     int    `json:"size"`
+	Encoding string `json:"encoding"`
+	Content  string `json:"content"`
+	Ref      string `json:"ref"`
+	BlobID   string `json:"blob_id"`
+	CommitID string `json:"commit_id"`
+}
+
+func (r File) String() string {
+	return Stringify(r)
+}
+
+// GetFileOptions represents the available GetFile() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/repository_files.html#get-file-from-respository
+type GetFileOptions struct {
+	FilePath *string `url:"file_path,omitempty" json:"file_path,omitempty"`
+	Ref      *string `url:"ref,omitempty" json:"ref,omitempty"`
+}
+
+// GetFile allows you to receive information about a file in repository like
+// name, size, content. Note that file content is Base64 encoded.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/repository_files.html#get-file-from-respository
+func (s *RepositoryFilesService) GetFile(
+	pid interface{},
+	opt *GetFileOptions) (*File, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/files", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("GET", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	f := new(File)
+	resp, err := s.client.Do(req, f)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return f, resp, err
+}
+
+// FileInfo represents file details of a GitLab repository file.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/repository_files.html
+type FileInfo struct {
+	FilePath   string `json:"file_path"`
+	BranchName string `json:"branch_name"`
+}
+
+func (r FileInfo) String() string {
+	return Stringify(r)
+}
+
+// CreateFileOptions represents the available CreateFile() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/repository_files.html#create-new-file-in-repository
+type CreateFileOptions struct {
+	FilePath      *string `url:"file_path,omitempty" json:"file_path,omitempty"`
+	BranchName    *string `url:"branch_name,omitempty" json:"branch_name,omitempty"`
+	Encoding      *string `url:"encoding,omitempty" json:"encoding,omitempty"`
+	AuthorEmail   *string `url:"author_email,omitempty" json:"author_email,omitempty"`
+	AuthorName    *string `url:"author_name,omitempty" json:"author_name,omitempty"`
+	Content       *string `url:"content,omitempty" json:"content,omitempty"`
+	CommitMessage *string `url:"commit_message,omitempty" json:"commit_message,omitempty"`
+}
+
+// CreateFile creates a new file in a repository.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/repository_files.html#create-new-file-in-repository
+func (s *RepositoryFilesService) CreateFile(
+	pid interface{},
+	opt *CreateFileOptions) (*FileInfo, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/files", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("POST", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	f := new(FileInfo)
+	resp, err := s.client.Do(req, f)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return f, resp, err
+}
+
+// UpdateFileOptions represents the available UpdateFile() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/repository_files.html#update-existing-file-in-repository
+type UpdateFileOptions struct {
+	FilePath      *string `url:"file_path,omitempty" json:"file_path,omitempty"`
+	BranchName    *string `url:"branch_name,omitempty" json:"branch_name,omitempty"`
+	Encoding      *string `url:"encoding,omitempty" json:"encoding,omitempty"`
+	AuthorEmail   *string `url:"author_email,omitempty" json:"author_email,omitempty"`
+	AuthorName    *string `url:"author_name,omitempty" json:"author_name,omitempty"`
+	Content       *string `url:"content,omitempty" json:"content,omitempty"`
+	CommitMessage *string `url:"commit_message,omitempty" json:"commit_message,omitempty"`
+}
+
+// UpdateFile updates an existing file in a repository
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/repository_files.html#update-existing-file-in-repository
+func (s *RepositoryFilesService) UpdateFile(
+	pid interface{},
+	opt *UpdateFileOptions) (*FileInfo, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/files", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("PUT", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	f := new(FileInfo)
+	resp, err := s.client.Do(req, f)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return f, resp, err
+}
+
+// DeleteFileOptions represents the available DeleteFile() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/repository_files.html#delete-existing-file-in-repository
+type DeleteFileOptions struct {
+	FilePath      *string `url:"file_path,omitempty" json:"file_path,omitempty"`
+	BranchName    *string `url:"branch_name,omitempty" json:"branch_name,omitempty"`
+	AuthorEmail   *string `url:"author_email,omitempty" json:"author_email,omitempty"`
+	AuthorName    *string `url:"author_name,omitempty" json:"author_name,omitempty"`
+	CommitMessage *string `url:"commit_message,omitempty" json:"commit_message,omitempty"`
+}
+
+// DeleteFile deletes an existing file in a repository
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/repository_files.html#delete-existing-file-in-repository
+func (s *RepositoryFilesService) DeleteFile(
+	pid interface{},
+	opt *DeleteFileOptions) (*FileInfo, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/files", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("DELETE", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	f := new(FileInfo)
+	resp, err := s.client.Do(req, f)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return f, resp, err
+}
diff --git a/vendor/github.com/xanzy/go-gitlab/services.go b/vendor/github.com/xanzy/go-gitlab/services.go
new file mode 100644
index 0000000000000000000000000000000000000000..a2a80ace2dcb434a858fc1a3b3a6534b21d5183b
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/services.go
@@ -0,0 +1,287 @@
+//
+// Copyright 2015, Sander van Harmelen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package gitlab
+
+import (
+	"fmt"
+	"net/url"
+	"time"
+)
+
+// ServicesService handles communication with the services related methods of
+// the GitLab API.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/services.html
+type ServicesService struct {
+	client *Client
+}
+
+// Service represents a GitLab service.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/services.html
+type Service struct {
+	ID                  *int       `json:"id"`
+	Title               *string    `json:"title"`
+	CreatedAt           *time.Time `json:"created_at"`
+	UpdatedAt           *time.Time `json:"created_at"`
+	Active              *bool      `json:"active"`
+	PushEvents          *bool      `json:"push_events"`
+	IssuesEvents        *bool      `json:"issues_events"`
+	MergeRequestsEvents *bool      `json:"merge_requests_events"`
+	TagPushEvents       *bool      `json:"tag_push_events"`
+	NoteEvents          *bool      `json:"note_events"`
+}
+
+// SetGitLabCIServiceOptions represents the available SetGitLabCIService()
+// options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/services.html#edit-gitlab-ci-service
+type SetGitLabCIServiceOptions struct {
+	Token      *string `url:"token,omitempty" json:"token,omitempty"`
+	ProjectURL *string `url:"project_url,omitempty" json:"project_url,omitempty"`
+}
+
+// SetGitLabCIService sets GitLab CI service for a project.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/services.html#edit-gitlab-ci-service
+func (s *ServicesService) SetGitLabCIService(
+	pid interface{},
+	opt *SetGitLabCIServiceOptions) (*Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, err
+	}
+	u := fmt.Sprintf("projects/%s/services/gitlab-ci", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("PUT", u, opt)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
+
+// DeleteGitLabCIService deletes GitLab CI service settings for a project.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/services.html#delete-gitlab-ci-service
+func (s *ServicesService) DeleteGitLabCIService(pid interface{}) (*Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, err
+	}
+	u := fmt.Sprintf("projects/%s/services/gitlab-ci", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
+
+// SetHipChatServiceOptions represents the available SetHipChatService()
+// options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/services.html#edit-hipchat-service
+type SetHipChatServiceOptions struct {
+	Token *string `url:"token,omitempty" json:"token,omitempty" `
+	Room  *string `url:"room,omitempty" json:"room,omitempty"`
+}
+
+// SetHipChatService sets HipChat service for a project
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/services.html#edit-hipchat-service
+func (s *ServicesService) SetHipChatService(
+	pid interface{},
+	opt *SetHipChatServiceOptions) (*Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, err
+	}
+	u := fmt.Sprintf("projects/%s/services/hipchat", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("PUT", u, opt)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
+
+// DeleteHipChatService deletes HipChat service for project.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/services.html#delete-hipchat-service
+func (s *ServicesService) DeleteHipChatService(pid interface{}) (*Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, err
+	}
+	u := fmt.Sprintf("projects/%s/services/hipchat", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
+
+// SetDroneCIServiceOptions represents the available SetDroneCIService()
+// options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/services.html#createedit-drone-ci-service
+type SetDroneCIServiceOptions struct {
+	Token                 *string `url:"token" json:"token" `
+	DroneURL              *string `url:"drone_url" json:"drone_url"`
+	EnableSSLVerification *string `url:"enable_ssl_verification,omitempty" json:"enable_ssl_verification,omitempty"`
+}
+
+// SetDroneCIService sets Drone CI service for a project.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/services.html#createedit-drone-ci-service
+func (s *ServicesService) SetDroneCIService(
+	pid interface{},
+	opt *SetDroneCIServiceOptions) (*Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, err
+	}
+	u := fmt.Sprintf("projects/%s/services/drone-ci", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("PUT", u, opt)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
+
+// DeleteDroneCIService deletes Drone CI service settings for a project.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/services.html#delete-drone-ci-service
+func (s *ServicesService) DeleteDroneCIService(pid interface{}) (*Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, err
+	}
+	u := fmt.Sprintf("projects/%s/services/drone-ci", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
+
+// DroneCIServiceProperties represents Drone CI specific properties.
+type DroneCIServiceProperties struct {
+	Token                 *string `url:"token" json:"token"`
+	DroneURL              *string `url:"drone_url" json:"drone_url"`
+	EnableSSLVerification *string `url:"enable_ssl_verification" json:"enable_ssl_verification"`
+}
+
+// DroneCIService represents Drone CI service settings.
+type DroneCIService struct {
+	Service
+	Properties *DroneCIServiceProperties `json:"properties"`
+}
+
+// GetDroneCIService gets Drone CI service settings for a project.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/services.html#get-drone-ci-service-settings
+func (s *ServicesService) GetDroneCIService(pid interface{}) (*DroneCIService, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/services/drone-ci", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	opt := new(DroneCIService)
+	resp, err := s.client.Do(req, opt)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return opt, resp, err
+}
+
+// SetSlackServiceOptions represents the available SetSlackService()
+// options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/services.html#edit-slack-service
+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"`
+}
+
+// SetSlackService sets Slack service for a project
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/services.html#edit-slack-service
+func (s *ServicesService) SetSlackService(
+	pid interface{},
+	opt *SetSlackServiceOptions) (*Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, err
+	}
+	u := fmt.Sprintf("projects/%s/services/slack", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("PUT", u, opt)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
+
+// DeleteSlackService deletes Slack service for project.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/services.html#delete-slack-service
+func (s *ServicesService) DeleteSlackService(pid interface{}) (*Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, err
+	}
+	u := fmt.Sprintf("projects/%s/services/slack", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
diff --git a/vendor/github.com/xanzy/go-gitlab/session.go b/vendor/github.com/xanzy/go-gitlab/session.go
new file mode 100644
index 0000000000000000000000000000000000000000..efe01692bf03e221dbcf86d5a19d444b7689f230
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/session.go
@@ -0,0 +1,78 @@
+//
+// Copyright 2015, Sander van Harmelen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package gitlab
+
+import "time"
+
+// SessionService handles communication with the session related methods of
+// the GitLab API.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/session.html
+type SessionService struct {
+	client *Client
+}
+
+// Session represents a GitLab session.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/session.html#session
+type Session struct {
+	ID               int         `json:"id"`
+	Username         string      `json:"username"`
+	Email            string      `json:"email"`
+	Name             string      `json:"name"`
+	PrivateToken     string      `json:"private_token"`
+	Blocked          bool        `json:"blocked"`
+	CreatedAt        *time.Time  `json:"created_at"`
+	Bio              interface{} `json:"bio"`
+	Skype            string      `json:"skype"`
+	Linkedin         string      `json:"linkedin"`
+	Twitter          string      `json:"twitter"`
+	WebsiteURL       string      `json:"website_url"`
+	DarkScheme       bool        `json:"dark_scheme"`
+	ThemeID          int         `json:"theme_id"`
+	IsAdmin          bool        `json:"is_admin"`
+	CanCreateGroup   bool        `json:"can_create_group"`
+	CanCreateTeam    bool        `json:"can_create_team"`
+	CanCreateProject bool        `json:"can_create_project"`
+}
+
+// GetSessionOptions represents the available Session() options.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/session.html#session
+type GetSessionOptions struct {
+	Login    *string `url:"login,omitempty" json:"login,omitempty"`
+	Email    *string `url:"email,omitempty" json:"email,omitempty"`
+	Password *string `url:"password,omitempty" json:"password,omitempty"`
+}
+
+// GetSession logs in to get private token.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/session.html#session
+func (s *SessionService) GetSession(opt *GetSessionOptions) (*Session, *Response, error) {
+	req, err := s.client.NewRequest("POST", "session", opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	session := new(Session)
+	resp, err := s.client.Do(req, session)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return session, resp, err
+}
diff --git a/vendor/github.com/xanzy/go-gitlab/settings.go b/vendor/github.com/xanzy/go-gitlab/settings.go
new file mode 100644
index 0000000000000000000000000000000000000000..cbb55233f0c77eaf051fb878d1e08e020cbd1dff
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/settings.go
@@ -0,0 +1,117 @@
+//
+// Copyright 2015, Sander van Harmelen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package gitlab
+
+import "time"
+
+// SettingsService handles communication with the application SettingsService
+// related methods of the GitLab API.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/settings.html
+type SettingsService struct {
+	client *Client
+}
+
+// Settings represents the GitLab application settings.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/settings.html
+type Settings struct {
+	ID                         int                    `json:"id"`
+	DefaultProjectsLimit       int                    `json:"default_projects_limit"`
+	SignupEnabled              bool                   `json:"signup_enabled"`
+	SigninEnabled              bool                   `json:"signin_enabled"`
+	GravatarEnabled            bool                   `json:"gravatar_enabled"`
+	SignInText                 string                 `json:"sign_in_text"`
+	CreatedAt                  *time.Time             `json:"created_at"`
+	UpdatedAt                  *time.Time             `json:"updated_at"`
+	HomePageURL                string                 `json:"home_page_url"`
+	DefaultBranchProtection    int                    `json:"default_branch_protection"`
+	TwitterSharingEnabled      bool                   `json:"twitter_sharing_enabled"`
+	RestrictedVisibilityLevels []VisibilityLevelValue `json:"restricted_visibility_levels"`
+	MaxAttachmentSize          int                    `json:"max_attachment_size"`
+	SessionExpireDelay         int                    `json:"session_expire_delay"`
+	DefaultProjectVisibility   int                    `json:"default_project_visibility"`
+	DefaultSnippetVisibility   int                    `json:"default_snippet_visibility"`
+	RestrictedSignupDomains    []string               `json:"restricted_signup_domains"`
+	UserOauthApplications      bool                   `json:"user_oauth_applications"`
+	AfterSignOutPath           string                 `json:"after_sign_out_path"`
+}
+
+func (s Settings) String() string {
+	return Stringify(s)
+}
+
+// GetSettings gets the current application settings.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/settings.html#get-current-application.settings
+func (s *SettingsService) GetSettings() (*Settings, *Response, error) {
+	req, err := s.client.NewRequest("GET", "application/settings", nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	as := new(Settings)
+	resp, err := s.client.Do(req, as)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return as, resp, err
+}
+
+// UpdateSettingsOptions represents the available UpdateSettings() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/settings.html#change-application.settings
+type UpdateSettingsOptions struct {
+	DefaultProjectsLimit       *int                   `url:"default_projects_limit,omitempty" json:"default_projects_limit,omitempty"`
+	SignupEnabled              *bool                  `url:"signup_enabled,omitempty" json:"signup_enabled,omitempty"`
+	SigninEnabled              *bool                  `url:"signin_enabled,omitempty" json:"signin_enabled,omitempty"`
+	GravatarEnabled            *bool                  `url:"gravatar_enabled,omitempty" json:"gravatar_enabled,omitempty"`
+	SignInText                 *string                `url:"sign_in_text,omitempty" json:"sign_in_text,omitempty"`
+	HomePageURL                *string                `url:"home_page_url,omitempty" json:"home_page_url,omitempty"`
+	DefaultBranchProtection    *int                   `url:"default_branch_protection,omitempty" json:"default_branch_protection,omitempty"`
+	TwitterSharingEnabled      *bool                  `url:"twitter_sharing_enabled,omitempty" json:"twitter_sharing_enabled,omitempty"`
+	RestrictedVisibilityLevels []VisibilityLevelValue `url:"restricted_visibility_levels,omitempty" json:"restricted_visibility_levels,omitempty"`
+	MaxAttachmentSize          *int                   `url:"max_attachment_size,omitempty" json:"max_attachment_size,omitempty"`
+	SessionExpireDelay         *int                   `url:"session_expire_delay,omitempty" json:"session_expire_delay,omitempty"`
+	DefaultProjectVisibility   *int                   `url:"default_project_visibility,omitempty" json:"default_project_visibility,omitempty"`
+	DefaultSnippetVisibility   *int                   `url:"default_snippet_visibility,omitempty" json:"default_snippet_visibility,omitempty"`
+	RestrictedSignupDomains    []string               `url:"restricted_signup_domains,omitempty" json:"restricted_signup_domains,omitempty"`
+	UserOauthApplications      *bool                  `url:"user_oauth_applications,omitempty" json:"user_oauth_applications,omitempty"`
+	AfterSignOutPath           *string                `url:"after_sign_out_path,omitempty" json:"after_sign_out_path,omitempty"`
+}
+
+// UpdateSettings updates the application settings.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/settings.html#change-application.settings
+func (s *SettingsService) UpdateSettings(opt *UpdateSettingsOptions) (*Settings, *Response, error) {
+	req, err := s.client.NewRequest("PUT", "application/settings", opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	as := new(Settings)
+	resp, err := s.client.Do(req, as)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return as, resp, err
+}
diff --git a/vendor/github.com/xanzy/go-gitlab/strings.go b/vendor/github.com/xanzy/go-gitlab/strings.go
new file mode 100644
index 0000000000000000000000000000000000000000..d0e7679b3a7c670c2ad3fddcd51f3744721e6ab8
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/strings.go
@@ -0,0 +1,94 @@
+//
+// Copyright 2015, Sander van Harmelen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package gitlab
+
+import (
+	"bytes"
+	"fmt"
+
+	"reflect"
+)
+
+// Stringify attempts to create a reasonable string representation of types in
+// the GitHub library.  It does things like resolve pointers to their values
+// and omits struct fields with nil values.
+func Stringify(message interface{}) string {
+	var buf bytes.Buffer
+	v := reflect.ValueOf(message)
+	stringifyValue(&buf, v)
+	return buf.String()
+}
+
+// stringifyValue was heavily inspired by the goprotobuf library.
+func stringifyValue(buf *bytes.Buffer, val reflect.Value) {
+	if val.Kind() == reflect.Ptr && val.IsNil() {
+		buf.WriteString("<nil>")
+		return
+	}
+
+	v := reflect.Indirect(val)
+
+	switch v.Kind() {
+	case reflect.String:
+		fmt.Fprintf(buf, `"%s"`, v)
+	case reflect.Slice:
+		buf.WriteByte('[')
+		for i := 0; i < v.Len(); i++ {
+			if i > 0 {
+				buf.WriteByte(' ')
+			}
+
+			stringifyValue(buf, v.Index(i))
+		}
+
+		buf.WriteByte(']')
+		return
+	case reflect.Struct:
+		if v.Type().Name() != "" {
+			buf.WriteString(v.Type().String())
+		}
+
+		buf.WriteByte('{')
+
+		var sep bool
+		for i := 0; i < v.NumField(); i++ {
+			fv := v.Field(i)
+			if fv.Kind() == reflect.Ptr && fv.IsNil() {
+				continue
+			}
+			if fv.Kind() == reflect.Slice && fv.IsNil() {
+				continue
+			}
+
+			if sep {
+				buf.WriteString(", ")
+			} else {
+				sep = true
+			}
+
+			buf.WriteString(v.Type().Field(i).Name)
+			buf.WriteByte(':')
+			stringifyValue(buf, fv)
+		}
+
+		buf.WriteByte('}')
+	default:
+		if v.CanInterface() {
+			fmt.Fprint(buf, v.Interface())
+		}
+	}
+}
diff --git a/vendor/github.com/xanzy/go-gitlab/system_hooks.go b/vendor/github.com/xanzy/go-gitlab/system_hooks.go
new file mode 100644
index 0000000000000000000000000000000000000000..48e052a5ab5e76e789db91de30c90b3f7ad038fb
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/system_hooks.go
@@ -0,0 +1,143 @@
+//
+// Copyright 2015, Sander van Harmelen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package gitlab
+
+import (
+	"fmt"
+	"time"
+)
+
+// SystemHooksService handles communication with the system hooks related
+// methods of the GitLab API.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/system_hooks.html
+type SystemHooksService struct {
+	client *Client
+}
+
+// Hook represents a GitLap system hook.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/system_hooks.html
+type Hook struct {
+	ID        int        `json:"id"`
+	URL       string     `json:"url"`
+	CreatedAt *time.Time `json:"created_at"`
+}
+
+func (h Hook) String() string {
+	return Stringify(h)
+}
+
+// ListHooks gets a list of system hooks.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/system_hooks.html#list-system-hooks
+func (s *SystemHooksService) ListHooks() ([]*Hook, *Response, error) {
+	req, err := s.client.NewRequest("GET", "hooks", nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var h []*Hook
+	resp, err := s.client.Do(req, &h)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return h, resp, err
+}
+
+// AddHookOptions represents the available AddHook() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/system_hooks.html#add-new-system-hook-hook
+type AddHookOptions struct {
+	URL *string `url:"url,omitempty" json:"url,omitempty"`
+}
+
+// AddHook adds a new system hook hook.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/system_hooks.html#add-new-system-hook-hook
+func (s *SystemHooksService) AddHook(opt *AddHookOptions) (*Hook, *Response, error) {
+	req, err := s.client.NewRequest("POST", "hooks", opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	h := new(Hook)
+	resp, err := s.client.Do(req, h)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return h, resp, err
+}
+
+// HookEvent represents an event triggert by a GitLab system hook.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/system_hooks.html
+type HookEvent struct {
+	EventName  string `json:"event_name"`
+	Name       string `json:"name"`
+	Path       string `json:"path"`
+	ProjectID  int    `json:"project_id"`
+	OwnerName  string `json:"owner_name"`
+	OwnerEmail string `json:"owner_email"`
+}
+
+func (h HookEvent) String() string {
+	return Stringify(h)
+}
+
+// TestHook tests a system hook.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/system_hooks.html#test-system-hook
+func (s *SystemHooksService) TestHook(hook int) (*HookEvent, *Response, error) {
+	u := fmt.Sprintf("hooks/%d", hook)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	h := new(HookEvent)
+	resp, err := s.client.Do(req, h)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return h, resp, err
+}
+
+// DeleteHook deletes a system hook. This is an idempotent API function and
+// returns 200 OK even if the hook is not available. If the hook is deleted it
+// is also returned as JSON.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/system_hooks.html#delete-system-hook
+func (s *SystemHooksService) DeleteHook(hook int) (*Response, error) {
+	u := fmt.Sprintf("hooks/%d", hook)
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
diff --git a/vendor/github.com/xanzy/go-gitlab/tags.go b/vendor/github.com/xanzy/go-gitlab/tags.go
new file mode 100644
index 0000000000000000000000000000000000000000..759cd7a2ecbc3b624c5484afbcf9f7051345cff7
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/tags.go
@@ -0,0 +1,149 @@
+//
+// Copyright 2015, Sander van Harmelen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package gitlab
+
+import (
+	"fmt"
+	"net/url"
+)
+
+// TagsService handles communication with the tags related methods
+// of the GitLab API.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/tags.html
+type TagsService struct {
+	client *Client
+}
+
+// Tag represents a GitLab tag.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/tags.html
+type Tag struct {
+	Commit  *Commit `json:"commit"`
+	Name    string  `json:"name"`
+	Message string  `json:"message"`
+}
+
+func (r Tag) String() string {
+	return Stringify(r)
+}
+
+// ListTags gets a list of tags from a project, sorted by name in reverse
+// alphabetical order.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/tags.html#list-project-repository-tags
+func (s *TagsService) ListTags(pid interface{}) ([]*Tag, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/tags", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var t []*Tag
+	resp, err := s.client.Do(req, &t)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return t, resp, err
+}
+
+// GetTag a specific repository tag determined by its name. It returns 200 together
+// with the tag information if the tag exists. It returns 404 if the tag does not exist.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/tags.html#get-a-single-repository-tag
+func (s *TagsService) GetTag(pid interface{}, tag string) (*Tag, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/tags/%s", url.QueryEscape(project), tag)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var t *Tag
+	resp, err := s.client.Do(req, &t)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return t, resp, err
+}
+
+// CreateTagOptions represents the available CreateTag() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/tags.html#create-a-new-tag
+type CreateTagOptions struct {
+	TagName *string `url:"tag_name,omitempty" json:"tag_name,omitempty"`
+	Ref     *string `url:"ref,omitempty" json:"ref,omitempty"`
+	Message *string `url:"message,omitempty" json:"message,omitempty"`
+}
+
+// CreateTag creates a new tag in the repository that points to the supplied ref.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/tags.html#create-a-new-tag
+func (s *TagsService) CreateTag(pid interface{}, opt *CreateTagOptions) (*Tag, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/tags", url.QueryEscape(project))
+
+	req, err := s.client.NewRequest("POST", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	t := new(Tag)
+	resp, err := s.client.Do(req, t)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return t, resp, err
+}
+
+// DeleteTag deletes a tag of a repository with given name.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/tags.html#delete-a-tag
+func (s *TagsService) DeleteTag(pid interface{}, tag string) (*Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, err
+	}
+	u := fmt.Sprintf("projects/%s/repository/tags/%s", url.QueryEscape(project), tag)
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
diff --git a/vendor/github.com/xanzy/go-gitlab/users.go b/vendor/github.com/xanzy/go-gitlab/users.go
new file mode 100644
index 0000000000000000000000000000000000000000..13ae2ae6496cda8ff0ad5414814d9629f2e8a23c
--- /dev/null
+++ b/vendor/github.com/xanzy/go-gitlab/users.go
@@ -0,0 +1,588 @@
+//
+// Copyright 2015, Sander van Harmelen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package gitlab
+
+import (
+	"errors"
+	"fmt"
+	"time"
+)
+
+// UsersService handles communication with the user related methods of
+// the GitLab API.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/users.html
+type UsersService struct {
+	client *Client
+}
+
+// User represents a GitLab user.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/users.html
+type User struct {
+	ID               int             `json:"id"`
+	Username         string          `json:"username"`
+	Email            string          `json:"email"`
+	Name             string          `json:"name"`
+	State            string          `json:"state"`
+	CreatedAt        *time.Time      `json:"created_at"`
+	Bio              string          `json:"bio"`
+	Skype            string          `json:"skype"`
+	Linkedin         string          `json:"linkedin"`
+	Twitter          string          `json:"twitter"`
+	WebsiteURL       string          `json:"website_url"`
+	ExternUID        string          `json:"extern_uid"`
+	Provider         string          `json:"provider"`
+	ThemeID          int             `json:"theme_id"`
+	ColorSchemeID    int             `json:"color_scheme_id"`
+	IsAdmin          bool            `json:"is_admin"`
+	AvatarURL        string          `json:"avatar_url"`
+	CanCreateGroup   bool            `json:"can_create_group"`
+	CanCreateProject bool            `json:"can_create_project"`
+	ProjectsLimit    int             `json:"projects_limit"`
+	CurrentSignInAt  *time.Time      `json:"current_sign_in_at"`
+	LastSignInAt     *time.Time      `json:"last_sign_in_at"`
+	TwoFactorEnabled bool            `json:"two_factor_enabled"`
+	Identities       []*UserIdentity `json:"identities"`
+}
+
+// UserIdentity represents a user identity
+type UserIdentity struct {
+	Provider  string `json:"provider"`
+	ExternUID string `json:"extern_uid"`
+}
+
+// ListUsersOptions represents the available ListUsers() options.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#list-users
+type ListUsersOptions struct {
+	ListOptions
+	Active   *bool   `url:"active,omitempty" json:"active,omitempty"`
+	Search   *string `url:"search,omitempty" json:"search,omitempty"`
+	Username *string `url:"username,omitempty" json:"username,omitempty"`
+}
+
+// ListUsers gets a list of users.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#list-users
+func (s *UsersService) ListUsers(opt *ListUsersOptions) ([]*User, *Response, error) {
+	req, err := s.client.NewRequest("GET", "users", opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var usr []*User
+	resp, err := s.client.Do(req, &usr)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return usr, resp, err
+}
+
+// GetUser gets a single user.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#single-user
+func (s *UsersService) GetUser(user int) (*User, *Response, error) {
+	u := fmt.Sprintf("users/%d", user)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	usr := new(User)
+	resp, err := s.client.Do(req, usr)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return usr, resp, err
+}
+
+// CreateUserOptions represents the available CreateUser() options.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#user-creation
+type CreateUserOptions struct {
+	Email          *string `url:"email,omitempty" json:"email,omitempty"`
+	Password       *string `url:"password,omitempty" json:"password,omitempty"`
+	Username       *string `url:"username,omitempty" json:"username,omitempty"`
+	Name           *string `url:"name,omitempty" json:"name,omitempty"`
+	Skype          *string `url:"skype,omitempty" json:"skype,omitempty"`
+	Linkedin       *string `url:"linkedin,omitempty" json:"linkedin,omitempty"`
+	Twitter        *string `url:"twitter,omitempty" json:"twitter,omitempty"`
+	WebsiteURL     *string `url:"website_url,omitempty" json:"website_url,omitempty"`
+	ProjectsLimit  *int    `url:"projects_limit,omitempty" json:"projects_limit,omitempty"`
+	ExternUID      *string `url:"extern_uid,omitempty" json:"extern_uid,omitempty"`
+	Provider       *string `url:"provider,omitempty" json:"provider,omitempty"`
+	Bio            *string `url:"bio,omitempty" json:"bio,omitempty"`
+	Admin          *bool   `url:"admin,omitempty" json:"admin,omitempty"`
+	CanCreateGroup *bool   `url:"can_create_group,omitempty" json:"can_create_group,omitempty"`
+	Confirm        *bool   `url:"confirm,omitempty" json:"confirm,omitempty"`
+}
+
+// CreateUser creates a new user. Note only administrators can create new users.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#user-creation
+func (s *UsersService) CreateUser(opt *CreateUserOptions) (*User, *Response, error) {
+	req, err := s.client.NewRequest("POST", "users", opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	usr := new(User)
+	resp, err := s.client.Do(req, usr)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return usr, resp, err
+}
+
+// ModifyUserOptions represents the available ModifyUser() options.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#user-modification
+type ModifyUserOptions struct {
+	Email          *string `url:"email,omitempty" json:"email,omitempty"`
+	Password       *string `url:"password,omitempty" json:"password,omitempty"`
+	Username       *string `url:"username,omitempty" json:"username,omitempty"`
+	Name           *string `url:"name,omitempty" json:"name,omitempty"`
+	Skype          *string `url:"skype,omitempty" json:"skype,omitempty"`
+	Linkedin       *string `url:"linkedin,omitempty" json:"linkedin,omitempty"`
+	Twitter        *string `url:"twitter,omitempty" json:"twitter,omitempty"`
+	WebsiteURL     *string `url:"website_url,omitempty" json:"website_url,omitempty"`
+	ProjectsLimit  *int    `url:"projects_limit,omitempty" json:"projects_limit,omitempty"`
+	ExternUID      *string `url:"extern_uid,omitempty" json:"extern_uid,omitempty"`
+	Provider       *string `url:"provider,omitempty" json:"provider,omitempty"`
+	Bio            *string `url:"bio,omitempty" json:"bio,omitempty"`
+	Admin          *bool   `url:"admin,omitempty" json:"admin,omitempty"`
+	CanCreateGroup *bool   `url:"can_create_group,omitempty" json:"can_create_group,omitempty"`
+}
+
+// ModifyUser modifies an existing user. Only administrators can change attributes
+// of a user.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#user-modification
+func (s *UsersService) ModifyUser(user int, opt *ModifyUserOptions) (*User, *Response, error) {
+	u := fmt.Sprintf("users/%d", user)
+
+	req, err := s.client.NewRequest("PUT", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	usr := new(User)
+	resp, err := s.client.Do(req, usr)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return usr, resp, err
+}
+
+// DeleteUser deletes a user. Available only for administrators. This is an
+// idempotent function, calling this function for a non-existent user id still
+// returns a status code 200 OK. The JSON response differs if the user was
+// actually deleted or not. In the former the user is returned and in the
+// latter not.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#user-deletion
+func (s *UsersService) DeleteUser(user int) (*Response, error) {
+	u := fmt.Sprintf("users/%d", user)
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
+
+// CurrentUser gets currently authenticated user.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#current-user
+func (s *UsersService) CurrentUser() (*User, *Response, error) {
+	req, err := s.client.NewRequest("GET", "user", nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	usr := new(User)
+	resp, err := s.client.Do(req, usr)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return usr, resp, err
+}
+
+// SSHKey represents a SSH key.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#list-ssh-keys
+type SSHKey struct {
+	ID        int        `json:"id"`
+	Title     string     `json:"title"`
+	Key       string     `json:"key"`
+	CreatedAt *time.Time `json:"created_at"`
+}
+
+// ListSSHKeys gets a list of currently authenticated user's SSH keys.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#list-ssh-keys
+func (s *UsersService) ListSSHKeys() ([]*SSHKey, *Response, error) {
+	req, err := s.client.NewRequest("GET", "user/keys", nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var k []*SSHKey
+	resp, err := s.client.Do(req, &k)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return k, resp, err
+}
+
+// ListSSHKeysForUser gets a list of a specified user's SSH keys. Available
+// only for admin
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/users.html#list-ssh-keys-for-user
+func (s *UsersService) ListSSHKeysForUser(user int) ([]*SSHKey, *Response, error) {
+	u := fmt.Sprintf("users/%d/keys", user)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var k []*SSHKey
+	resp, err := s.client.Do(req, &k)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return k, resp, err
+}
+
+// GetSSHKey gets a single key.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#single-ssh-key
+func (s *UsersService) GetSSHKey(kid int) (*SSHKey, *Response, error) {
+	u := fmt.Sprintf("user/keys/%d", kid)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	k := new(SSHKey)
+	resp, err := s.client.Do(req, k)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return k, resp, err
+}
+
+// AddSSHKeyOptions represents the available AddSSHKey() options.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#add-ssh-key
+type AddSSHKeyOptions struct {
+	Title *string `url:"title,omitempty" json:"title,omitempty"`
+	Key   *string `url:"key,omitempty" json:"key,omitempty"`
+}
+
+// AddSSHKey creates a new key owned by the currently authenticated user.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#add-ssh-key
+func (s *UsersService) AddSSHKey(opt *AddSSHKeyOptions) (*SSHKey, *Response, error) {
+	req, err := s.client.NewRequest("POST", "user/keys", opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	k := new(SSHKey)
+	resp, err := s.client.Do(req, k)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return k, resp, err
+}
+
+// AddSSHKeyForUser creates new key owned by specified user. Available only for
+// admin.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#add-ssh-key-for-user
+func (s *UsersService) AddSSHKeyForUser(
+	user int,
+	opt *AddSSHKeyOptions) (*SSHKey, *Response, error) {
+	u := fmt.Sprintf("users/%d/keys", user)
+
+	req, err := s.client.NewRequest("POST", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	k := new(SSHKey)
+	resp, err := s.client.Do(req, k)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return k, resp, err
+}
+
+// DeleteSSHKey deletes key owned by currently authenticated user. This is an
+// idempotent function and calling it on a key that is already deleted or not
+// available results in 200 OK.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/users.html#delete-ssh-key-for-current-owner
+func (s *UsersService) DeleteSSHKey(kid int) (*Response, error) {
+	u := fmt.Sprintf("user/keys/%d", kid)
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
+
+// DeleteSSHKeyForUser deletes key owned by a specified user. Available only
+// for admin.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/users.html#delete-ssh-key-for-given-user
+func (s *UsersService) DeleteSSHKeyForUser(user int, kid int) (*Response, error) {
+	u := fmt.Sprintf("users/%d/keys/%d", user, kid)
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
+
+// BlockUser blocks the specified user. Available only for admin.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#block-user
+func (s *UsersService) BlockUser(user int) error {
+	u := fmt.Sprintf("users/%d/block", user)
+
+	req, err := s.client.NewRequest("PUT", u, nil)
+	if err != nil {
+		return err
+	}
+
+	resp, err := s.client.Do(req, nil)
+	if err != nil {
+		return err
+	}
+
+	switch resp.StatusCode {
+	case 200:
+		return nil
+	case 403:
+		return errors.New("Cannot block a user that is already blocked by LDAP synchronization")
+	case 404:
+		return errors.New("User does not exists")
+	default:
+		return fmt.Errorf("Received unexpected result code: %d", resp.StatusCode)
+	}
+}
+
+// UnblockUser unblocks the specified user. Available only for admin.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#unblock-user
+func (s *UsersService) UnblockUser(user int) error {
+	u := fmt.Sprintf("users/%d/unblock", user)
+
+	req, err := s.client.NewRequest("PUT", u, nil)
+	if err != nil {
+		return err
+	}
+
+	resp, err := s.client.Do(req, nil)
+	if err != nil {
+		return err
+	}
+
+	switch resp.StatusCode {
+	case 200:
+		return nil
+	case 403:
+		return errors.New("Cannot unblock a user that is blocked by LDAP synchronization")
+	case 404:
+		return errors.New("User does not exists")
+	default:
+		return fmt.Errorf("Received unexpected result code: %d", resp.StatusCode)
+	}
+}
+
+// Email represents an Email.
+//
+// GitLab API docs: https://doc.gitlab.com/ce/api/users.html#list-emails
+type Email struct {
+	ID    int    `json:"id"`
+	Email string `json:"email"`
+}
+
+// ListEmails gets a list of currently authenticated user's Emails.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#list-emails
+func (s *UsersService) ListEmails() ([]*Email, *Response, error) {
+	req, err := s.client.NewRequest("GET", "user/emails", nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var e []*Email
+	resp, err := s.client.Do(req, &e)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return e, resp, err
+}
+
+// ListEmailsForUser gets a list of a specified user's Emails. Available
+// only for admin
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/users.html#list-emails-for-user
+func (s *UsersService) ListEmailsForUser(uid int) ([]*Email, *Response, error) {
+	u := fmt.Sprintf("users/%d/emails", uid)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var e []*Email
+	resp, err := s.client.Do(req, &e)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return e, resp, err
+}
+
+// GetEmail gets a single email.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#single-email
+func (s *UsersService) GetEmail(eid int) (*Email, *Response, error) {
+	u := fmt.Sprintf("user/emails/%d", eid)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	e := new(Email)
+	resp, err := s.client.Do(req, e)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return e, resp, err
+}
+
+// AddEmailOptions represents the available AddEmail() options.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#add-email
+type AddEmailOptions struct {
+	Email *string `url:"email,omitempty" json:"email,omitempty"`
+}
+
+// AddEmail creates a new email owned by the currently authenticated user.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#add-email
+func (s *UsersService) AddEmail(opt *AddEmailOptions) (*Email, *Response, error) {
+	req, err := s.client.NewRequest("POST", "user/emails", opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	e := new(Email)
+	resp, err := s.client.Do(req, e)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return e, resp, err
+}
+
+// AddEmailForUser creates new email owned by specified user. Available only for
+// admin.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#add-email-for-user
+func (s *UsersService) AddEmailForUser(
+	uid int,
+	opt *AddEmailOptions) (*Email, *Response, error) {
+	u := fmt.Sprintf("users/%d/emails", uid)
+
+	req, err := s.client.NewRequest("POST", u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	e := new(Email)
+	resp, err := s.client.Do(req, e)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return e, resp, err
+}
+
+// DeleteEmail deletes email owned by currently authenticated user. This is an
+// idempotent function and calling it on a key that is already deleted or not
+// available results in 200 OK.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/users.html#delete-email-for-current-owner
+func (s *UsersService) DeleteEmail(eid int) (*Response, error) {
+	u := fmt.Sprintf("user/emails/%d", eid)
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
+
+// DeleteEmailForUser deletes email owned by a specified user. Available only
+// for admin.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/users.html#delete-email-for-given-user
+func (s *UsersService) DeleteEmailForUser(uid int, eid int) (*Response, error) {
+	u := fmt.Sprintf("users/%d/emails/%d", uid, eid)
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
diff --git a/vendor/vendor.json b/vendor/vendor.json
index 48a6e98ddd5dd6d9da3f8b838dc9198ca5fd9cd7..85333978282ba322573ea67537434e779545843c 100644
--- a/vendor/vendor.json
+++ b/vendor/vendor.json
@@ -500,6 +500,12 @@
 			"revision": "fd565ec6f8e236d6b63b953f3aecb2f2cca80605",
 			"revisionTime": "2016-07-21T22:16:07Z"
 		},
+		{
+			"checksumSHA1": "2ATUAGg/AkEvSkj0w8x480HUEKA=",
+			"path": "github.com/xanzy/go-gitlab",
+			"revision": "eeb802d2a232062597f50c12390fd70b8bf3f7db",
+			"revisionTime": "2016-12-29T10:51:52Z"
+		},
 		{
 			"checksumSHA1": "RBe0HvUoZ1JL4XXPxslcvt+E6AI=",
 			"path": "go4.org/wkfs",