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
[JENKINS-52161] Improve creation-date value determination #3525
[JENKINS-52161] Improve creation-date value determination #3525
Conversation
- in case of migration we put null instead of now - improve also the difference in days for the Xxx day(s) ago to take calendar day in difference and not the total duration (<24h = 0 days, which seems wrong in UI)
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.
Thanks, this seems like a good improvement over what's happening today.
<j:if test="${legacyStats.lastUseDate != null}"> | ||
<i:formatDate var="lastUseDateFormat" value="${legacyStats.lastUseDate}" type="both" dateStyle="medium" timeStyle="medium" /> | ||
<!--TODO convert to "Today", "Tomorrow", "4 days ago", "2 weeks ago", etc--> |
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.
Pet peeve: etc.
core/src/main/java/hudson/Util.java
Outdated
@@ -23,6 +23,7 @@ | |||
*/ | |||
package hudson; | |||
|
|||
import com.sun.istack.internal.NotNull; |
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.
Is this the right import?
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 think it is not used, indeed.
core/src/main/java/hudson/Util.java
Outdated
*/ | ||
@Restricted(NoExternalUse.class) | ||
public static int differenceInCalendarDay(@Nonnull Date a, @Nonnull Date b){ | ||
LocalDate aLocal = a.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); |
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 have half a preference for considering the user's time zone instead of the system's. (This is achievable by passing both dates down through to the jelly and letting it do this math instead.)
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.
IIRC HTTP Headers do not contain any information about timezone. You mean using JavaScript instead of server-side rendering ?
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.
Except for time zones that have managed to skip a day recently (which hasn't happened for decades or possibly centuries IIRC), this logic would work for any time zone.
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.
Yes, I meant JavaScript instead of server-side.
The issue isn't that the logic would work for any time zone, it's that the creature who wants to do the counting has a different perspective.
Date A is created at 1:03am New Zealand time.
https://www.timeanddate.com/worldclock/converter.html?iso=20171230T120300&p1=22&p2=195
Date B is created at 11:55pm New Zealand time on the same calendar date in New Zealand.
https://www.timeanddate.com/worldclock/converter.html?iso=20171231T105500&p1=22&p2=195
User C in New Zealand sees these two events as 0 days apart.
User D in Paris looks at these dates and sees them as 1 day apart.
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.
Oh, I see. Yeah, that would be an actual issue.
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.
To me it seems like we want a more general fix for this, maybe JENKINS-19887 or the linked tickets there rather than introducing complexity here as a one-off case.
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.
Yeah, I'm fine with it not being addressed here. I just want people to be aware. Hence "my preference" as opposed to any stronger request.
The reason to mention it here is that it impacts the "api" perspective. If the values are both exposed to the client, then the client side can be upgraded to get this w/o needing to rebuild the "api".
OTOH, if jenkins treats the strings as the "api" and doesn't see them as "frozen", then evolving it later and doing it server-side is fine. -- I haven't built up a complete sense of how jenkins manages its "apis". (I just know that it has things that are apis.)
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.
@jsoref FYI about API:
As the code that is modified here is @Restricted
(actually an inner class of a restricted class) we can consider it as an internal API (i.e. private) and so we could break it without any other consideration.
If there are public methods in a non-@Restricted
, they could be used by other plugins / components, that's the developer API we need to care about in terms of binary compatibility.
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.
@Wadeck: k. that covers the java side, but what are the rules for the http side? (Maybe the answer is there aren't any constraints, which is probably a good thing here)
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.
@jsoref yeah in general I would say there is no constraint except that you need to keep consistency, security and compatibility in mind.
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.
🐝
LGTM, just a minor comment
core/src/main/java/hudson/Util.java
Outdated
@@ -23,6 +23,7 @@ | |||
*/ | |||
package hudson; | |||
|
|||
import com.sun.istack.internal.NotNull; |
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 think it is not used, indeed.
@@ -371,6 +371,22 @@ private void init() { | |||
|
|||
return result; | |||
} | |||
|
|||
public static @Nonnull HashedToken buildNewFromLegacy(@Nonnull HashValue value, boolean migrationFromExistingLegacy) { |
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.
@since
or @Restricted
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.
as the parent class (ApiTokenStore) is @Restricted
, this method is also @Restricted
by implication
core/src/main/java/hudson/Util.java
Outdated
public static int differenceInCalendarDay(@Nonnull Date a, @Nonnull Date b){ | ||
LocalDate aLocal = a.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); | ||
LocalDate bLocal = b.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); | ||
return Period.between(aLocal, bLocal).getDays(); |
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.
Period#getDays
just returns the number of days less than a month, not the total (i.e. differenceInCalendarDay(2017-01-01, 2018-01-01) will return 0, but I think you want it to return 365 (Yes, I have been bitten by this in the past)). You should use ChronoUnit.DAYS.between(aLocal, bLocal)
to get the total number of days.
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.
Nice catch! It's due to things like this that I tend to use Instant
more often than the human versions.
Date day1_11pm55 = new Date(2018, 4, 6, 23, 55); | ||
Date day2_01am = new Date(2018, 4, 7, 1, 0); | ||
Date day2_11pm = new Date(2018, 4, 7, 1, 0); | ||
Date day3_08am = new Date(2018, 4, 8, 8, 0); |
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.
Add some Dates with different years, and dates more than a month apart :)
core/src/main/java/hudson/Util.java
Outdated
* even if there are only 3 hours between. As well as "10am" to "2pm" both on the same day, returns 0. | ||
*/ | ||
@Restricted(NoExternalUse.class) | ||
public static int differenceInCalendarDay(@Nonnull Date a, @Nonnull Date b){ |
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.
Days instead of day for all these methods?
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.
How about daysBetween()
?
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.
Added a couple notes about naming and boolean usage, but otherwise looks good.
core/src/main/java/hudson/Util.java
Outdated
* even if there are only 3 hours between. As well as "10am" to "2pm" both on the same day, returns 0. | ||
*/ | ||
@Restricted(NoExternalUse.class) | ||
public static int differenceInCalendarDay(@Nonnull Date a, @Nonnull Date b){ |
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.
How about daysBetween()
?
core/src/main/java/hudson/Util.java
Outdated
*/ | ||
@Restricted(NoExternalUse.class) | ||
public static int differenceInCalendarDay(@Nonnull Date a, @Nonnull Date b){ | ||
LocalDate aLocal = a.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); |
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.
Except for time zones that have managed to skip a day recently (which hasn't happened for decades or possibly centuries IIRC), this logic would work for any time zone.
core/src/main/java/hudson/Util.java
Outdated
public static int differenceInCalendarDay(@Nonnull Date a, @Nonnull Date b){ | ||
LocalDate aLocal = a.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); | ||
LocalDate bLocal = b.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); | ||
return Period.between(aLocal, bLocal).getDays(); |
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.
Nice catch! It's due to things like this that I tend to use Instant
more often than the human versions.
core/src/main/java/hudson/Util.java
Outdated
* @see #differenceInCalendarDay(Date, Date) | ||
*/ | ||
@Restricted(NoExternalUse.class) | ||
public static int numOfCalendarDayToNow(@Nonnull Date date){ |
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.
Could name this something like daysSince()
or daysElapsedSince()
. Also, based on usage, you could also return 0 for future dates to simplify a bit.
@@ -371,6 +371,22 @@ private void init() { | |||
|
|||
return result; | |||
} | |||
|
|||
public static @Nonnull HashedToken buildNewFromLegacy(@Nonnull HashValue value, boolean migrationFromExistingLegacy) { |
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 already packed it away, so I'm not sure which item it is, but Effective Java suggests using enums instead of booleans for situations like this. The context of what exactly that flag does is lost in a language like Java (i.e., no passing parameters by name).
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.
In this case the method is @Restricted
and so can be considered "private" for us, i.e. the context is never lost as we are using the source directly.
Date day2_01am = new Date(2018, 4, 7, 1, 0); | ||
Date day2_11pm = new Date(2018, 4, 7, 1, 0); | ||
Date day3_08am = new Date(2018, 4, 8, 8, 0); | ||
assertEquals(0, Util.differenceInCalendarDay(day1_10am, day1_11pm55)); |
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.
It might be simpler to use a parameterized test for this, but it'd have to be in a separate class thanks to junit 4.
- also add translation for another creationDate - and manage correctly the null creation date instead of 0
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.
LGTM
@@ -138,14 +144,14 @@ THE SOFTWARE. | |||
</j:otherwise> | |||
</j:choose> | |||
</table> | |||
|
|||
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'm not sure of the normal style. I personally am not a fan of trailing whitespace (and apparently the code wasn't using it before).
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.
Yeah I just tried to make it consistent
@@ -781,4 +781,29 @@ public void testPermissionsToMode() throws Exception { | |||
assertEquals(0000, Util.permissionsToMode(PosixFilePermissions.fromString("---------"))); | |||
} | |||
|
|||
@Test | |||
public void testDifferenceDays() { | |||
Date may_6_10am = new Date(2018 - 1900, 4, 6, 10, 0); |
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.
https://docs.oracle.com/javase/8/docs/api/java/util/Date.html#constructor.summary
Date(int year, int month, int date, int hrs, int min, int sec)
Deprecated.
As of JDK version 1.1, replaced by Calendar.set(year + 1900, month, date, hrs, min, sec) or GregorianCalendar(year + 1900, month, date, hrs, min, sec).
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.
In general I do not care really for test code to use deprecated constructors like that because it's not the code that is tested but only the tools we use to test the real things.
As you pointed out this code and take time to retrieve the documentation, I imagine it's important for you, so I changed it 👍
@Wadeck: thanks, that's actually much easier to read. |
@reviewbybees done @jsoref do you approve this PR ? :) |
null
instead of now and so changed the display in Legacy token monitoring page.See JENKINS-52161.
Proposed changelog entries
null
during migration of legacy token from XMLUnknown
creation date from today.Submitter checklist
* Use the
Internal:
prefix if the change has no user-visible impact (API, test frameworks, etc.)Desired reviewers
@reviewbybees @jsoref