Add org label management (#732)
All checks were successful
testing / Run govulncheck (push) Successful in 26s
testing / testing (push) Successful in 2m31s

Replace #717 Related to gitea/gitea-mcp#99 Reviewed-on: #732
This commit was merged in pull request #732.
This commit is contained in:
2025-10-16 22:06:13 +00:00
parent 77c08edde0
commit 060554f462

View File

@@ -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 {

View File

@@ -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{})

View File

@@ -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)

View File

@@ -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
View 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
View 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
View 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)
}