fix(api): keep milestone due date when it is omitted in edit request (#39869)

`PATCH /repos/{owner}/{repo}/milestones/{id}` always overwrote the due
date with `due_on`, so a request that only changed other fields, such as
`{"state": "closed"}`, silently removed it.

The due date is now kept when `due_on` is omitted, and `"due_on": null`
or `"due_on": ""` remove it.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
Shudhanshu Singhandwxiaoguang authored and GitHub committed 2026-10-21 18:52:33 +08:00
1 parent b5e53210c2
commit a8e1057f5e
15 files changed
+192 -74

No files matched your search

@@ -41,6 +41,7 @@ func TestAPIIssuesMilestone(t *testing.T) {
resp := MakeRequest(t, req, http.StatusOK)
apiMilestone := DecodeJSON(t, resp, &structs.Milestone{})
assert.EqualValues(t, "closed", apiMilestone.State)
assert.NotNil(t, apiMilestone.Deadline, "an omitted due_on keeps the due date")
req = NewRequest(t, "GET", urlStr).
AddTokenAuth(token)
@@ -48,6 +49,10 @@ func TestAPIIssuesMilestone(t *testing.T) {
apiMilestone2 := DecodeJSON(t, resp, &structs.Milestone{})
assert.EqualValues(t, "closed", apiMilestone2.State)
req = NewRequestWithJSON(t, "PATCH", urlStr, map[string]any{"due_on": ""}).AddTokenAuth(token)
resp = MakeRequest(t, req, http.StatusOK)
assert.Nil(t, DecodeJSON(t, resp, &structs.Milestone{}).Deadline)
req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/milestones", owner.Name, repo.Name), structs.CreateMilestoneOption{
Title: "wow",
Description: "closed one",
+2 -1
View File
@@ -18,6 +18,7 @@ import (
repo_model "gitea.dev/models/repo"
"gitea.dev/models/unittest"
user_model "gitea.dev/models/user"
"gitea.dev/modules/optional"
"gitea.dev/modules/setting"
api "gitea.dev/modules/structs"
"gitea.dev/modules/test"
@@ -126,7 +127,7 @@ func testAPICreateIssue(t *testing.T) {
Body: body,
Title: title,
Assignee: owner.Name,
Deadline: new(time.Date(2026, 5, 11, 12, 0, 0, 0, time.FixedZone("", -10*3600))),
Deadline: optional.Some(new("2026-05-11T12:00:00-10:00")),
}).AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusCreated)
apiIssue := DecodeJSON(t, resp, &api.Issue{})
+16 -5
View File
@@ -20,6 +20,7 @@ import (
unit_model "gitea.dev/models/unit"
"gitea.dev/models/unittest"
user_model "gitea.dev/models/user"
"gitea.dev/modules/optional"
"gitea.dev/modules/setting"
api "gitea.dev/modules/structs"
"gitea.dev/modules/util"
@@ -491,7 +492,7 @@ func TestAPIEditPull(t *testing.T) {
Head: "develop",
Base: "master",
Title: title,
Deadline: new(time.Date(2026, 5, 11, 12, 0, 0, 0, time.FixedZone("", -10*3600))),
Deadline: optional.Some(new("2026-05-11T12:00:00-10:00")),
}).AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusCreated)
apiPull := DecodeJSON(t, resp, &api.PullRequest{})
@@ -521,10 +522,20 @@ func TestAPIEditPull(t *testing.T) {
}).AddTokenAuth(token)
MakeRequest(t, req, http.StatusNotFound)
req = NewRequestWithJSON(t, http.MethodPatch, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d", owner10.Name, repo10.Name, pull.Index), &api.EditPullRequestOption{
RemoveDeadline: new(false),
}).AddTokenAuth(token)
MakeRequest(t, req, http.StatusBadRequest)
req = NewRequestWithJSON(t, http.MethodPatch, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d", owner10.Name, repo10.Name, pull.Index), map[string]any{"due_date": "2000-01-02"}).AddTokenAuth(token)
MakeRequest(t, req, http.StatusCreated)
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: pull.IssueID})
assert.NotZero(t, issue.DeadlineUnix)
req = NewRequestWithJSON(t, http.MethodPatch, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d", owner10.Name, repo10.Name, pull.Index), map[string]any{}).AddTokenAuth(token)
MakeRequest(t, req, http.StatusCreated)
issue = unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: pull.IssueID})
assert.NotZero(t, issue.DeadlineUnix)
req = NewRequestWithJSON(t, http.MethodPatch, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d", owner10.Name, repo10.Name, pull.Index), map[string]any{"due_date": nil}).AddTokenAuth(token)
MakeRequest(t, req, http.StatusCreated)
issue = unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: pull.IssueID})
assert.Zero(t, issue.DeadlineUnix)
t.Run("PullContentVersion", func(t *testing.T) {
testAPIPullContentVersion(t, pull.ID)