Skip to content

Commit

Permalink
Merge pull request #2 from rseguy/master
Browse files Browse the repository at this point in the history
[FIXED JENKINS-9217 JENKINS-9391]
  • Loading branch information
rseguy committed May 23, 2011
2 parents d22c738 + ba2c25d commit 418d072
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 20 deletions.
@@ -1,5 +1,31 @@
/*
* The MIT License
*
* Copyright (c) 2010-2011, InfraDNA, Inc., Manufacture Francaise des Pneumatiques Michelin,
* Romain Seguy
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package hudson.plugins.parameterizedtrigger;

import org.apache.commons.lang.StringUtils;
import hudson.Extension;
import hudson.model.Describable;
import hudson.model.Descriptor;
Expand All @@ -18,28 +44,50 @@
* @author Kohsuke Kawaguchi
*/
public class BlockingBehaviour implements Describable<BlockingBehaviour> {
public final Result buildStepFailureThreshold;
public final Result unstableThreshold;
public final Result failureThreshold;

@DataBoundConstructor
public BlockingBehaviour(String unstableThreshold, String failureThreshold) {
public BlockingBehaviour(String buildStepFailureThreshold, String unstableThreshold, String failureThreshold) {
this.buildStepFailureThreshold = parse(buildStepFailureThreshold);
this.unstableThreshold = parse(unstableThreshold);
this.failureThreshold = parse(failureThreshold);
}

private Result parse(String t) {
return t.equals("never") ? null : Result.fromString(t);
if(StringUtils.isBlank(t) || "never".equals(t)) {
return null;
}
return Result.fromString(t);
}

public BlockingBehaviour(Result unstableThreshold, Result failureThreshold) {
public BlockingBehaviour(Result buildStepFailureThreshold, Result unstableThreshold, Result failureThreshold) {
this.buildStepFailureThreshold = buildStepFailureThreshold;
this.unstableThreshold = unstableThreshold;
this.failureThreshold = failureThreshold;
}

/**
* Maps the result of a triggered build to the result of the triggering build step.
*
* @param r the {@link Result} of the triggered build to map
* @return {@code false} if the triggering build step has to fail, {@code true} otherwise
*/
public boolean mapBuildStepResult(Result r) {
if (buildStepFailureThreshold!=null && r.isWorseOrEqualTo(buildStepFailureThreshold)) {
return false;
}
return true;
}

/**
* Maps the result of the triggered build to the result of the triggering build.
* Maps the result of a triggered build to the result of the triggering build.
*
* @param r the {@link Result} of the triggered build to map
* @return the result of the triggering build
*/
public Result mapResult(Result r) {
public Result mapBuildResult(Result r) {
if (failureThreshold!=null && r.isWorseOrEqualTo(failureThreshold)) return FAILURE;
if (unstableThreshold!=null && r.isWorseOrEqualTo(unstableThreshold)) return UNSTABLE;
return SUCCESS;
Expand Down
Expand Up @@ -69,7 +69,7 @@ public void buildDependencyGraph(AbstractProject owner, DependencyGraph graph) {
if (!canDeclare(owner)) return;

for (BuildTriggerConfig config : configs)
for (AbstractProject project : config.getProjectList())
for (AbstractProject project : config.getProjectList(null))
ParameterizedDependency.add(owner, project, config, graph);
}

Expand Down
@@ -1,5 +1,6 @@
package hudson.plugins.parameterizedtrigger;

import hudson.EnvVars;
import static hudson.Util.fixEmpty;
import hudson.Extension;
import hudson.Launcher;
Expand Down Expand Up @@ -31,6 +32,7 @@
import java.util.LinkedHashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.StringTokenizer;
import java.util.concurrent.Future;

public class BuildTriggerConfig implements Describable<BuildTriggerConfig> {
Expand All @@ -41,6 +43,10 @@ public class BuildTriggerConfig implements Describable<BuildTriggerConfig> {
private final ResultCondition condition;
private boolean triggerWithNoParameters;

// the list of projects to build is computed in getProjectList() ; this method
// is actually invoked twice (when in a build step), so let's cache its result
private transient List<AbstractProject> projectList;

@DataBoundConstructor
public BuildTriggerConfig(String projects, ResultCondition condition,
boolean triggerWithNoParameters, List<AbstractBuildParameters> configs) {
Expand Down Expand Up @@ -70,10 +76,26 @@ public ResultCondition getCondition() {
public boolean getTriggerWithNoParameters() {
return triggerWithNoParameters;
}

public List<AbstractProject> getProjectList() {
List<AbstractProject> projectList = new ArrayList<AbstractProject>();
projectList.addAll(Items.fromNameList(projects, AbstractProject.class));

/**
* @param env Environment variables from which to expand project names; Might be {@code null}.
*/
public List<AbstractProject> getProjectList(EnvVars env) {
if(projectList == null) {
projectList = new ArrayList<AbstractProject>();

// expand variables if applicable
StringBuilder projectNames = new StringBuilder();
StringTokenizer tokens = new StringTokenizer(projects,",");
while(tokens.hasMoreTokens()) {
if(projectNames.length() > 0) {
projectNames.append(',');
}
projectNames.append(env != null ? env.expand(tokens.nextToken().trim()) : tokens.nextToken().trim());
}

projectList.addAll(Items.fromNameList(projectNames.toString(), AbstractProject.class));
}
return projectList;
}

Expand Down Expand Up @@ -141,12 +163,15 @@ List<Action> getBuildActions(List<Action> baseActions, AbstractProject project)
*/
public List<Future<AbstractBuild>> perform(AbstractBuild<?, ?> build, Launcher launcher,
BuildListener listener) throws InterruptedException, IOException {
try {
EnvVars env = build.getEnvironment(listener);
env.overrideAll(build.getBuildVariables());

try {
if (condition.isMet(build.getResult())) {
List<Action> actions = getBaseActions(build, listener);

List<Future<AbstractBuild>> futures = new ArrayList<Future<AbstractBuild>>();
for (AbstractProject project : getProjectList()) {
for (AbstractProject project : getProjectList(env)) {
List<Action> list = getBuildActions(actions, project);

futures.add(schedule(build, project, list));
Expand Down
@@ -1,6 +1,32 @@
/*
* The MIT License
*
* Copyright (c) 2010-2011, InfraDNA, Inc., Manufacture Francaise des Pneumatiques Michelin,
* Romain Seguy
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package hudson.plugins.parameterizedtrigger;

import hudson.AbortException;
import hudson.EnvVars;
import hudson.Extension;
import hudson.Launcher;
import hudson.Util;
Expand Down Expand Up @@ -54,35 +80,50 @@ public BuildStepMonitor getRequiredMonitorService() {
@Override
public boolean perform(AbstractBuild<?, ?> build, Launcher launcher,
BuildListener listener) throws InterruptedException, IOException {
EnvVars env = build.getEnvironment(listener);
env.overrideAll(build.getBuildVariables());

Map<BlockableBuildTriggerConfig,List<Future<AbstractBuild>>> futures = new HashMap<BlockableBuildTriggerConfig, List<Future<AbstractBuild>>>();
for (BlockableBuildTriggerConfig config : configs) {
futures.put(config,config.perform(build, launcher, listener));
futures.put(config, config.perform(build, launcher, listener));
}

boolean buildStepResult = true;

try {
for (Entry<BlockableBuildTriggerConfig, List<Future<AbstractBuild>>> e : futures.entrySet()) {
int n=0;
if(!e.getKey().getProjectList().isEmpty()){
AbstractProject p = e.getKey().getProjectList().get(n);
BlockableBuildTriggerConfig config = e.getKey();
List<AbstractProject> projectList = config.getProjectList(env);

if(!projectList.isEmpty()){
AbstractProject p = projectList.get(n);
for (Future<AbstractBuild> f : e.getValue()) {
try {
listener.getLogger().println("Waiting for the completion of "+p.getFullDisplayName());
AbstractBuild b = f.get();
listener.getLogger().println(b.getFullDisplayName()+" completed. Result was "+b.getResult());
build.setResult(e.getKey().getBlock().mapResult(b.getResult()));

if(buildStepResult && config.getBlock().mapBuildStepResult(b.getResult())) {
build.setResult(config.getBlock().mapBuildResult(b.getResult()));
}
else {
buildStepResult = false;
}
} catch (CancellationException x) {
throw new AbortException(p.getFullDisplayName() +" aborted.");
}
n++;
}
}else{
} else {
throw new AbortException("Build aborted. No projects to trigger. Check your configuration!");
}
}
} catch (ExecutionException e) {
throw new IOException2(e); // can't happen, I think.
}

return true;
return buildStepResult;
}

@Extension
Expand Down
@@ -0,0 +1,44 @@
<!--
- The MIT License
-
- Copyright (c) 2011, Manufacture Francaise des Pneumatiques Michelin, Romain Seguy
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
-->

<div>
When activating this option, triggered builds will be run synchronously. The
result of the current build step or the current build can then be controlled
using the three following options:<br/><ul>
<li><b>Fail this build step if the triggered build is worse or equal to</b>:
This option takes precedence over the two following ones if its value is not
<b>never</b>. In that case, the result of the current build step (that is,
success or failure) is based on the result of the triggered builds. If the
condition defined for at least one of the triggered build is met, then the
build step will be considered as failed.</li>
<li><b>Mark this build as failure if the triggered build is worse or equal to</b>:
This option takes precedence over the next one if its value is not set to
<b>never</b>. In that case, the current build will be considered as failed
based on the result of the triggered builds and the value of the option.</li>
<li><b>Mark this build as unstable if the triggered build is worse or equal to</b>:
This option is taken into account if its value is not <b>never</b>. In that
case, the build will be considered as unstable based on the result of the
triggered builds and the value of this option.</li>
</ul>
</div>
@@ -1,7 +1,8 @@
<!--
The MIT License
Copyright (c) 2010, InfraDNA, Inc.
Copyright (c) 2010-2011, InfraDNA, Inc., Manufacture Francaise des Pneumatiques Michelin,
Romain Seguy
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand All @@ -22,7 +23,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<f:entry title="${%Mark this build as unstable if the triggered build is worse or equal to}" field="unstableThreshold">
<f:entry title="${%Fail this build step if the triggered build is worse or equal to}" field="buildStepFailureThreshold">
<select class="setting-input" name="${field}">
<f:option value="never">${%never}</f:option>
<j:forEach var="it" items="${descriptor.allResults}">
Expand All @@ -43,4 +44,16 @@ THE SOFTWARE.
</j:forEach>
</select>
</f:entry>

<f:entry title="${%Mark this build as unstable if the triggered build is worse or equal to}" field="unstableThreshold">
<select class="setting-input" name="${field}">
<f:option value="never">${%never}</f:option>
<j:forEach var="it" items="${descriptor.allResults}">
<f:option value="${it}" selected="${it==instance[field]}">
${it}
</f:option>
</j:forEach>
</select>
</f:entry>

</j:jelly>

0 comments on commit 418d072

Please sign in to comment.