Skip to content

Commit e008d4e

Browse files
committed
validate cron parameters against project parameters, warning if cron includes unmatched
better use of i81n via parameters
1 parent 796a5c3 commit e008d4e

7 files changed

Lines changed: 117 additions & 66 deletions

File tree

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package org.jenkinsci.plugins.parameterizedschedular;
2+
3+
import static hudson.Util.fixNull;
4+
import hudson.Extension;
5+
import hudson.model.Item;
6+
import hudson.model.AbstractProject;
7+
import hudson.model.ParametersDefinitionProperty;
8+
import hudson.triggers.TriggerDescriptor;
9+
import hudson.util.FormValidation;
10+
11+
import org.kohsuke.stapler.AncestorInPath;
12+
import org.kohsuke.stapler.QueryParameter;
13+
14+
import antlr.ANTLRException;
15+
16+
@Extension
17+
public class DescriptorImpl extends TriggerDescriptor {
18+
19+
/**
20+
* I don't like inner classes. Using the declaritive support here by calling super constructor with class.
21+
*/
22+
public DescriptorImpl() {
23+
super(ParameterizedTimerTrigger.class);
24+
}
25+
26+
@SuppressWarnings("rawtypes")
27+
@Override
28+
public boolean isApplicable(Item item) {
29+
boolean result = false;
30+
if (item instanceof AbstractProject) {
31+
result = ((AbstractProject) item).isParameterized();
32+
}
33+
return result;
34+
}
35+
36+
@Override
37+
public String getDisplayName() {
38+
return Messages.ParameterizedTimerTrigger_DisplayName();
39+
}
40+
41+
/**
42+
* Performs syntax check.
43+
*/
44+
public FormValidation doCheckParameterizedSpecification(@QueryParameter String value,
45+
@AncestorInPath AbstractProject<?, ?> project) {
46+
try {
47+
48+
String msg = ParameterizedCronTabList.create(fixNull(value)).checkSanity();
49+
if (msg != null) {
50+
return FormValidation.warning(msg);
51+
}
52+
53+
ParametersDefinitionProperty paramDefProp = project.getProperty(ParametersDefinitionProperty.class);
54+
msg = new ParameterParser().checkSanity(value, paramDefProp);
55+
if (msg != null) {
56+
return FormValidation.warning(msg);
57+
}
58+
59+
return FormValidation.ok();
60+
} catch (ANTLRException e) {
61+
if (value.trim().indexOf('\n') == -1 && value.contains("**"))
62+
return FormValidation.error(Messages.ParameterizedTimerTrigger_MissingWhitespace());
63+
return FormValidation.error(e.getMessage());
64+
} catch (IllegalArgumentException e) {
65+
return FormValidation.error(e.getMessage());
66+
}
67+
}
68+
}

src/main/java/org/jenkinsci/plugins/parameterizedschedular/ParameterParser.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package org.jenkinsci.plugins.parameterizedschedular;
22

3+
import hudson.model.ParametersDefinitionProperty;
4+
5+
import java.util.ArrayList;
6+
import java.util.List;
37
import java.util.Map;
48

59
import org.apache.commons.lang.StringUtils;
@@ -32,7 +36,7 @@ public Map<String, String> parse(String nameValuePairFormattedString) {
3236
return Splitter.on(PAIR_SEPARATOR).withKeyValueSeparator(NAME_VALUE_SEPARATOR).split(clean);
3337
}
3438

35-
public String checkSanity(String cronTabSpec) {
39+
public String checkSanity(String cronTabSpec, ParametersDefinitionProperty parametersDefinitionProperty) {
3640
String[] split = cronTabSpec.split(PARAMETER_SEPARATOR);
3741
if (split.length < 2) {
3842
return null;
@@ -42,7 +46,13 @@ public String checkSanity(String cronTabSpec) {
4246
}
4347

4448
try {
45-
parse(split[1]);
49+
Map<String, String> parsedParameters = parse(split[1]);
50+
List<String> parameterDefinitionNames = parametersDefinitionProperty.getParameterDefinitionNames();
51+
List<String> parsedKeySet = new ArrayList<String>(parsedParameters.keySet());
52+
parsedKeySet.removeAll(parameterDefinitionNames);
53+
if (!parsedKeySet.isEmpty()) {
54+
return Messages.ParameterizedTimerTrigger_UndefinedParameter(parsedKeySet, parameterDefinitionNames);
55+
}
4656
} catch (IllegalArgumentException e) {
4757
return e.getMessage();
4858
}

src/main/java/org/jenkinsci/plugins/parameterizedschedular/ParameterizedTimerTrigger.java

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,12 @@
11
package org.jenkinsci.plugins.parameterizedschedular;
22

3-
import static hudson.Util.fixNull;
4-
import hudson.Extension;
5-
import hudson.model.Item;
63
import hudson.model.ParameterValue;
74
import hudson.model.AbstractProject;
85
import hudson.model.ParameterDefinition;
96
import hudson.model.ParametersAction;
107
import hudson.model.ParametersDefinitionProperty;
118
import hudson.scheduler.Hash;
129
import hudson.triggers.Trigger;
13-
import hudson.triggers.TriggerDescriptor;
14-
import hudson.util.FormValidation;
1510

1611
import java.util.ArrayList;
1712
import java.util.Calendar;
@@ -21,7 +16,6 @@
2116
import java.util.logging.Logger;
2217

2318
import org.kohsuke.stapler.DataBoundConstructor;
24-
import org.kohsuke.stapler.QueryParameter;
2519

2620
import antlr.ANTLRException;
2721

@@ -99,52 +93,6 @@ public void start(AbstractProject project, boolean newInstance) {
9993
}
10094
}
10195

102-
@Extension
103-
public static class DescriptorImpl extends TriggerDescriptor {
104-
@Override
105-
public boolean isApplicable(Item item) {
106-
boolean result = false;
107-
if (item instanceof AbstractProject) {
108-
result = ((AbstractProject) item).isParameterized();
109-
}
110-
return result;
111-
}
112-
113-
@Override
114-
public String getDisplayName() {
115-
return Messages.ParameterizedTimerTrigger_DisplayName();
116-
}
117-
118-
// backward compatibility
119-
public FormValidation doCheck(@QueryParameter String value) {
120-
return doCheckParameterizedSpecification(value);
121-
}
122-
123-
/**
124-
* Performs syntax check.
125-
*/
126-
public FormValidation doCheckParameterizedSpecification(@QueryParameter String value) {
127-
try {
128-
String msg = ParameterizedCronTabList.create(fixNull(value)).checkSanity();
129-
if (msg != null) {
130-
return FormValidation.warning(msg);
131-
}
132-
msg = new ParameterParser().checkSanity(value);
133-
if (msg != null) {
134-
return FormValidation.warning(msg);
135-
}
136-
137-
return FormValidation.ok();
138-
} catch (ANTLRException e) {
139-
if (value.trim().indexOf('\n') == -1 && value.contains("**"))
140-
return FormValidation.error(Messages.ParameterizedTimerTrigger_MissingWhitespace());
141-
return FormValidation.error(e.getMessage());
142-
} catch (IllegalArgumentException e) {
143-
return FormValidation.error(e.getMessage());
144-
}
145-
}
146-
}
147-
14896
/**
14997
* for the config.jelly to populate
15098
*

src/main/java/org/jenkinsci/plugins/parameterizedschedular/ParameterizedTimerTriggerCause.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ public class ParameterizedTimerTriggerCause extends Cause {
99
private final String description;
1010

1111
public ParameterizedTimerTriggerCause(Map<String, String> parameterValues) {
12-
this.description = Messages.ParameterizedTimerTrigger_TimerTriggerCause_ShortDescription()
13-
+ parameterValues.toString();
12+
this.description = Messages.ParameterizedTimerTrigger_TimerTriggerCause_ShortDescription(parameterValues
13+
.toString());
1414
}
1515

1616
@Override

src/main/resources/org/jenkinsci/plugins/parameterizedschedular/Messages.properties

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ ParameterizedTimerTrigger.DisplayName=Build periodically with parameters
22
ParameterizedTimerTrigger.MissingWhitespace=You appear to be missing whitespace between * and *.
33
ParameterizedTimerTrigger.MoreThanOnePercent=You can only use one percent sign to separate the cron from the parameters.
44
ParameterizedTimerTrigger.TrailingSemicolon=I need you to remove that semicolon from the end of the line.
5-
ParameterizedTimerTrigger.TimerTriggerCause.ShortDescription=Started by timer with parameters:
5+
ParameterizedTimerTrigger.UndefinedParameter=You have tried to schedule with parameters ({0}), which are not among saved project parameters: {1}
6+
ParameterizedTimerTrigger.TimerTriggerCause.ShortDescription=Started by timer with parameters: {0}

src/test/java/org/jenkinsci/plugins/parameterizedschedular/ParameterParserTest.java

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,24 @@
22

33
import static org.junit.Assert.assertEquals;
44
import static org.junit.Assert.assertNull;
5+
import hudson.model.ParametersDefinitionProperty;
56

7+
import java.util.Arrays;
68
import java.util.HashMap;
9+
import java.util.List;
710

811
import org.junit.Test;
12+
import org.junit.runner.RunWith;
13+
import org.mockito.Mock;
14+
import org.mockito.Mockito;
15+
import org.mockito.runners.MockitoJUnitRunner;
916

17+
@RunWith(MockitoJUnitRunner.class)
1018
public class ParameterParserTest {
1119

20+
@Mock
21+
private ParametersDefinitionProperty mockParametersDefinitionProperty;
22+
1223
@Test
1324
public void test_nullReturns_emptyMap() {
1425
ParameterParser testObject = new ParameterParser();
@@ -72,44 +83,57 @@ public void test_TwoParamsStringReturns_emptyMap() {
7283
public void checkSanity_HappyPath() throws Exception {
7384
ParameterParser testObject = new ParameterParser();
7485

75-
assertNull(testObject.checkSanity("* * * * *%name=value"));
86+
Mockito.when(mockParametersDefinitionProperty.getParameterDefinitionNames()).thenReturn(Arrays.asList("name"));
87+
assertNull(testObject.checkSanity("* * * * *%name=value", mockParametersDefinitionProperty));
88+
}
89+
90+
@Test
91+
public void checkSanity_NotDefined_ProjectParameter() throws Exception {
92+
ParameterParser testObject = new ParameterParser();
93+
94+
List<String> list = Arrays.asList("not name");
95+
Mockito.when(mockParametersDefinitionProperty.getParameterDefinitionNames()).thenReturn(list);
96+
assertEquals(Messages.ParameterizedTimerTrigger_UndefinedParameter("[name]", list.toString()),
97+
testObject.checkSanity("* * * * *%name=value", mockParametersDefinitionProperty));
7698
}
7799

78100
@Test
79101
public void checkSanity_TrailingSemiColon_IsTrimmed() throws Exception {
80102
ParameterParser testObject = new ParameterParser();
81103

82-
assertNull(testObject.checkSanity("* * * * *%env=eight;freckled=flase;frecked=false;"));
104+
Mockito.when(mockParametersDefinitionProperty.getParameterDefinitionNames()).thenReturn(
105+
Arrays.asList("env", "freckled"));
106+
assertNull(testObject.checkSanity("* * * * *%env=eight;freckled=flase;", mockParametersDefinitionProperty));
83107
}
84108

85109
@Test
86110
public void checkSanity_MoreThanOnePercent() throws Exception {
87111
ParameterParser testObject = new ParameterParser();
88112

89113
assertEquals(Messages.ParameterizedTimerTrigger_MoreThanOnePercent(),
90-
testObject.checkSanity("* * * * *%name=value;%fred=barney"));
114+
testObject.checkSanity("* * * * *%name=value;%fred=barney", mockParametersDefinitionProperty));
91115
}
92116

93117
@Test
94-
public void checkSanity_NoParaetersIsNoBigDeal() throws Exception {
118+
public void checkSanity_NoParametersIsNoBigDeal() throws Exception {
95119
ParameterParser testObject = new ParameterParser();
96120

97-
assertNull(testObject.checkSanity("* * * * *%"));
98-
assertNull(testObject.checkSanity("* * * * *"));
121+
assertNull(testObject.checkSanity("* * * * *%", mockParametersDefinitionProperty));
122+
assertNull(testObject.checkSanity("* * * * *", mockParametersDefinitionProperty));
99123
}
100124

101125
@Test
102126
public void checkSanity_duplicateParamName() throws Exception {
103127
ParameterParser testObject = new ParameterParser();
104128

105-
testObject.checkSanity("* * * * *%name=value;name=value2");
129+
testObject.checkSanity("* * * * *%name=value;name=value2", mockParametersDefinitionProperty);
106130
}
107131

108132
@Test
109133
public void checkSanity_UnmatchedEquals() throws Exception {
110134
ParameterParser testObject = new ParameterParser();
111135

112-
testObject.checkSanity("* * * * *%name=value;name2=");
136+
testObject.checkSanity("* * * * *%name=value;name2=", mockParametersDefinitionProperty);
113137
}
114138

115139
}

src/test/java/org/jenkinsci/plugins/parameterizedschedular/ParameterizedTimerTriggerCauseTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public void happyPath() {
1616
parameters.put("o", "v");
1717
ParameterizedTimerTriggerCause testObject = new ParameterizedTimerTriggerCause(parameters);
1818

19-
assertEquals(Messages.ParameterizedTimerTrigger_TimerTriggerCause_ShortDescription() + "{o=v}",
19+
assertEquals(Messages.ParameterizedTimerTrigger_TimerTriggerCause_ShortDescription("{o=v}"),
2020
testObject.getShortDescription());
2121
}
2222

0 commit comments

Comments
 (0)