Commit 87481151 authored by achiu's avatar achiu

Add support for protected tags

parent 294b2a04
......@@ -321,6 +321,7 @@ type Client struct {
ProjectSnippets *ProjectSnippetsService
ProjectVariables *ProjectVariablesService
ProtectedBranches *ProtectedBranchesService
ProtectedTags *ProtectedTagsService
Repositories *RepositoriesService
RepositoryFiles *RepositoryFilesService
Runners *RunnersService
......@@ -461,6 +462,7 @@ func newClient(httpClient *http.Client) *Client {
c.ProjectSnippets = &ProjectSnippetsService{client: c}
c.ProjectVariables = &ProjectVariablesService{client: c}
c.ProtectedBranches = &ProtectedBranchesService{client: c}
c.ProtectedTags = &ProtectedTagsService{client: c}
c.Repositories = &RepositoriesService{client: c}
c.RepositoryFiles = &RepositoryFilesService{client: c}
c.Runners = &RunnersService{client: c}
......
package gitlab
import (
"fmt"
"net/url"
)
// ProtectedTagsService handles communication with the protected tag methods of the GitLab API.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/protected_tags.html
type ProtectedTagsService struct {
client *Client
}
// TagAccessDescription reperesents the access decription for a protected tag.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/protected_tags.html#list-protected-tags
type TagAccessDescription struct {
AccessLevel AccessLevelValue `json:"access_level"`
AccessLevelDescription string `json:"access_level_description"`
}
// ProtectedTag represents a protected tag.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/protected_tags.html#list-protected-tags
type ProtectedTag struct {
Name string `json:"name"`
CreateAccessLevels []*TagAccessDescription `json:"create_access_levels"`
}
// ListProtectedTagsOptions represents available ListProtectedTags() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/protected_tags.html#list-protected-tags
type ListProtectedTagsOptions ListOptions
// ListProtectedTags returns a list of protected tags from a project.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/protected_tags.html#list-protected-tags
func (s *ProtectedTagsService) ListProtectedTags(pid interface{}, opt *ListProtectedTagsOptions, options ...OptionFunc) ([]*ProtectedTag, *Response, error) {
project, err := parseID(pid)
if err != nil {
return nil, nil, err
}
u := fmt.Sprintf("projects/%s/protected_tags", url.QueryEscape(project))
req, err := s.client.NewRequest("GET", u, opt, options)
if err != nil {
return nil, nil, err
}
var p []*ProtectedTag
resp, err := s.client.Do(req, &p)
if err != nil {
return nil, resp, err
}
return p, resp, err
}
// GetProtectedTag returns a single protected tag or wildcard protected tag.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/protected_tags.html#get-a-single-protected-tag-or-wildcard-protected-tag
func (s *ProtectedTagsService) GetProtectedTag(pid interface{}, tag string, options ...OptionFunc) (*ProtectedTag, *Response, error) {
project, err := parseID(pid)
if err != nil {
return nil, nil, err
}
u := fmt.Sprintf("projects/%s/protected_tags/%s", url.QueryEscape(project), tag)
req, err := s.client.NewRequest("GET", u, nil, options)
if err != nil {
return nil, nil, err
}
p := new(ProtectedTag)
resp, err := s.client.Do(req, p)
if err != nil {
return nil, resp, err
}
return p, resp, err
}
// ProtectRepositoryTagsOptions represents available ProtectRepositoryTags() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/protected_tags.html#protect-repository-tags
type ProtectRepositoryTagsOptions struct {
Name string `url:"name,omitempty" json:"name,omitempty"`
CreateAccessLevel *AccessLevelValue `url:"create_access_level,omitempty" json:"create_access_level,omitempty"`
}
// ProtectRepositoryTags protects a single repository tag or several project repository tags using a wildcard protected tag.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/protected_tags.html#protect-repository-tags
func (s *ProtectedTagsService) ProtectRepositoryTags(pid interface{}, opt *ProtectRepositoryTagsOptions, options ...OptionFunc) (*ProtectedTag, *Response, error) {
project, err := parseID(pid)
if err != nil {
return nil, nil, err
}
u := fmt.Sprintf("projects/%s/protected_tags", url.QueryEscape(project))
req, err := s.client.NewRequest("POST", u, opt, options)
if err != nil {
return nil, nil, err
}
p := new(ProtectedTag)
resp, err := s.client.Do(req, p)
if err != nil {
return nil, resp, err
}
return p, resp, err
}
// UnprotectRepositoryTags unprotects the given protected tag or wildcard protected tag.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/protected_tags.html#unprotect-repository-tags
func (s *ProtectedTagsService) UnprotectRepositoryTags(pid interface{}, tag string, options ...OptionFunc) (*Response, error) {
project, err := parseID(pid)
if err != nil {
return nil, err
}
u := fmt.Sprintf("projects/%s/protected_tags/%s", url.QueryEscape(project), tag)
req, err := s.client.NewRequest("DELETE", u, nil, options)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}
package gitlab
import (
"fmt"
"net/http"
"testing"
"github.com/stretchr/testify/assert"
)
func TestListProtectedTags(t *testing.T) {
mux, server, client := setup()
defer teardown(server)
mux.HandleFunc("/api/v4/projects/1/protected_tags", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `[{"name":"1.0.0", "create_access_levels": [{"access_level": 40, "access_level_description": "Maintainers"}]},{"name":"*-release", "create_access_levels": [{"access_level": 30, "access_level_description": "Developers + Maintainers"}]}]`)
})
expected := []*ProtectedTag{
{
Name: "1.0.0",
CreateAccessLevels: []*TagAccessDescription{
{
AccessLevel: 40,
AccessLevelDescription: "Maintainers",
},
},
},
{
Name: "*-release",
CreateAccessLevels: []*TagAccessDescription{
{
AccessLevel: 30,
AccessLevelDescription: "Developers + Maintainers",
},
},
},
}
opt := &ListProtectedTagsOptions{}
tags, _, err := client.ProtectedTags.ListProtectedTags(1, opt)
assert.NoError(t, err, "failed to get response")
assert.Equal(t, expected, tags)
}
func TestListProtectedTags_WithServerError(t *testing.T) {
mux, server, client := setup()
defer teardown(server)
mux.HandleFunc("/api/v4/projects/1/protected_tags", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
w.WriteHeader(http.StatusInternalServerError)
})
opt := &ListProtectedTagsOptions{}
tags, resp, err := client.ProtectedTags.ListProtectedTags(1, opt)
assert.Error(t, err)
assert.Nil(t, tags)
assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
}
func TestGetProtectedTag(t *testing.T) {
mux, server, client := setup()
defer teardown(server)
tagName := "my-awesome-tag"
mux.HandleFunc(fmt.Sprintf("/api/v4/projects/1/protected_tags/%s", tagName), func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"name":"my-awesome-tag", "create_access_levels": [{"access_level": 30, "access_level_description": "Developers + Maintainers"}]}`)
})
expected := &ProtectedTag{
Name: tagName,
CreateAccessLevels: []*TagAccessDescription{
{
AccessLevel: 30,
AccessLevelDescription: "Developers + Maintainers",
},
},
}
tag, _, err := client.ProtectedTags.GetProtectedTag(1, tagName)
assert.NoError(t, err, "failed to get response")
assert.Equal(t, expected, tag)
}
func TestGetProtectedTag_WithServerError(t *testing.T) {
mux, server, client := setup()
defer teardown(server)
tagName := "my-awesome-tag"
mux.HandleFunc(fmt.Sprintf("/api/v4/projects/1/protected_tags/%s", tagName), func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
w.WriteHeader(http.StatusInternalServerError)
})
tag, resp, err := client.ProtectedTags.GetProtectedTag(1, tagName)
assert.Error(t, err)
assert.Nil(t, tag)
assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
}
func TestProtectRepositoryTags(t *testing.T) {
mux, server, client := setup()
defer teardown(server)
mux.HandleFunc("/api/v4/projects/1/protected_tags", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "POST")
fmt.Fprint(w, `{"name":"my-awesome-tag", "create_access_levels": [{"access_level": 30, "access_level_description": "Developers + Maintainers"}]}`)
})
expected := &ProtectedTag{
Name: "my-awesome-tag",
CreateAccessLevels: []*TagAccessDescription{
{
AccessLevel: 30,
AccessLevelDescription: "Developers + Maintainers",
},
},
}
opt := &ProtectRepositoryTagsOptions{Name: "my-awesome-tag", CreateAccessLevel: AccessLevel(30)}
tag, _, err := client.ProtectedTags.ProtectRepositoryTags(1, opt)
assert.NoError(t, err, "failed to get response")
assert.Equal(t, expected, tag)
}
func TestProtectRepositoryTags_WithServerError(t *testing.T) {
mux, server, client := setup()
defer teardown(server)
mux.HandleFunc("/api/v4/projects/1/protected_tags", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "POST")
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprint(w, `{"message":"some error"}`)
})
opt := &ProtectRepositoryTagsOptions{Name: "my-awesome-tag", CreateAccessLevel: AccessLevel(30)}
tag, resp, err := client.ProtectedTags.ProtectRepositoryTags(1, opt)
assert.Nil(t, tag)
assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
assert.Error(t, err)
}
func TestUnprotectRepositoryTags(t *testing.T) {
mux, server, client := setup()
defer teardown(server)
mux.HandleFunc("/api/v4/projects/1/protected_tags/my-awesome-tag", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
})
resp, err := client.ProtectedTags.UnprotectRepositoryTags(1, "my-awesome-tag")
assert.NoError(t, err, "failed to get response")
assert.Equal(t, http.StatusOK, resp.StatusCode)
}
func TestUnprotectRepositoryTags_WithServerError(t *testing.T) {
mux, server, client := setup()
defer teardown(server)
mux.HandleFunc("/api/v4/projects/1/protected_tags/my-awesome-tag", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprint(w, `{"message": "some error"}`)
})
resp, err := client.ProtectedTags.UnprotectRepositoryTags(1, "my-awesome-tag")
assert.Error(t, err)
assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment