From deb21f270ce877b475b9c5fb4c49f9e3e80598fa Mon Sep 17 00:00:00 2001 From: David Lawrence Date: Tue, 1 Sep 2026 18:00:22 -0400 Subject: [PATCH 1/3] Bug 2066252 - Prevent save if keyword checkin-needed-tb exists without target milestone --- extensions/MozChangeField/Extension.pm | 4 ++ .../lib/Post/CheckinNeededTbMilestone.pm | 50 +++++++++++++++++++ .../hook/global/user-error-errors.html.tmpl | 5 ++ 3 files changed, 59 insertions(+) create mode 100644 extensions/MozChangeField/lib/Post/CheckinNeededTbMilestone.pm diff --git a/extensions/MozChangeField/Extension.pm b/extensions/MozChangeField/Extension.pm index 6e2dbffdae..860b0fdad7 100644 --- a/extensions/MozChangeField/Extension.pm +++ b/extensions/MozChangeField/Extension.pm @@ -34,18 +34,22 @@ my @pre_instances = ( use Bugzilla::Extension::MozChangeField::Post::SeverityS1PriorityP1; use Bugzilla::Extension::MozChangeField::Post::ClearTrackingPriorityS1; + #use Bugzilla::Extension::MozChangeField::Post::CommentOnSeverity; use Bugzilla::Extension::MozChangeField::Post::SetTrackingSeverityS1; use Bugzilla::Extension::MozChangeField::Post::TypePriSevEditbugs; use Bugzilla::Extension::MozChangeField::Post::RegressedByTypeKeyword; +use Bugzilla::Extension::MozChangeField::Post::CheckinNeededTbMilestone; my @post_instances = ( Bugzilla::Extension::MozChangeField::Post::SeverityS1PriorityP1->new, Bugzilla::Extension::MozChangeField::Post::ClearTrackingPriorityS1->new, + #Bugzilla::Extension::MozChangeField::Post::CommentOnSeverity->new, Bugzilla::Extension::MozChangeField::Post::SetTrackingSeverityS1->new, Bugzilla::Extension::MozChangeField::Post::TypePriSevEditbugs->new, Bugzilla::Extension::MozChangeField::Post::RegressedByTypeKeyword->new, + Bugzilla::Extension::MozChangeField::Post::CheckinNeededTbMilestone->new, ); our $VERSION = '0.1'; diff --git a/extensions/MozChangeField/lib/Post/CheckinNeededTbMilestone.pm b/extensions/MozChangeField/lib/Post/CheckinNeededTbMilestone.pm new file mode 100644 index 0000000000..263efe67da --- /dev/null +++ b/extensions/MozChangeField/lib/Post/CheckinNeededTbMilestone.pm @@ -0,0 +1,50 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +package Bugzilla::Extension::MozChangeField::Post::CheckinNeededTbMilestone; + +use 5.10.1; +use Moo; + +use Bugzilla::Error; + +use constant PRODUCTS => + {map { $_ => 1 } ('Thunderbird', 'MailNews Core', 'Calendar')}; + +use constant KEYWORD => 'checkin-needed-tb'; + +sub _check_milestone { + my ($bug) = @_; + my $product = $bug->product_obj; + + return if !PRODUCTS->{$product->name}; + return if !$bug->has_keyword(KEYWORD); + + # The product's default milestone (normally '---') means 'not set'. + return if $bug->target_milestone ne $product->default_milestone; + + ThrowUserError('mozchangefield_checkin_needed_tb_milestone', + {keyword => KEYWORD}); +} + +sub evaluate_create { + my ($self, $args) = @_; + _check_milestone($args->{bug}); +} + +sub evaluate_change { + my ($self, $args) = @_; + my $changes = $args->{changes}; + + # Only enforce on a save that touches one of the two fields, so bugs + # already in this state don't block unrelated edits. + return if !exists $changes->{keywords} && !exists $changes->{target_milestone}; + + _check_milestone($args->{bug}); +} + +1; diff --git a/extensions/MozChangeField/template/en/default/hook/global/user-error-errors.html.tmpl b/extensions/MozChangeField/template/en/default/hook/global/user-error-errors.html.tmpl index 62ca30ec20..777ecc516f 100644 --- a/extensions/MozChangeField/template/en/default/hook/global/user-error-errors.html.tmpl +++ b/extensions/MozChangeField/template/en/default/hook/global/user-error-errors.html.tmpl @@ -14,4 +14,9 @@ [% title = "Invalid Change" %] You need "editbugs" permissions to alter the '[% field FILTER html %]' field. +[% ELSIF error == "mozchangefield_checkin_needed_tb_milestone" %] + [% title = "Target Milestone Required" %] + The [% keyword FILTER html %] keyword requires a + Target Milestone to be set. + [% END %] From aaabb5adb639e3d6e76294d03176ea1fff1a2b3e Mon Sep 17 00:00:00 2001 From: David Lawrence Date: Tue, 1 Sep 2026 18:05:06 -0400 Subject: [PATCH 2/3] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../MozChangeField/lib/Post/CheckinNeededTbMilestone.pm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/extensions/MozChangeField/lib/Post/CheckinNeededTbMilestone.pm b/extensions/MozChangeField/lib/Post/CheckinNeededTbMilestone.pm index 263efe67da..94a2e07829 100644 --- a/extensions/MozChangeField/lib/Post/CheckinNeededTbMilestone.pm +++ b/extensions/MozChangeField/lib/Post/CheckinNeededTbMilestone.pm @@ -42,7 +42,9 @@ sub evaluate_change { # Only enforce on a save that touches one of the two fields, so bugs # already in this state don't block unrelated edits. - return if !exists $changes->{keywords} && !exists $changes->{target_milestone}; + return if !exists $changes->{keywords} + && !exists $changes->{target_milestone} + && !exists $changes->{product}; _check_milestone($args->{bug}); } From 6fc4d14283bb9d7acede75588d82d3e2293c7794 Mon Sep 17 00:00:00 2001 From: David Lawrence Date: Wed, 2 Sep 2026 22:26:53 -0400 Subject: [PATCH 3/3] Review fixes --- .../MozChangeField/lib/Post/CheckinNeededTbMilestone.pm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/extensions/MozChangeField/lib/Post/CheckinNeededTbMilestone.pm b/extensions/MozChangeField/lib/Post/CheckinNeededTbMilestone.pm index 94a2e07829..d52db2b615 100644 --- a/extensions/MozChangeField/lib/Post/CheckinNeededTbMilestone.pm +++ b/extensions/MozChangeField/lib/Post/CheckinNeededTbMilestone.pm @@ -40,9 +40,10 @@ sub evaluate_change { my ($self, $args) = @_; my $changes = $args->{changes}; - # Only enforce on a save that touches one of the two fields, so bugs + # Only enforce on a save that touches one of three fields, so bugs # already in this state don't block unrelated edits. - return if !exists $changes->{keywords} + return + if !exists $changes->{keywords} && !exists $changes->{target_milestone} && !exists $changes->{product};