From 495fee455521b9f9c00bbc8bbd37cdf3151b0d15 Mon Sep 17 00:00:00 2001 From: Scion Date: Sat, 20 Dec 2025 08:16:20 -0800 Subject: [PATCH] Closed milestones with no issues now show as 100% completed (#36220) Closed milestones with 0 issues currently display as having 0% completion. This makes sense if the milestone is still open, but if the milestone is closed it seems like that it should show 100% completeness instead. Before: image After: image --- models/issues/milestone.go | 11 +++++++++-- models/migrations/migrations.go | 1 + models/migrations/v1_26/v324.go | 24 ++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 models/migrations/v1_26/v324.go diff --git a/models/issues/milestone.go b/models/issues/milestone.go index 82a82ac913..1dd8630276 100644 --- a/models/issues/milestone.go +++ b/models/issues/milestone.go @@ -75,6 +75,8 @@ func init() { func (m *Milestone) BeforeUpdate() { if m.NumIssues > 0 { m.Completeness = m.NumClosedIssues * 100 / m.NumIssues + } else if m.IsClosed { + m.Completeness = 100 } else { m.Completeness = 0 } @@ -195,8 +197,8 @@ func UpdateMilestoneCounters(ctx context.Context, id int64) error { if err != nil { return err } - _, err = e.Exec("UPDATE `milestone` SET completeness=100*num_closed_issues/(CASE WHEN num_issues > 0 THEN num_issues ELSE 1 END) WHERE id=?", - id, + _, err = e.Exec("UPDATE `milestone` SET completeness=(CASE WHEN is_closed = ? AND num_issues = 0 THEN 100 ELSE 100*num_closed_issues/(CASE WHEN num_issues > 0 THEN num_issues ELSE 1 END) END) WHERE id=?", + true, id, ) return err } @@ -240,6 +242,11 @@ func changeMilestoneStatus(ctx context.Context, m *Milestone, isClosed bool) err if count < 1 { return nil } + + if err := UpdateMilestoneCounters(ctx, m.ID); err != nil { + return err + } + return updateRepoMilestoneNum(ctx, m.RepoID) } diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index e8ebb5df43..fa11acaee2 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -398,6 +398,7 @@ func prepareMigrationTasks() []*migration { // Gitea 1.25.0 ends at migration ID number 322 (database version 323) newMigration(323, "Add support for actions concurrency", v1_26.AddActionsConcurrency), + newMigration(324, "Fix closed milestone completeness for milestones with no issues", v1_26.FixClosedMilestoneCompleteness), } return preparedMigrations } diff --git a/models/migrations/v1_26/v324.go b/models/migrations/v1_26/v324.go new file mode 100644 index 0000000000..5d96bfa3ca --- /dev/null +++ b/models/migrations/v1_26/v324.go @@ -0,0 +1,24 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_26 + +import ( + "fmt" + + "xorm.io/xorm" +) + +func FixClosedMilestoneCompleteness(x *xorm.Engine) error { + // Update all milestones to recalculate completeness with the new logic: + // - Closed milestones with 0 issues should show 100% + // - All other milestones should calculate based on closed/total ratio + _, err := x.Exec("UPDATE `milestone` SET completeness=(CASE WHEN is_closed = ? AND num_issues = 0 THEN 100 ELSE 100*num_closed_issues/(CASE WHEN num_issues > 0 THEN num_issues ELSE 1 END) END)", + true, + ) + if err != nil { + return fmt.Errorf("error updating milestone completeness: %w", err) + } + + return nil +}