-
Notifications
You must be signed in to change notification settings - Fork 1.1k
[JENKINS-64810] Add creation time boundaries to tags for discovery #1764
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 1 commit
5b9acb0
8a7de39
77c1168
d20c7ed
fcfb5f8
df42f96
2dea2d7
ff5e2cd
fa788b3
1c59f53
1abea7a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -37,6 +37,7 @@ | |||||||||||||||||||||||||||||||
| import java.util.Objects; | ||||||||||||||||||||||||||||||||
| import java.util.Set; | ||||||||||||||||||||||||||||||||
| import java.util.TreeSet; | ||||||||||||||||||||||||||||||||
| import java.util.concurrent.TimeUnit; | ||||||||||||||||||||||||||||||||
| import java.util.regex.Matcher; | ||||||||||||||||||||||||||||||||
| import java.util.regex.Pattern; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
@@ -95,6 +96,12 @@ | |||||||||||||||||||||||||||||||
| @NonNull | ||||||||||||||||||||||||||||||||
| private String remoteName = AbstractGitSCMSource.DEFAULT_REMOTE_NAME; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| @CheckForNull | ||||||||||||||||||||||||||||||||
| private long atLeastTagCommitTimeMillis; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| @CheckForNull | ||||||||||||||||||||||||||||||||
| private long atMostTagCommitTimeMillis; | ||||||||||||||||||||||||||||||||
|
dodo920306 marked this conversation as resolved.
Outdated
dodo920306 marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||
| * Constructor. | ||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||
|
|
@@ -192,6 +199,14 @@ | |||||||||||||||||||||||||||||||
| return remoteName; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| public final long getAtLeastTagCommitTimeMillis() { | ||||||||||||||||||||||||||||||||
| return atLeastTagCommitTimeMillis; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| public final long getAtMostTagCommitTimeMillis() { | ||||||||||||||||||||||||||||||||
| return atMostTagCommitTimeMillis; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||
| * Adds a requirement for branch details to any {@link GitSCMSourceRequest} for this context. | ||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||
|
|
@@ -358,6 +373,25 @@ | |||||||||||||||||||||||||||||||
| return result; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| private long getTagCommitTimeLimitMillisFromDays(String limitDays) { | ||||||||||||||||||||||||||||||||
| long tagCommitTimeLimit = Long.parseLong(StringUtils.defaultIfBlank(limitDays, "-1")); | ||||||||||||||||||||||||||||||||
| return tagCommitTimeLimit < 0 ? -1L : TimeUnit.DAYS.toMillis(tagCommitTimeLimit); | ||||||||||||||||||||||||||||||||
|
dodo920306 marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||
| private long getTagCommitTimeLimitMillisFromDays(String limitDays) { | |
| long tagCommitTimeLimit = Long.parseLong(StringUtils.defaultIfBlank(limitDays, "-1")); | |
| return tagCommitTimeLimit < 0 ? -1L : TimeUnit.DAYS.toMillis(tagCommitTimeLimit); | |
| private static final long MAX_TAG_COMMIT_TIME_LIMIT_DAYS = | |
| Long.MAX_VALUE / TimeUnit.DAYS.toMillis(1); | |
| private long getTagCommitTimeLimitMillisFromDays(String limitDays) { | |
| long tagCommitTimeLimit = Long.parseLong(StringUtils.defaultIfBlank(limitDays, "-1")); | |
| if (tagCommitTimeLimit < 0) { | |
| return -1L; | |
| } | |
| if (tagCommitTimeLimit > MAX_TAG_COMMIT_TIME_LIMIT_DAYS) { | |
| throw new IllegalArgumentException("Tag commit time limit is too large: " + tagCommitTimeLimit + " days"); | |
| } | |
| return TimeUnit.DAYS.toMillis(tagCommitTimeLimit); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I...am not quite sure about this?
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,6 +23,7 @@ | |
| */ | ||
| package jenkins.plugins.git.traits; | ||
|
|
||
| import edu.umd.cs.findbugs.annotations.CheckForNull; | ||
| import edu.umd.cs.findbugs.annotations.NonNull; | ||
| import hudson.Extension; | ||
| import jenkins.plugins.git.GitSCMBuilder; | ||
|
|
@@ -51,11 +52,20 @@ | |
| * @since 3.6.0 | ||
| */ | ||
| public class TagDiscoveryTrait extends SCMSourceTrait { | ||
| private final String atLeastDays; | ||
| private final String atMostDays; | ||
|
|
||
| /** | ||
| * Constructor for stapler. | ||
| */ | ||
| @DataBoundConstructor | ||
| public TagDiscoveryTrait(@CheckForNull String atLeastDays, @CheckForNull String atMostDays) { | ||
| this.atLeastDays = atLeastDays; | ||
| this.atMostDays = atMostDays; | ||
| } | ||
|
|
||
| public TagDiscoveryTrait() { | ||
| this(null, null); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -66,6 +76,8 @@ | |
| GitSCMSourceContext<?,?> ctx = (GitSCMSourceContext<?, ?>) context; | ||
| ctx.wantTags(true); | ||
| ctx.withAuthority(new TagSCMHeadAuthority()); | ||
| ctx.withAtLeastTagCommitTimeDays(atLeastDays) | ||
| .withAtMostTagCommitTimeDays(atMostDays); | ||
| } | ||
|
Comment on lines
+79
to
81
|
||
|
|
||
| /** | ||
|
|
@@ -76,6 +88,14 @@ | |
| return category instanceof TagSCMHeadCategory; | ||
| } | ||
|
|
||
| public String getAtLeastDays() { | ||
| return atLeastDays; | ||
| } | ||
|
|
||
| public String getAtMostDays() { | ||
| return atMostDays; | ||
| } | ||
|
|
||
| /** | ||
| * Our descriptor. | ||
| */ | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,4 +1,10 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <?jelly escape-by-default='true'?> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:c="/lib/credentials" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <f:entry field="atLeastDays" title="${%Ignore tags newer than}"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <f:number default=""/> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </f:entry> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <f:entry field="atMostDays" title="${%Ignore tags older than}"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+4
to
+7
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <f:entry field="atLeastDays" title="${%Ignore tags newer than}"> | |
| <f:number default=""/> | |
| </f:entry> | |
| <f:entry field="atMostDays" title="${%Ignore tags older than}"> | |
| <f:entry field="atLeastDays" title="${%Discover tags older than (days)}"> | |
| <f:number default=""/> | |
| </f:entry> | |
| <f:entry field="atMostDays" title="${%Discover tags newer than (days)}"> |
Copilot
AI
Jan 23, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new configuration fields "atLeastDays" and "atMostDays" lack help documentation. The config.jelly file adds these fields but there are no corresponding help-atLeastDays.html and help-atMostDays.html files to explain to users what these fields do.
These help files should explain:
- What the fields control (filtering tags by age)
- How the age is calculated (from tag creation/commit time)
- What empty/blank values mean
- Examples of usage (e.g., "Enter 7 to ignore tags older than 7 days")
- How these interact with each other (atMostDays should be greater than atLeastDays)
This is especially important since the UI labels "Ignore tags newer than" and "Ignore tags older than" might be confusing without additional context.
| <f:number default=""/> | |
| </f:entry> | |
| <f:entry field="atMostDays" title="${%Ignore tags older than}"> | |
| <f:number default="7"/> | |
| <f:number default=""/> | |
| <f:help> | |
| <p> | |
| Minimum age of tags (in days) to <strong>include</strong> when discovering tags. | |
| Tags newer than this value are ignored. | |
| </p> | |
| <p> | |
| Tag age is calculated from the tag creation / commit timestamp to the time the | |
| scan runs. | |
| </p> | |
| <p> | |
| Leave this field blank to <strong>not</strong> filter out tags based on a minimum age | |
| (no lower age bound). | |
| </p> | |
| <p> | |
| Examples: | |
| </p> | |
| <ul> | |
| <li><code>7</code> – ignore tags created in the last 7 days (only tags at least 7 days old are used).</li> | |
| <li><code>0</code> – do not ignore tags for being too new (equivalent to leaving it blank).</li> | |
| </ul> | |
| <p> | |
| When used together with <em>Ignore tags older than</em> (<code>atMostDays</code>), | |
| this value should be less than or equal to the <em>older than</em> value to define a valid age range. | |
| </p> | |
| </f:help> | |
| </f:entry> | |
| <f:entry field="atMostDays" title="${%Ignore tags older than}"> | |
| <f:number default="7"/> | |
| <f:help> | |
| <p> | |
| Maximum age of tags (in days) to <strong>include</strong> when discovering tags. | |
| Tags older than this value are ignored. | |
| </p> | |
| <p> | |
| Tag age is calculated from the tag creation / commit timestamp to the time the | |
| scan runs. | |
| </p> | |
| <p> | |
| Leave this field blank to <strong>not</strong> filter out tags based on a maximum age | |
| (no upper age bound). | |
| </p> | |
| <p> | |
| Examples: | |
| </p> | |
| <ul> | |
| <li><code>7</code> – ignore tags older than 7 days (only tags from the last 7 days are used).</li> | |
| <li><code>30</code> – ignore tags older than 30 days (only tags from the last 30 days are used).</li> | |
| </ul> | |
| <p> | |
| When used together with <em>Ignore tags newer than</em> (<code>atLeastDays</code>), | |
| this value should be greater than or equal to the <em>newer than</em> value so that the | |
| age range is consistent. | |
| </p> | |
| </f:help> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no other traits that includes such help messages for their fields in this project.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no other traits that includes such help messages for their fields in this project.
GitHub Copilot suggested the wrong approach here. Please refer to the following example files for the correct approach to add online help to traits:
- src/main/resources/jenkins/plugins/git/traits/BranchDiscoveryTrait/help.html
- src/main/resources/jenkins/plugins/git/traits/DiscoverOtherRefsTrait/help-nameMapping.html
- src/main/resources/jenkins/plugins/git/traits/DiscoverOtherRefsTrait/help-ref.html
- src/main/resources/jenkins/plugins/git/traits/DiscoverOtherRefsTrait/help.html
- src/main/resources/jenkins/plugins/git/traits/RefSpecsSCMSourceTrait/RefSpecTemplate/help-value.html
- src/main/resources/jenkins/plugins/git/traits/TagDiscoveryTrait/help.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GitHub Copilot suggested the wrong approach here. Please refer to the following example files for the correct approach to add online help to traits:
* src/main/resources/jenkins/plugins/git/traits/BranchDiscoveryTrait/help.html * src/main/resources/jenkins/plugins/git/traits/DiscoverOtherRefsTrait/help-nameMapping.html * src/main/resources/jenkins/plugins/git/traits/DiscoverOtherRefsTrait/help-ref.html * src/main/resources/jenkins/plugins/git/traits/DiscoverOtherRefsTrait/help.html * src/main/resources/jenkins/plugins/git/traits/RefSpecsSCMSourceTrait/RefSpecTemplate/help-value.html * src/main/resources/jenkins/plugins/git/traits/TagDiscoveryTrait/help.html
OK.
Copilot
AI
Jan 23, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The field order in the UI might be counterintuitive. The "atLeastDays" field (tags older than X days) appears before "atMostDays" field (tags newer than Y days). When users think about filtering by time range, they typically think in chronological order: "from X days ago to Y days ago" or in age order: "minimum age to maximum age".
Consider reordering the fields to be more intuitive:
- If using the current labels, swap them so "Ignore tags older than" (atMostDays) comes first, then "Ignore tags newer than" (atLeastDays)
- Or rename to "Minimum tag age" (atLeastDays) first, then "Maximum tag age" (atMostDays)
This would align better with user expectations when setting up a time range filter.
| <f:entry field="atLeastDays" title="${%Ignore tags newer than}"> | |
| <f:number default=""/> | |
| </f:entry> | |
| <f:entry field="atMostDays" title="${%Ignore tags older than}"> | |
| <f:number default="7"/> | |
| </f:entry> | |
| <f:entry field="atMostDays" title="${%Ignore tags older than}"> | |
| <f:number default="7"/> | |
| </f:entry> | |
| <f:entry field="atLeastDays" title="${%Ignore tags newer than}"> | |
| <f:number default=""/> | |
| </f:entry> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I doubt this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The filtering logic checks if atMostMillis >= 0L && atLeastMillis > atMostMillis and continues to skip the tag if this invalid configuration is detected. However, this check is performed inside the loop for every tag, which is inefficient.
Consider moving this validation earlier, such as:
This would provide earlier feedback to users about configuration errors and avoid redundant checks for every tag.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is necessary.