Add org label management (#732)
Replace #717 Related to gitea/gitea-mcp#99 Reviewed-on: #732
This commit was merged in pull request #732.
This commit is contained in:
@@ -8,147 +8,8 @@ import ( | ||||
"bytes" | ||||
"encoding/json" | ||||
"fmt" | ||||
"regexp" | ||||
"strings" | ||||
) | ||||
| ||||
// Label a label to an issue or a pr | ||||
type Label struct { | ||||
ID int64 `json:"id"` | ||||
Name string `json:"name"` | ||||
// example: 00aabb | ||||
Color string `json:"color"` | ||||
Description string `json:"description"` | ||||
Exclusive bool `json:"exclusive"` | ||||
URL string `json:"url"` | ||||
} | ||||
| ||||
// ListLabelsOptions options for listing repository's labels | ||||
type ListLabelsOptions struct { | ||||
ListOptions | ||||
} | ||||
| ||||
// ListRepoLabels list labels of one repository | ||||
func (c *Client) ListRepoLabels(owner, repo string, opt ListLabelsOptions) ([]*Label, *Response, error) { | ||||
if err := escapeValidatePathSegments(&owner, &repo); err != nil { | ||||
return nil, nil, err | ||||
} | ||||
opt.setDefaults() | ||||
labels := make([]*Label, 0, opt.PageSize) | ||||
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/labels?%s", owner, repo, opt.getURLQuery().Encode()), nil, nil, &labels) | ||||
return labels, resp, err | ||||
} | ||||
| ||||
// GetRepoLabel get one label of repository by repo it | ||||
func (c *Client) GetRepoLabel(owner, repo string, id int64) (*Label, *Response, error) { | ||||
if err := escapeValidatePathSegments(&owner, &repo); err != nil { | ||||
return nil, nil, err | ||||
} | ||||
label := new(Label) | ||||
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/labels/%d", owner, repo, id), nil, nil, label) | ||||
return label, resp, err | ||||
} | ||||
| ||||
// CreateLabelOption options for creating a label | ||||
type CreateLabelOption struct { | ||||
Name string `json:"name"` | ||||
// example: #00aabb | ||||
Color string `json:"color"` | ||||
Description string `json:"description"` | ||||
Exclusive bool `json:"exclusive"` | ||||
} | ||||
| ||||
// Validate the CreateLabelOption struct | ||||
func (opt CreateLabelOption) Validate() error { | ||||
aw, err := regexp.MatchString("^#?[0-9,a-f,A-F]{6}$", opt.Color) | ||||
if err != nil { | ||||
return err | ||||
} | ||||
if !aw { | ||||
return fmt.Errorf("invalid color format") | ||||
} | ||||
if len(strings.TrimSpace(opt.Name)) == 0 { | ||||
return fmt.Errorf("empty name not allowed") | ||||
} | ||||
return nil | ||||
} | ||||
| ||||
// CreateLabel create one label of repository | ||||
func (c *Client) CreateLabel(owner, repo string, opt CreateLabelOption) (*Label, *Response, error) { | ||||
if err := escapeValidatePathSegments(&owner, &repo); err != nil { | ||||
return nil, nil, err | ||||
} | ||||
if err := opt.Validate(); err != nil { | ||||
return nil, nil, err | ||||
} | ||||
if len(opt.Color) == 6 { | ||||
if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { | ||||
opt.Color = "#" + opt.Color | ||||
} | ||||
} | ||||
body, err := json.Marshal(&opt) | ||||
if err != nil { | ||||
return nil, nil, err | ||||
} | ||||
label := new(Label) | ||||
resp, err := c.getParsedResponse("POST", | ||||
fmt.Sprintf("/repos/%s/%s/labels", owner, repo), | ||||
jsonHeader, bytes.NewReader(body), label) | ||||
return label, resp, err | ||||
} | ||||
| ||||
// EditLabelOption options for editing a label | ||||
type EditLabelOption struct { | ||||
Name *string `json:"name"` | ||||
Color *string `json:"color"` | ||||
Description *string `json:"description"` | ||||
Exclusive *bool `json:"exclusive"` | ||||
} | ||||
| ||||
// Validate the EditLabelOption struct | ||||
func (opt EditLabelOption) Validate() error { | ||||
if opt.Color != nil { | ||||
aw, err := regexp.MatchString("^#?[0-9,a-f,A-F]{6}$", *opt.Color) | ||||
if err != nil { | ||||
return err | ||||
} | ||||
if !aw { | ||||
return fmt.Errorf("invalid color format") | ||||
} | ||||
} | ||||
if opt.Name != nil { | ||||
if len(strings.TrimSpace(*opt.Name)) == 0 { | ||||
return fmt.Errorf("empty name not allowed") | ||||
} | ||||
} | ||||
return nil | ||||
} | ||||
| ||||
// EditLabel modify one label with options | ||||
func (c *Client) EditLabel(owner, repo string, id int64, opt EditLabelOption) (*Label, *Response, error) { | ||||
if err := escapeValidatePathSegments(&owner, &repo); err != nil { | ||||
return nil, nil, err | ||||
} | ||||
if err := opt.Validate(); err != nil { | ||||
return nil, nil, err | ||||
} | ||||
body, err := json.Marshal(&opt) | ||||
if err != nil { | ||||
return nil, nil, err | ||||
} | ||||
label := new(Label) | ||||
resp, err := c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s/labels/%d", owner, repo, id), jsonHeader, bytes.NewReader(body), label) | ||||
return label, resp, err | ||||
} | ||||
| ||||
// DeleteLabel delete one label of repository by id | ||||
func (c *Client) DeleteLabel(owner, repo string, id int64) (*Response, error) { | ||||
if err := escapeValidatePathSegments(&owner, &repo); err != nil { | ||||
return nil, err | ||||
} | ||||
return c.doRequestWithStatusHandle("DELETE", fmt.Sprintf("/repos/%s/%s/labels/%d", owner, repo, id), nil, nil) | ||||
} | ||||
| ||||
// GetIssueLabels get labels of one issue via issue id | ||||
func (c *Client) GetIssueLabels(owner, repo string, index int64, opts ListLabelsOptions) ([]*Label, *Response, error) { | ||||
if err := escapeValidatePathSegments(&owner, &repo); err != nil { | ||||
| ||||
@@ -11,9 +11,9 @@ import ( | ||||
"github.com/stretchr/testify/assert" | ||||
) | ||||
| ||||
// TestLabels test label related func | ||||
func TestLabels(t *testing.T) { | ||||
log.Println("== TestLabels ==") | ||||
// TestIssueLabels test label related func | ||||
func TestIssueLabels(t *testing.T) { | ||||
log.Println("== TestIssueLabels ==") | ||||
c := newTestClient() | ||||
repo, err := createTestRepo(t, "LabelTestsRepo", c) | ||||
assert.NoError(t, err) | ||||
@@ -81,7 +81,10 @@ func TestLabels(t *testing.T) { | ||||
}, label) | ||||
labels, _, _ = c.ListRepoLabels(repo.Owner.UserName, repo.Name, ListLabelsOptions{ListOptions: ListOptions{PageSize: 3}}) | ||||
| ||||
createTestIssue(t, c, repo.Name, "test-issue", "", nil, nil, 0, []int64{label.ID}, false, false) | ||||
user, _, err := c.GetMyUserInfo() | ||||
assert.NoError(t, err) | ||||
| ||||
createTestIssue(t, c, user.UserName, repo.Name, "test-issue", "", nil, nil, 0, []int64{label.ID}, false, false) | ||||
issueIndex := int64(1) | ||||
| ||||
issueLabels, _, err := c.GetIssueLabels(repo.Owner.UserName, repo.Name, issueIndex, ListLabelsOptions{}) | ||||
| ||||
@@ -18,7 +18,9 @@ func TestIssueSubscription(t *testing.T) { | ||||
| ||||
c := newTestClient() | ||||
repo, _ := createTestRepo(t, "IssueWatch", c) | ||||
createTestIssue(t, c, repo.Name, "First Issue", "", nil, nil, 0, nil, false, false) | ||||
user, _, err := c.GetMyUserInfo() | ||||
assert.NoError(t, err) | ||||
createTestIssue(t, c, user.UserName, repo.Name, "First Issue", "", nil, nil, 0, nil, false, false) | ||||
| ||||
wi, _, err := c.CheckIssueSubscription(repo.Owner.UserName, repo.Name, 1) | ||||
assert.NoError(t, err) | ||||
| ||||
@@ -37,15 +37,15 @@ func createIssue(t *testing.T, c *Client) { | ||||
label1, _, _ := c.CreateLabel(user.UserName, repo.Name, CreateLabelOption{Name: "Label1", Description: "a", Color: "#ee0701"}) | ||||
label2, _, _ := c.CreateLabel(user.UserName, repo.Name, CreateLabelOption{Name: "Label2", Description: "b", Color: "#128a0c"}) | ||||
| ||||
createTestIssue(t, c, repo.Name, "First Issue", "", nil, nil, 0, nil, false, false) | ||||
createTestIssue(t, c, repo.Name, "Issue 2", "closed isn't it?", nil, nil, 0, nil, true, false) | ||||
createTestIssue(t, c, repo.Name, "Issue 3", "", nil, nil, 0, nil, true, false) | ||||
createTestIssue(t, c, repo.Name, "Feature: spam protect 4", "explain explain explain", []string{user.UserName}, &nowTime, 0, nil, true, false) | ||||
createTestIssue(t, c, repo.Name, "W 123", "", nil, &nowTime, mile.ID, nil, false, false) | ||||
createTestIssue(t, c, repo.Name, "First Issue", "", nil, nil, 0, nil, false, false) | ||||
createTestIssue(t, c, repo.Name, "Do it soon!", "is important!", []string{user.UserName}, &nowTime, mile.ID, []int64{label1.ID, label2.ID}, false, false) | ||||
createTestIssue(t, c, repo.Name, "Job Done", "you never know", nil, nil, mile.ID, []int64{label2.ID}, true, false) | ||||
createTestIssue(t, c, repo.Name, "", "you never know", nil, nil, mile.ID, nil, true, true) | ||||
createTestIssue(t, c, user.UserName, repo.Name, "First Issue", "", nil, nil, 0, nil, false, false) | ||||
createTestIssue(t, c, user.UserName, repo.Name, "Issue 2", "closed isn't it?", nil, nil, 0, nil, true, false) | ||||
createTestIssue(t, c, user.UserName, repo.Name, "Issue 3", "", nil, nil, 0, nil, true, false) | ||||
createTestIssue(t, c, user.UserName, repo.Name, "Feature: spam protect 4", "explain explain explain", []string{user.UserName}, &nowTime, 0, nil, true, false) | ||||
createTestIssue(t, c, user.UserName, repo.Name, "W 123", "", nil, &nowTime, mile.ID, nil, false, false) | ||||
createTestIssue(t, c, user.UserName, repo.Name, "First Issue", "", nil, nil, 0, nil, false, false) | ||||
createTestIssue(t, c, user.UserName, repo.Name, "Do it soon!", "is important!", []string{user.UserName}, &nowTime, mile.ID, []int64{label1.ID, label2.ID}, false, false) | ||||
createTestIssue(t, c, user.UserName, repo.Name, "Job Done", "you never know", nil, nil, mile.ID, []int64{label2.ID}, true, false) | ||||
createTestIssue(t, c, user.UserName, repo.Name, "", "you never know", nil, nil, mile.ID, nil, true, true) | ||||
} | ||||
| ||||
func deleteIssue(t *testing.T, c *Client) { | ||||
@@ -55,7 +55,7 @@ func deleteIssue(t *testing.T, c *Client) { | ||||
assert.NoError(t, err) | ||||
repo, _ := createTestRepo(t, "IssueTestsRepo", c) | ||||
| ||||
issue := createTestIssue(t, c, repo.Name, "Deleteable Issue", "", nil, nil, 0, nil, false, false) | ||||
issue := createTestIssue(t, c, user.UserName, repo.Name, "Deleteable Issue", "", nil, nil, 0, nil, false, false) | ||||
_, err = c.DeleteIssue(user.UserName, repo.Name, issue.Index) | ||||
assert.NoError(t, err) | ||||
} | ||||
@@ -118,10 +118,8 @@ func listIssues(t *testing.T, c *Client) { | ||||
assert.Len(t, issues, 3) | ||||
} | ||||
| ||||
func createTestIssue(t *testing.T, c *Client, repoName, title, body string, assignees []string, deadline *time.Time, milestone int64, labels []int64, closed, shouldFail bool) *Issue { | ||||
user, _, err := c.GetMyUserInfo() | ||||
assert.NoError(t, err) | ||||
issue, _, e := c.CreateIssue(user.UserName, repoName, CreateIssueOption{ | ||||
func createTestIssue(t *testing.T, c *Client, userName, repoName, title, body string, assignees []string, deadline *time.Time, milestone int64, labels []int64, closed, shouldFail bool) *Issue { | ||||
issue, _, e := c.CreateIssue(userName, repoName, CreateIssueOption{ | ||||
Title: title, | ||||
Body: body, | ||||
Assignees: assignees, | ||||
| ||||
116 gitea/org_label.go Normal file
116
gitea/org_label.go Normal file @@ -0,0 +1,116 @@ | ||||
// Copyright 2025 The Gitea Authors. All rights reserved. | ||||
// Use of this source code is governed by a MIT-style | ||||
// license that can be found in the LICENSE file. | ||||
| ||||
package gitea | ||||
| ||||
import ( | ||||
"bytes" | ||||
"encoding/json" | ||||
"fmt" | ||||
"net/url" | ||||
"regexp" | ||||
"strings" | ||||
) | ||||
| ||||
// ListOrgLabelsOptions options for listing organization labels | ||||
type ListOrgLabelsOptions struct { | ||||
ListOptions | ||||
} | ||||
| ||||
// ListOrgLabels returns the labels defined at the org level | ||||
func (c *Client) ListOrgLabels(orgName string, opt ListOrgLabelsOptions) ([]*Label, *Response, error) { | ||||
if err := escapeValidatePathSegments(&orgName); err != nil { | ||||
return nil, nil, err | ||||
} | ||||
opt.setDefaults() | ||||
labels := make([]*Label, 0, opt.PageSize) | ||||
link, _ := url.Parse(fmt.Sprintf("/orgs/%s/labels", orgName)) | ||||
link.RawQuery = opt.getURLQuery().Encode() | ||||
resp, err := c.getParsedResponse("GET", link.String(), jsonHeader, nil, &labels) | ||||
return labels, resp, err | ||||
} | ||||
| ||||
type CreateOrgLabelOption struct { | ||||
// Name of the label | ||||
Name string `json:"name"` | ||||
// Color of the label in hex format without # | ||||
Color string `json:"color"` | ||||
// Description of the label | ||||
Description string `json:"description"` | ||||
// Whether this is an exclusive label | ||||
Exclusive bool `json:"exclusive"` | ||||
} | ||||
| ||||
// Validate the CreateLabelOption struct | ||||
func (opt CreateOrgLabelOption) Validate() error { | ||||
aw, err := regexp.MatchString("^#?[0-9,a-f,A-F]{6}$", opt.Color) | ||||
if err != nil { | ||||
return err | ||||
} | ||||
if !aw { | ||||
return fmt.Errorf("invalid color format") | ||||
} | ||||
if len(strings.TrimSpace(opt.Name)) == 0 { | ||||
return fmt.Errorf("empty name not allowed") | ||||
} | ||||
return nil | ||||
} | ||||
| ||||
// CreateOrgLabel creates a new label under an organization | ||||
func (c *Client) CreateOrgLabel(orgName string, opt CreateOrgLabelOption) (*Label, *Response, error) { | ||||
if err := escapeValidatePathSegments(&orgName); err != nil { | ||||
return nil, nil, err | ||||
} | ||||
body, err := json.Marshal(&opt) | ||||
if err != nil { | ||||
return nil, nil, err | ||||
} | ||||
label := new(Label) | ||||
resp, err := c.getParsedResponse("POST", fmt.Sprintf("/orgs/%s/labels", orgName), jsonHeader, bytes.NewReader(body), label) | ||||
return label, resp, err | ||||
} | ||||
| ||||
// GetOrgLabel get one label of organization by org it | ||||
func (c *Client) GetOrgLabel(orgName string, labelID int64) (*Label, *Response, error) { | ||||
if err := escapeValidatePathSegments(&orgName); err != nil { | ||||
return nil, nil, err | ||||
} | ||||
label := new(Label) | ||||
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/orgs/%s/labels/%d", orgName, labelID), nil, nil, label) | ||||
return label, resp, err | ||||
} | ||||
| ||||
type EditOrgLabelOption struct { | ||||
// New name of the label | ||||
Name *string `json:"name"` | ||||
// New color of the label in hex format without # | ||||
Color *string `json:"color"` | ||||
// New description of the label | ||||
Description *string `json:"description"` | ||||
// Whether this is an exclusive label | ||||
Exclusive *bool `json:"exclusive,omitempty"` | ||||
} | ||||
| ||||
// EditOrgLabel edits an existing org-level label by ID | ||||
func (c *Client) EditOrgLabel(orgName string, labelID int64, opt EditOrgLabelOption) (*Label, *Response, error) { | ||||
if err := escapeValidatePathSegments(&orgName); err != nil { | ||||
return nil, nil, err | ||||
} | ||||
body, err := json.Marshal(&opt) | ||||
if err != nil { | ||||
return nil, nil, err | ||||
} | ||||
label := new(Label) | ||||
resp, err := c.getParsedResponse("PATCH", fmt.Sprintf("/orgs/%s/labels/%d", orgName, labelID), jsonHeader, bytes.NewReader(body), label) | ||||
return label, resp, err | ||||
} | ||||
| ||||
// DeleteOrgLabel deletes a org label by ID | ||||
func (c *Client) DeleteOrgLabel(orgName string, labelID int64) (*Response, error) { | ||||
if err := escapeValidatePathSegments(&orgName); err != nil { | ||||
return nil, err | ||||
} | ||||
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/orgs/%s/labels/%d", orgName, labelID), jsonHeader, nil) | ||||
return resp, err | ||||
} | ||||
124 gitea/org_label_test.go Normal file
124
gitea/org_label_test.go Normal file @@ -0,0 +1,124 @@ | ||||
// Copyright 2020 The Gitea Authors. All rights reserved. | ||||
// Use of this source code is governed by a MIT-style | ||||
// license that can be found in the LICENSE file. | ||||
| ||||
package gitea | ||||
| ||||
import ( | ||||
"log" | ||||
"testing" | ||||
| ||||
"github.com/stretchr/testify/assert" | ||||
) | ||||
| ||||
// TestOrgLabels test label related func | ||||
func TestOrgLabels(t *testing.T) { | ||||
log.Println("== TestOrgLabels ==") | ||||
c := newTestClient() | ||||
orgCleanup, orgRepo, err := createTestOrgRepo(t, c, "LabelTestsOrg") | ||||
assert.NoError(t, err) | ||||
defer orgCleanup() | ||||
| ||||
org := orgRepo.Owner | ||||
| ||||
createOpts := CreateOrgLabelOption{ | ||||
Name: " ", | ||||
Description: "", | ||||
Color: "", | ||||
} | ||||
err = createOpts.Validate() | ||||
assert.Error(t, err) | ||||
assert.EqualValues(t, "invalid color format", err.Error()) | ||||
createOpts.Color = "12345f" | ||||
err = createOpts.Validate() | ||||
assert.Error(t, err) | ||||
assert.EqualValues(t, "empty name not allowed", err.Error()) | ||||
createOpts.Name = "label one" | ||||
| ||||
labelOne, _, err := c.CreateOrgLabel(org.UserName, createOpts) | ||||
assert.NoError(t, err) | ||||
assert.EqualValues(t, createOpts.Name, labelOne.Name) | ||||
assert.EqualValues(t, createOpts.Color, labelOne.Color) | ||||
| ||||
labelTwo, _, err := c.CreateOrgLabel(org.UserName, CreateOrgLabelOption{ | ||||
Name: "blue", | ||||
Color: "#0000FF", | ||||
Description: "CMYB(100%, 100%, 0%, 0%)", | ||||
}) | ||||
assert.NoError(t, err) | ||||
_, _, err = c.CreateOrgLabel(org.UserName, CreateOrgLabelOption{ | ||||
Name: "gray", | ||||
Color: "808080", | ||||
Description: "CMYB(0%, 0%, 0%, 50%)", | ||||
}) | ||||
assert.NoError(t, err) | ||||
_, _, err = c.CreateOrgLabel(org.UserName, CreateOrgLabelOption{ | ||||
Name: "green", | ||||
Color: "#98F76C", | ||||
Description: "CMYB(38%, 0%, 56%, 3%)", | ||||
}) | ||||
assert.NoError(t, err) | ||||
| ||||
labels, resp, err := c.ListOrgLabels(org.UserName, ListOrgLabelsOptions{ListOptions: ListOptions{PageSize: 3}}) | ||||
assert.NoError(t, err) | ||||
assert.Len(t, labels, 3) | ||||
assert.NotNil(t, resp) | ||||
assert.Contains(t, labels, labelTwo) | ||||
assert.NotContains(t, labels, labelOne) | ||||
| ||||
label, _, err := c.GetOrgLabel(org.UserName, labelTwo.ID) | ||||
assert.NoError(t, err) | ||||
assert.EqualValues(t, labelTwo, label) | ||||
| ||||
label, _, err = c.EditOrgLabel(org.UserName, labelTwo.ID, EditOrgLabelOption{ | ||||
Color: OptionalString("#0e0175"), | ||||
Description: OptionalString("blueish"), | ||||
}) | ||||
assert.NoError(t, err) | ||||
assert.EqualValues(t, &Label{ | ||||
ID: labelTwo.ID, | ||||
Name: labelTwo.Name, | ||||
Color: "0e0175", | ||||
Description: "blueish", | ||||
URL: labelTwo.URL, | ||||
}, label) | ||||
labels, _, _ = c.ListOrgLabels(org.UserName, ListOrgLabelsOptions{ListOptions: ListOptions{PageSize: 3}}) | ||||
| ||||
createTestIssue(t, c, org.UserName, orgRepo.Name, "test-issue", "", nil, nil, 0, []int64{label.ID}, false, false) | ||||
issueIndex := int64(1) | ||||
| ||||
issueLabels, _, err := c.GetIssueLabels(orgRepo.Owner.UserName, orgRepo.Name, issueIndex, ListLabelsOptions{}) | ||||
assert.NoError(t, err) | ||||
assert.Len(t, issueLabels, 1) | ||||
assert.EqualValues(t, label, issueLabels[0]) | ||||
| ||||
_, _, err = c.AddIssueLabels(orgRepo.Owner.UserName, orgRepo.Name, issueIndex, IssueLabelsOption{Labels: []int64{labels[0].ID}}) | ||||
assert.NoError(t, err) | ||||
| ||||
issueLabels, _, err = c.AddIssueLabels(orgRepo.Owner.UserName, orgRepo.Name, issueIndex, IssueLabelsOption{Labels: []int64{labels[1].ID, labels[2].ID}}) | ||||
assert.NoError(t, err) | ||||
assert.Len(t, issueLabels, 3) | ||||
assert.EqualValues(t, labels, issueLabels) | ||||
| ||||
labels, _, _ = c.ListRepoLabels(orgRepo.Owner.UserName, orgRepo.Name, ListLabelsOptions{}) | ||||
assert.Len(t, labels, 7) | ||||
| ||||
issueLabels, _, err = c.ReplaceIssueLabels(orgRepo.Owner.UserName, orgRepo.Name, issueIndex, IssueLabelsOption{Labels: []int64{labels[0].ID, labels[1].ID}}) | ||||
assert.NoError(t, err) | ||||
assert.Len(t, issueLabels, 2) | ||||
| ||||
_, err = c.DeleteIssueLabel(orgRepo.Owner.UserName, orgRepo.Name, issueIndex, labels[0].ID) | ||||
assert.NoError(t, err) | ||||
issueLabels, _, _ = c.GetIssueLabels(orgRepo.Owner.UserName, orgRepo.Name, issueIndex, ListLabelsOptions{}) | ||||
assert.Len(t, issueLabels, 1) | ||||
| ||||
_, err = c.ClearIssueLabels(orgRepo.Owner.UserName, orgRepo.Name, issueIndex) | ||||
assert.NoError(t, err) | ||||
issueLabels, _, _ = c.GetIssueLabels(orgRepo.Owner.UserName, orgRepo.Name, issueIndex, ListLabelsOptions{}) | ||||
assert.Len(t, issueLabels, 0) | ||||
| ||||
_, err = c.DeleteOrgLabel(org.UserName, labelTwo.ID) | ||||
assert.NoError(t, err) | ||||
labels, _, _ = c.ListOrgLabels(org.UserName, ListOrgLabelsOptions{}) | ||||
assert.Len(t, labels, 3) | ||||
} | ||||
150 gitea/repo_label.go Normal file
150
gitea/repo_label.go Normal file @@ -0,0 +1,150 @@ | ||||
// Copyright 2016 The Gogs Authors. All rights reserved. | ||||
// Use of this source code is governed by a MIT-style | ||||
// license that can be found in the LICENSE file. | ||||
| ||||
package gitea | ||||
| ||||
import ( | ||||
"bytes" | ||||
"encoding/json" | ||||
"fmt" | ||||
"regexp" | ||||
"strings" | ||||
) | ||||
| ||||
// Label a label to an issue or a pr | ||||
type Label struct { | ||||
ID int64 `json:"id"` | ||||
Name string `json:"name"` | ||||
// example: 00aabb | ||||
Color string `json:"color"` | ||||
Description string `json:"description"` | ||||
Exclusive bool `json:"exclusive"` | ||||
URL string `json:"url"` | ||||
} | ||||
| ||||
// ListLabelsOptions options for listing repository's labels | ||||
type ListLabelsOptions struct { | ||||
ListOptions | ||||
} | ||||
| ||||
// ListRepoLabels list labels of one repository | ||||
func (c *Client) ListRepoLabels(owner, repo string, opt ListLabelsOptions) ([]*Label, *Response, error) { | ||||
if err := escapeValidatePathSegments(&owner, &repo); err != nil { | ||||
return nil, nil, err | ||||
} | ||||
opt.setDefaults() | ||||
labels := make([]*Label, 0, opt.PageSize) | ||||
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/labels?%s", owner, repo, opt.getURLQuery().Encode()), nil, nil, &labels) | ||||
return labels, resp, err | ||||
} | ||||
| ||||
// GetRepoLabel get one label of repository by repo it | ||||
func (c *Client) GetRepoLabel(owner, repo string, id int64) (*Label, *Response, error) { | ||||
if err := escapeValidatePathSegments(&owner, &repo); err != nil { | ||||
return nil, nil, err | ||||
} | ||||
label := new(Label) | ||||
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/labels/%d", owner, repo, id), nil, nil, label) | ||||
return label, resp, err | ||||
} | ||||
| ||||
// CreateLabelOption options for creating a label | ||||
type CreateLabelOption struct { | ||||
Name string `json:"name"` | ||||
// example: #00aabb | ||||
Color string `json:"color"` | ||||
Description string `json:"description"` | ||||
Exclusive bool `json:"exclusive"` | ||||
} | ||||
| ||||
// Validate the CreateLabelOption struct | ||||
func (opt CreateLabelOption) Validate() error { | ||||
aw, err := regexp.MatchString("^#?[0-9,a-f,A-F]{6}$", opt.Color) | ||||
if err != nil { | ||||
return err | ||||
} | ||||
if !aw { | ||||
return fmt.Errorf("invalid color format") | ||||
} | ||||
if len(strings.TrimSpace(opt.Name)) == 0 { | ||||
return fmt.Errorf("empty name not allowed") | ||||
} | ||||
return nil | ||||
} | ||||
| ||||
// CreateLabel create one label of repository | ||||
func (c *Client) CreateLabel(owner, repo string, opt CreateLabelOption) (*Label, *Response, error) { | ||||
if err := escapeValidatePathSegments(&owner, &repo); err != nil { | ||||
return nil, nil, err | ||||
} | ||||
if err := opt.Validate(); err != nil { | ||||
return nil, nil, err | ||||
} | ||||
if len(opt.Color) == 6 { | ||||
if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { | ||||
opt.Color = "#" + opt.Color | ||||
} | ||||
} | ||||
body, err := json.Marshal(&opt) | ||||
if err != nil { | ||||
return nil, nil, err | ||||
} | ||||
label := new(Label) | ||||
resp, err := c.getParsedResponse("POST", | ||||
fmt.Sprintf("/repos/%s/%s/labels", owner, repo), | ||||
jsonHeader, bytes.NewReader(body), label) | ||||
return label, resp, err | ||||
} | ||||
| ||||
// EditLabelOption options for editing a label | ||||
type EditLabelOption struct { | ||||
Name *string `json:"name"` | ||||
Color *string `json:"color"` | ||||
Description *string `json:"description"` | ||||
Exclusive *bool `json:"exclusive"` | ||||
} | ||||
| ||||
// Validate the EditLabelOption struct | ||||
func (opt EditLabelOption) Validate() error { | ||||
if opt.Color != nil { | ||||
aw, err := regexp.MatchString("^#?[0-9,a-f,A-F]{6}$", *opt.Color) | ||||
if err != nil { | ||||
return err | ||||
} | ||||
if !aw { | ||||
return fmt.Errorf("invalid color format") | ||||
} | ||||
} | ||||
if opt.Name != nil { | ||||
if len(strings.TrimSpace(*opt.Name)) == 0 { | ||||
return fmt.Errorf("empty name not allowed") | ||||
} | ||||
} | ||||
return nil | ||||
} | ||||
| ||||
// EditLabel modify one label with options | ||||
func (c *Client) EditLabel(owner, repo string, id int64, opt EditLabelOption) (*Label, *Response, error) { | ||||
if err := escapeValidatePathSegments(&owner, &repo); err != nil { | ||||
return nil, nil, err | ||||
} | ||||
if err := opt.Validate(); err != nil { | ||||
return nil, nil, err | ||||
} | ||||
body, err := json.Marshal(&opt) | ||||
if err != nil { | ||||
return nil, nil, err | ||||
} | ||||
label := new(Label) | ||||
resp, err := c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s/labels/%d", owner, repo, id), jsonHeader, bytes.NewReader(body), label) | ||||
return label, resp, err | ||||
} | ||||
| ||||
// DeleteLabel delete one label of repository by id | ||||
func (c *Client) DeleteLabel(owner, repo string, id int64) (*Response, error) { | ||||
if err := escapeValidatePathSegments(&owner, &repo); err != nil { | ||||
return nil, err | ||||
} | ||||
return c.doRequestWithStatusHandle("DELETE", fmt.Sprintf("/repos/%s/%s/labels/%d", owner, repo, id), nil, nil) | ||||
} | ||||
Reference in New Issue
Block a user