diff --git a/github/issues.go b/github/issues.go index 46aff2954bb..f35f2b566ae 100644 --- a/github/issues.go +++ b/github/issues.go @@ -299,6 +299,29 @@ func (s *IssuesService) Edit(ctx context.Context, owner string, repo string, num return i, resp, nil } +// Remove a milestone from an issue. +// +// This is a helper method to explicitly update an issue with a `null` milestone, thereby removing it. +// +// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/issues/#update-an-issue +func (s *IssuesService) RemoveMilestone(ctx context.Context, owner, repo string, issueNumber int) (*Issue, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/issues/%v", owner, repo, issueNumber) + req, err := s.client.NewRequest("PATCH", u, &struct { + Milestone *Milestone `json:"milestone"` + }{}) + if err != nil { + return nil, nil, err + } + + i := new(Issue) + resp, err := s.client.Do(ctx, req, i) + if err != nil { + return nil, resp, err + } + + return i, resp, nil +} + // LockIssueOptions specifies the optional parameters to the // IssuesService.Lock method. type LockIssueOptions struct { diff --git a/github/issues_test.go b/github/issues_test.go index 80bfb3ff6d2..3ed7390f5f6 100644 --- a/github/issues_test.go +++ b/github/issues_test.go @@ -345,6 +345,40 @@ func TestIssuesService_Edit(t *testing.T) { }) } +func TestIssuesService_RemoveMilestone(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + mux.HandleFunc("/repos/o/r/issues/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PATCH") + fmt.Fprint(w, `{"number":1}`) + }) + + ctx := context.Background() + issue, _, err := client.Issues.RemoveMilestone(ctx, "o", "r", 1) + if err != nil { + t.Errorf("Issues.RemoveMilestone returned error: %v", err) + } + + want := &Issue{Number: Int(1)} + if !cmp.Equal(issue, want) { + t.Errorf("Issues.RemoveMilestone returned %+v, want %+v", issue, want) + } + + const methodName = "RemoveMilestone" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Issues.RemoveMilestone(ctx, "\n", "\n", -1) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Issues.RemoveMilestone(ctx, "o", "r", 1) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + func TestIssuesService_Edit_invalidOwner(t *testing.T) { client, _, _, teardown := setup() defer teardown()