diff --git a/core/src/main/java/hudson/scheduler/CronTab.java b/core/src/main/java/hudson/scheduler/CronTab.java index 72614b3921902d24c983d9b713a2c30e45a50530..ec8c4ffb430aa0d3d7915ad0eac9b79a37547ac9 100644 --- a/core/src/main/java/hudson/scheduler/CronTab.java +++ b/core/src/main/java/hudson/scheduler/CronTab.java @@ -29,6 +29,8 @@ import java.io.StringReader; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static java.util.Calendar.*; import javax.annotation.CheckForNull; @@ -451,6 +453,19 @@ public final class CronTab { } else if (spec.matches("\\d+ .+")) {// "0 ..." (certain minute) to hash return "H " + spec.substring(spec.indexOf(' ') + 1); } else { + Matcher m = Pattern.compile("0(,(\\d+)(,\\d+)*)( .+)").matcher(spec); + if (m.matches()) { // 0,15,30,45 to H/15 + int period = Integer.parseInt(m.group(2)); + if (period > 0) { + StringBuilder b = new StringBuilder(); + for (int i = period; i < 60; i += period) { + b.append(',').append(i); + } + if (b.toString().equals(m.group(1))) { + return "H/" + period + m.group(4); + } + } + } return null; } } diff --git a/core/src/test/java/hudson/scheduler/CronTabTest.java b/core/src/test/java/hudson/scheduler/CronTabTest.java index c7d943fbee2150ba38ba32d5fbe7e17e0a506e5b..388784b141a19222c37829a3c1bbabc16ece3e39 100644 --- a/core/src/test/java/hudson/scheduler/CronTabTest.java +++ b/core/src/test/java/hudson/scheduler/CronTabTest.java @@ -176,6 +176,7 @@ public class CronTabTest { @Test public void checkSanity() throws Exception { assertEquals(null, new CronTab("@hourly").checkSanity()); assertEquals(Messages.CronTab_do_you_really_mean_every_minute_when_you("* * * * *", "H * * * *"), new CronTab("* * * * *").checkSanity()); + assertEquals(Messages.CronTab_do_you_really_mean_every_minute_when_you("*/1 * * * *", "H * * * *"), new CronTab("*/1 * * * *").checkSanity()); assertEquals(null, new CronTab("H H(0-2) * * *", Hash.from("stuff")).checkSanity()); assertEquals(Messages.CronTab_do_you_really_mean_every_minute_when_you("* 0 * * *", "H 0 * * *"), new CronTab("* 0 * * *").checkSanity()); assertEquals(Messages.CronTab_do_you_really_mean_every_minute_when_you("* 6,18 * * *", "H 6,18 * * *"), new CronTab("* 6,18 * * *").checkSanity()); @@ -183,11 +184,12 @@ public class CronTabTest { assertEquals(Messages.CronTab_do_you_really_mean_every_minute_when_you("* * 3 * *", "H * 3 * *"), new CronTab("* * 3 * *").checkSanity()); // promote hashes: assertEquals(Messages.CronTab_spread_load_evenly_by_using_rather_than_("H/15 * * * *", "*/15 * * * *"), new CronTab("*/15 * * * *").checkSanity()); - // XXX 0,15,30,45 * * * * → H/15 * * * * + assertEquals(Messages.CronTab_spread_load_evenly_by_using_rather_than_("H/15 * * * *", "0,15,30,45 * * * *"), new CronTab("0,15,30,45 * * * *").checkSanity()); assertEquals(Messages.CronTab_spread_load_evenly_by_using_rather_than_("H * * * *", "0 * * * *"), new CronTab("0 * * * *").checkSanity()); + assertEquals(Messages.CronTab_spread_load_evenly_by_using_rather_than_("H * * * *", "5 * * * *"), new CronTab("5 * * * *").checkSanity()); // if the user specifically asked for 3:00 AM, probably we should stick to 3:00–3:59 assertEquals(Messages.CronTab_spread_load_evenly_by_using_rather_than_("H 3 * * *", "0 3 * * *"), new CronTab("0 3 * * *").checkSanity()); - + assertEquals(Messages.CronTab_spread_load_evenly_by_using_rather_than_("H 22 * * 6", "00 22 * * 6"), new CronTab("00 22 * * 6").checkSanity()); assertEquals(null, new CronTab("H/15 * 1 1 *").checkSanity()); }