Skip to content

Commit 24b83ff

Browse files
lunnywxiaoguangGiteaBot
authored
Fix milestone deadline and date related problems (#32339)
Use zero instead of 9999-12-31 for deadline Fix #32291 --------- Co-authored-by: wxiaoguang <[email protected]> Co-authored-by: Giteabot <[email protected]>
1 parent 1887c75 commit 24b83ff

File tree

23 files changed

+147
-165
lines changed

23 files changed

+147
-165
lines changed

Diff for: models/actions/schedule_spec_test.go

+3-5
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,17 @@ import (
77
"testing"
88
"time"
99

10+
"code.gitea.io/gitea/modules/test"
11+
1012
"github.com/stretchr/testify/assert"
1113
"github.com/stretchr/testify/require"
1214
)
1315

1416
func TestActionScheduleSpec_Parse(t *testing.T) {
1517
// Mock the local timezone is not UTC
16-
local := time.Local
1718
tz, err := time.LoadLocation("Asia/Shanghai")
1819
require.NoError(t, err)
19-
defer func() {
20-
time.Local = local
21-
}()
22-
time.Local = tz
20+
defer test.MockVariableValue(&time.Local, tz)()
2321

2422
now, err := time.Parse(time.RFC3339, "2024-07-31T15:47:55+08:00")
2523
require.NoError(t, err)

Diff for: models/issues/milestone.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,9 @@ func (m *Milestone) BeforeUpdate() {
8484
// this object.
8585
func (m *Milestone) AfterLoad() {
8686
m.NumOpenIssues = m.NumIssues - m.NumClosedIssues
87-
if m.DeadlineUnix.Year() == 9999 {
87+
if m.DeadlineUnix == 0 {
8888
return
8989
}
90-
9190
m.DeadlineString = m.DeadlineUnix.FormatDate()
9291
if m.IsClosed {
9392
m.IsOverdue = m.ClosedDateUnix >= m.DeadlineUnix

Diff for: models/migrations/migrations.go

+1
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,7 @@ func prepareMigrationTasks() []*migration {
364364
newMigration(304, "Add index for release sha1", v1_23.AddIndexForReleaseSha1),
365365
newMigration(305, "Add Repository Licenses", v1_23.AddRepositoryLicenses),
366366
newMigration(306, "Add BlockAdminMergeOverride to ProtectedBranch", v1_23.AddBlockAdminMergeOverrideBranchProtection),
367+
newMigration(307, "Fix milestone deadline_unix when there is no due date", v1_23.FixMilestoneNoDueDate),
367368
}
368369
return preparedMigrations
369370
}

Diff for: models/migrations/v1_23/v307.go

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2024 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package v1_23 //nolint
5+
6+
import (
7+
"code.gitea.io/gitea/modules/timeutil"
8+
9+
"xorm.io/xorm"
10+
)
11+
12+
func FixMilestoneNoDueDate(x *xorm.Engine) error {
13+
type Milestone struct {
14+
DeadlineUnix timeutil.TimeStamp
15+
}
16+
// Wednesday, December 1, 9999 12:00:00 AM GMT+00:00
17+
_, err := x.Table("milestone").Where("deadline_unix > 253399622400").
18+
Cols("deadline_unix").
19+
Update(&Milestone{DeadlineUnix: 0})
20+
return err
21+
}

Diff for: modules/gitgraph/graph.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func GetCommitGraph(r *git.Repository, page, maxAllowedColors int, hidePRRefs bo
3232
graphCmd.AddArguments("--all")
3333
}
3434

35-
graphCmd.AddArguments("-C", "-M", "--date=iso").
35+
graphCmd.AddArguments("-C", "-M", "--date=iso-strict").
3636
AddOptionFormat("-n %d", setting.UI.GraphMaxCommitNum*page).
3737
AddOptionFormat("--pretty=format:%s", format)
3838

Diff for: modules/gitgraph/graph_models.go

+11-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"context"
99
"fmt"
1010
"strings"
11+
"time"
1112

1213
asymkey_model "code.gitea.io/gitea/models/asymkey"
1314
"code.gitea.io/gitea/models/db"
@@ -192,6 +193,14 @@ var RelationCommit = &Commit{
192193
Row: -1,
193194
}
194195

196+
func parseGitTime(timeStr string) time.Time {
197+
t, err := time.Parse(time.RFC3339, timeStr)
198+
if err != nil {
199+
return time.Unix(0, 0)
200+
}
201+
return t
202+
}
203+
195204
// NewCommit creates a new commit from a provided line
196205
func NewCommit(row, column int, line []byte) (*Commit, error) {
197206
data := bytes.SplitN(line, []byte("|"), 5)
@@ -206,7 +215,7 @@ func NewCommit(row, column int, line []byte) (*Commit, error) {
206215
// 1 matches git log --pretty=format:%H => commit hash
207216
Rev: string(data[1]),
208217
// 2 matches git log --pretty=format:%ad => author date (format respects --date= option)
209-
Date: string(data[2]),
218+
Date: parseGitTime(string(data[2])),
210219
// 3 matches git log --pretty=format:%h => abbreviated commit hash
211220
ShortRev: string(data[3]),
212221
// 4 matches git log --pretty=format:%s => subject
@@ -245,7 +254,7 @@ type Commit struct {
245254
Column int
246255
Refs []git.Reference
247256
Rev string
248-
Date string
257+
Date time.Time
249258
ShortRev string
250259
Subject string
251260
}

Diff for: modules/templates/util_date.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func (du *DateUtils) AbsoluteShort(time any) template.HTML {
2727

2828
// AbsoluteLong renders in "January 01, 2006" format
2929
func (du *DateUtils) AbsoluteLong(time any) template.HTML {
30-
return dateTimeFormat("short", time)
30+
return dateTimeFormat("long", time)
3131
}
3232

3333
// FullTime renders in "Jan 01, 2006 20:33:44" format

Diff for: routers/api/v1/repo/issue.go

+3-9
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"code.gitea.io/gitea/modules/timeutil"
2727
"code.gitea.io/gitea/modules/web"
2828
"code.gitea.io/gitea/routers/api/v1/utils"
29+
"code.gitea.io/gitea/routers/common"
2930
"code.gitea.io/gitea/services/context"
3031
"code.gitea.io/gitea/services/convert"
3132
issue_service "code.gitea.io/gitea/services/issue"
@@ -1046,18 +1047,11 @@ func UpdateIssueDeadline(ctx *context.APIContext) {
10461047
return
10471048
}
10481049

1049-
var deadlineUnix timeutil.TimeStamp
1050-
var deadline time.Time
1051-
if form.Deadline != nil && !form.Deadline.IsZero() {
1052-
deadline = time.Date(form.Deadline.Year(), form.Deadline.Month(), form.Deadline.Day(),
1053-
23, 59, 59, 0, time.Local)
1054-
deadlineUnix = timeutil.TimeStamp(deadline.Unix())
1055-
}
1056-
1050+
deadlineUnix, _ := common.ParseAPIDeadlineToEndOfDay(form.Deadline)
10571051
if err := issues_model.UpdateIssueDeadline(ctx, issue, deadlineUnix, ctx.Doer); err != nil {
10581052
ctx.Error(http.StatusInternalServerError, "UpdateIssueDeadline", err)
10591053
return
10601054
}
10611055

1062-
ctx.JSON(http.StatusCreated, api.IssueDeadline{Deadline: &deadline})
1056+
ctx.JSON(http.StatusCreated, api.IssueDeadline{Deadline: deadlineUnix.AsTimePtr()})
10631057
}

Diff for: routers/api/v1/repo/milestone.go

+6-8
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ package repo
77
import (
88
"net/http"
99
"strconv"
10-
"time"
1110

1211
"code.gitea.io/gitea/models/db"
1312
issues_model "code.gitea.io/gitea/models/issues"
@@ -16,6 +15,7 @@ import (
1615
"code.gitea.io/gitea/modules/timeutil"
1716
"code.gitea.io/gitea/modules/web"
1817
"code.gitea.io/gitea/routers/api/v1/utils"
18+
"code.gitea.io/gitea/routers/common"
1919
"code.gitea.io/gitea/services/context"
2020
"code.gitea.io/gitea/services/convert"
2121
)
@@ -155,16 +155,16 @@ func CreateMilestone(ctx *context.APIContext) {
155155
// "$ref": "#/responses/notFound"
156156
form := web.GetForm(ctx).(*api.CreateMilestoneOption)
157157

158-
if form.Deadline == nil {
159-
defaultDeadline, _ := time.ParseInLocation("2006-01-02", "9999-12-31", time.Local)
160-
form.Deadline = &defaultDeadline
158+
var deadlineUnix int64
159+
if form.Deadline != nil {
160+
deadlineUnix = form.Deadline.Unix()
161161
}
162162

163163
milestone := &issues_model.Milestone{
164164
RepoID: ctx.Repo.Repository.ID,
165165
Name: form.Title,
166166
Content: form.Description,
167-
DeadlineUnix: timeutil.TimeStamp(form.Deadline.Unix()),
167+
DeadlineUnix: timeutil.TimeStamp(deadlineUnix),
168168
}
169169

170170
if form.State == "closed" {
@@ -225,9 +225,7 @@ func EditMilestone(ctx *context.APIContext) {
225225
if form.Description != nil {
226226
milestone.Content = *form.Description
227227
}
228-
if form.Deadline != nil && !form.Deadline.IsZero() {
229-
milestone.DeadlineUnix = timeutil.TimeStamp(form.Deadline.Unix())
230-
}
228+
milestone.DeadlineUnix, _ = common.ParseAPIDeadlineToEndOfDay(form.Deadline)
231229

232230
oldIsClosed := milestone.IsClosed
233231
if form.State != nil {

Diff for: routers/common/deadline.go

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2024 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package common
5+
6+
import (
7+
"time"
8+
9+
"code.gitea.io/gitea/modules/setting"
10+
"code.gitea.io/gitea/modules/timeutil"
11+
)
12+
13+
func ParseDeadlineDateToEndOfDay(date string) (timeutil.TimeStamp, error) {
14+
if date == "" {
15+
return 0, nil
16+
}
17+
deadline, err := time.ParseInLocation("2006-01-02", date, setting.DefaultUILocation)
18+
if err != nil {
19+
return 0, err
20+
}
21+
deadline = time.Date(deadline.Year(), deadline.Month(), deadline.Day(), 23, 59, 59, 0, deadline.Location())
22+
return timeutil.TimeStamp(deadline.Unix()), nil
23+
}
24+
25+
func ParseAPIDeadlineToEndOfDay(t *time.Time) (timeutil.TimeStamp, error) {
26+
if t == nil || t.IsZero() || t.Unix() == 0 {
27+
return 0, nil
28+
}
29+
deadline := time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 0, setting.DefaultUILocation)
30+
return timeutil.TimeStamp(deadline.Unix()), nil
31+
}

Diff for: routers/web/repo/issue.go

+3-12
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import (
1717
"sort"
1818
"strconv"
1919
"strings"
20-
"time"
2120

2221
activities_model "code.gitea.io/gitea/models/activities"
2322
"code.gitea.io/gitea/models/db"
@@ -45,9 +44,9 @@ import (
4544
api "code.gitea.io/gitea/modules/structs"
4645
"code.gitea.io/gitea/modules/templates"
4746
"code.gitea.io/gitea/modules/templates/vars"
48-
"code.gitea.io/gitea/modules/timeutil"
4947
"code.gitea.io/gitea/modules/util"
5048
"code.gitea.io/gitea/modules/web"
49+
"code.gitea.io/gitea/routers/common"
5150
"code.gitea.io/gitea/routers/utils"
5251
shared_user "code.gitea.io/gitea/routers/web/shared/user"
5352
asymkey_service "code.gitea.io/gitea/services/asymkey"
@@ -2329,7 +2328,6 @@ func UpdateIssueContent(ctx *context.Context) {
23292328

23302329
// UpdateIssueDeadline updates an issue deadline
23312330
func UpdateIssueDeadline(ctx *context.Context) {
2332-
form := web.GetForm(ctx).(*api.EditDeadlineOption)
23332331
issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index"))
23342332
if err != nil {
23352333
if issues_model.IsErrIssueNotExist(err) {
@@ -2345,20 +2343,13 @@ func UpdateIssueDeadline(ctx *context.Context) {
23452343
return
23462344
}
23472345

2348-
var deadlineUnix timeutil.TimeStamp
2349-
var deadline time.Time
2350-
if form.Deadline != nil && !form.Deadline.IsZero() {
2351-
deadline = time.Date(form.Deadline.Year(), form.Deadline.Month(), form.Deadline.Day(),
2352-
23, 59, 59, 0, time.Local)
2353-
deadlineUnix = timeutil.TimeStamp(deadline.Unix())
2354-
}
2355-
2346+
deadlineUnix, _ := common.ParseDeadlineDateToEndOfDay(ctx.FormString("deadline"))
23562347
if err := issues_model.UpdateIssueDeadline(ctx, issue, deadlineUnix, ctx.Doer); err != nil {
23572348
ctx.Error(http.StatusInternalServerError, "UpdateIssueDeadline", err.Error())
23582349
return
23592350
}
23602351

2361-
ctx.JSON(http.StatusCreated, api.IssueDeadline{Deadline: &deadline})
2352+
ctx.JSONRedirect("")
23622353
}
23632354

23642355
// UpdateIssueMilestone change issue's milestone

Diff for: routers/web/repo/milestone.go

+6-15
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"fmt"
88
"net/http"
99
"net/url"
10-
"time"
1110

1211
"code.gitea.io/gitea/models/db"
1312
issues_model "code.gitea.io/gitea/models/issues"
@@ -16,8 +15,8 @@ import (
1615
"code.gitea.io/gitea/modules/markup/markdown"
1716
"code.gitea.io/gitea/modules/optional"
1817
"code.gitea.io/gitea/modules/setting"
19-
"code.gitea.io/gitea/modules/timeutil"
2018
"code.gitea.io/gitea/modules/web"
19+
"code.gitea.io/gitea/routers/common"
2120
"code.gitea.io/gitea/services/context"
2221
"code.gitea.io/gitea/services/forms"
2322
"code.gitea.io/gitea/services/issue"
@@ -134,22 +133,18 @@ func NewMilestonePost(ctx *context.Context) {
134133
return
135134
}
136135

137-
if len(form.Deadline) == 0 {
138-
form.Deadline = "9999-12-31"
139-
}
140-
deadline, err := time.ParseInLocation("2006-01-02", form.Deadline, time.Local)
136+
deadlineUnix, err := common.ParseDeadlineDateToEndOfDay(form.Deadline)
141137
if err != nil {
142138
ctx.Data["Err_Deadline"] = true
143139
ctx.RenderWithErr(ctx.Tr("repo.milestones.invalid_due_date_format"), tplMilestoneNew, &form)
144140
return
145141
}
146142

147-
deadline = time.Date(deadline.Year(), deadline.Month(), deadline.Day(), 23, 59, 59, 0, deadline.Location())
148-
if err = issues_model.NewMilestone(ctx, &issues_model.Milestone{
143+
if err := issues_model.NewMilestone(ctx, &issues_model.Milestone{
149144
RepoID: ctx.Repo.Repository.ID,
150145
Name: form.Title,
151146
Content: form.Content,
152-
DeadlineUnix: timeutil.TimeStamp(deadline.Unix()),
147+
DeadlineUnix: deadlineUnix,
153148
}); err != nil {
154149
ctx.ServerError("NewMilestone", err)
155150
return
@@ -194,17 +189,13 @@ func EditMilestonePost(ctx *context.Context) {
194189
return
195190
}
196191

197-
if len(form.Deadline) == 0 {
198-
form.Deadline = "9999-12-31"
199-
}
200-
deadline, err := time.ParseInLocation("2006-01-02", form.Deadline, time.Local)
192+
deadlineUnix, err := common.ParseDeadlineDateToEndOfDay(form.Deadline)
201193
if err != nil {
202194
ctx.Data["Err_Deadline"] = true
203195
ctx.RenderWithErr(ctx.Tr("repo.milestones.invalid_due_date_format"), tplMilestoneNew, &form)
204196
return
205197
}
206198

207-
deadline = time.Date(deadline.Year(), deadline.Month(), deadline.Day(), 23, 59, 59, 0, deadline.Location())
208199
m, err := issues_model.GetMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":id"))
209200
if err != nil {
210201
if issues_model.IsErrMilestoneNotExist(err) {
@@ -216,7 +207,7 @@ func EditMilestonePost(ctx *context.Context) {
216207
}
217208
m.Name = form.Title
218209
m.Content = form.Content
219-
m.DeadlineUnix = timeutil.TimeStamp(deadline.Unix())
210+
m.DeadlineUnix = deadlineUnix
220211
if err = issues_model.UpdateMilestone(ctx, m, m.IsClosed); err != nil {
221212
ctx.ServerError("UpdateMilestone", err)
222213
return

Diff for: routers/web/web.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1208,7 +1208,7 @@ func registerRoutes(m *web.Router) {
12081208
m.Group("/{index}", func() {
12091209
m.Post("/title", repo.UpdateIssueTitle)
12101210
m.Post("/content", repo.UpdateIssueContent)
1211-
m.Post("/deadline", web.Bind(structs.EditDeadlineOption{}), repo.UpdateIssueDeadline)
1211+
m.Post("/deadline", repo.UpdateIssueDeadline)
12121212
m.Post("/watch", repo.IssueWatch)
12131213
m.Post("/ref", repo.UpdateIssueRef)
12141214
m.Post("/pin", reqRepoAdmin, repo.IssuePinOrUnpin)

Diff for: services/convert/issue.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ func ToAPIMilestone(m *issues_model.Milestone) *api.Milestone {
260260
if m.IsClosed {
261261
apiMilestone.Closed = m.ClosedDateUnix.AsTimePtr()
262262
}
263-
if m.DeadlineUnix.Year() < 9999 {
263+
if m.DeadlineUnix > 0 {
264264
apiMilestone.Deadline = m.DeadlineUnix.AsTimePtr()
265265
}
266266
return apiMilestone

Diff for: templates/repo/graph/commits.tmpl

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
{{end}}
5757
{{end}}
5858
</span>
59-
<span class="author tw-flex tw-items-center tw-mr-2 tw-gap-[1px]">
59+
<span class="author tw-flex tw-items-center tw-mr-2 tw-gap-1">
6060
{{$userName := $commit.Commit.Author.Name}}
6161
{{if $commit.User}}
6262
{{if and $commit.User.FullName DefaultShowFullName}}

Diff for: templates/repo/issue/milestone_new.tmpl

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@
3030
<div class="field {{if .Err_Deadline}}error{{end}}">
3131
<label>
3232
{{ctx.Locale.Tr "repo.milestones.due_date"}}
33-
<a id="clear-date">{{ctx.Locale.Tr "repo.milestones.clear"}}</a>
33+
<a id="milestone-clear-deadline">{{ctx.Locale.Tr "repo.milestones.clear"}}</a>
3434
</label>
35-
<input type="date" id="deadline" name="deadline" value="{{.deadline}}" placeholder="{{ctx.Locale.Tr "repo.issues.due_date_form"}}">
35+
<input type="date" name="deadline" class="tw-w-auto" value="{{.deadline}}" placeholder="{{ctx.Locale.Tr "repo.issues.due_date_form"}}">
3636
</div>
3737
<div class="field">
3838
<label>{{ctx.Locale.Tr "repo.milestones.desc"}}</label>

0 commit comments

Comments
 (0)