Skip to content
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

enable changing parameter value for promotion re-execution #27

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
78 changes: 50 additions & 28 deletions src/main/java/hudson/plugins/promoted_builds/Promotion.java
Expand Up @@ -2,19 +2,19 @@

import hudson.EnvVars;
import hudson.console.HyperlinkNote;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.model.Cause;
import hudson.model.Node;
import hudson.model.Result;
import hudson.model.Run;
import hudson.model.Action;
import hudson.model.CauseAction;
import hudson.model.Environment;
import hudson.model.ParameterValue;
import hudson.model.Result;
import hudson.model.TaskListener;
import hudson.model.TopLevelItem;
import hudson.plugins.promoted_builds.conditions.ManualCondition.ManualApproval;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Node;
import hudson.model.ParameterDefinition;
import hudson.model.Run;
import hudson.plugins.promoted_builds.conditions.ManualCondition;
import hudson.security.Permission;
import hudson.security.PermissionGroup;
import hudson.security.PermissionScope;
Expand All @@ -23,15 +23,18 @@
import hudson.tasks.BuildStep;
import hudson.tasks.BuildWrapper;
import hudson.tasks.BuildTrigger;
import hudson.triggers.Trigger;
import jenkins.model.Jenkins;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import java.util.Map.Entry;

import jenkins.model.Jenkins;


/**
* Records a promotion process.
*
Expand Down Expand Up @@ -105,6 +108,29 @@ public EnvVars getEnvironment(TaskListener listener) throws IOException, Interru

return e;
}

public List<ParameterValue> getParameterValues(){
PromotionParametersAction parametersAction=getAction(PromotionParametersAction.class);
if (parametersAction!=null){
return parametersAction.getParameters();
}
for (PromotionBadge badget:getStatus().getBadges()){
if (badget instanceof ManualCondition.Badge){
return ((ManualCondition.Badge) badget).getParameterValues();
}
}
return Collections.emptyList();
}

public List<ParameterDefinition> getParameterDefinitionsWithValue(){
List<ParameterDefinition> definitions=new ArrayList<ParameterDefinition>();
ManualCondition manualCondition=(ManualCondition) getProject().getPromotionCondition(ManualCondition.class.getName());
for (ParameterValue pvalue:getParameterValues()){
ParameterDefinition pdef=manualCondition.getParameterDefinition(pvalue.getName());
definitions.add(pdef.copyWithDefaultValue(pvalue));
}
return definitions;
}

public void run() {
getStatus().addPromotionAttempt(this);
Expand Down Expand Up @@ -144,24 +170,20 @@ protected Result doRun(BuildListener listener) throws Exception {
return Result.FAILURE;

try {
PromotionTargetAction targetAction = getAction(PromotionTargetAction.class);
AbstractBuild<?, ?> build = targetAction.resolve();
List<ManualApproval> approvals = build.getActions(ManualApproval.class);
for(ManualApproval approval : approvals) {
List<ParameterValue> params = approval.badge.getParameterValues();

for(ParameterValue value : params) {
BuildWrapper wrapper = value.createBuildWrapper(Promotion.this);
if(wrapper != null) {
Environment e = wrapper.setUp(Promotion.this, launcher, listener);

if(e==null)
return Result.FAILURE;

buildEnvironments.add(e);
}
}
}
//PromotionTargetAction targetAction = getAction(PromotionTargetAction.class);
List<ParameterValue> params=getParameterValues();

if (params!=null){
for(ParameterValue value : params) {
BuildWrapper wrapper=value.createBuildWrapper(Promotion.this);
if (wrapper!=null){
Environment e = wrapper.setUp(Promotion.this, launcher, listener);
if(e==null)
return Result.FAILURE;
buildEnvironments.add(e);
}
}
}

if(!build(listener,project.getBuildSteps(),target))
return Result.FAILURE;
Expand Down
@@ -0,0 +1,18 @@
package hudson.plugins.promoted_builds;

import java.util.List;

import hudson.model.ParameterValue;
import hudson.model.ParametersAction;

public class PromotionParametersAction extends ParametersAction {

public PromotionParametersAction(List<ParameterValue> parameters) {
super(parameters);
}

public PromotionParametersAction(ParameterValue... parameters) {
super(parameters);
}

}
Expand Up @@ -8,8 +8,9 @@
import hudson.model.AbstractProject;
import hudson.model.Action;
import hudson.model.AutoCompletionCandidates;
import hudson.model.ParameterValue;
import hudson.model.Cause;
import hudson.model.Cause.LegacyCodeCause;
import hudson.model.Cause.UserCause;
import hudson.model.DependencyGraph;
import hudson.model.Describable;
import hudson.model.Descriptor;
Expand All @@ -28,6 +29,7 @@
import hudson.model.Saveable;
import hudson.model.labels.LabelAtom;
import hudson.model.labels.LabelExpression;
import hudson.plugins.promoted_builds.conditions.ManualCondition.ManualApproval;
import hudson.tasks.BuildStep;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.Builder;
Expand Down Expand Up @@ -314,7 +316,7 @@ public Future<Promotion> considerPromotion2(AbstractBuild<?,?> build) throws IOE
return null; // not this time

LOGGER.fine("Promotion condition of "+build+" is met: "+qualification);
Future<Promotion> f = promote2(build, new LegacyCodeCause(), qualification); // TODO: define promotion cause
Future<Promotion> f = promote2(build, new UserCause(), qualification); // TODO: define promotion cause
if (f==null)
LOGGER.warning(build+" qualifies for a promotion but the queueing failed.");
return f;
Expand Down Expand Up @@ -363,7 +365,7 @@ public boolean scheduleBuild() {
}

public boolean scheduleBuild(AbstractBuild<?,?> build) {
return scheduleBuild(build,new LegacyCodeCause());
return scheduleBuild(build,new UserCause());
}

/**
Expand All @@ -374,7 +376,7 @@ public boolean scheduleBuild(AbstractBuild<?,?> build, Cause cause) {
return scheduleBuild2(build,cause)!=null;
}

public Future<Promotion> scheduleBuild2(AbstractBuild<?,?> build, Cause cause) {
public Future<Promotion> scheduleBuild2(AbstractBuild<?,?> build, Cause cause, List<ParameterValue> params) {
assert build.getProject()==getOwner();

// Get the parameters, if any, used in the target build and make these
Expand All @@ -384,11 +386,27 @@ public Future<Promotion> scheduleBuild2(AbstractBuild<?,?> build, Cause cause) {
// Create list of actions to pass to scheduled build
List<Action> actions = new ArrayList<Action>();
actions.addAll(parameters);

actions.add(new PromotionTargetAction(build));

if (params!=null && params.size()> 0){
actions.add(new PromotionParametersAction(params));
}
// remember what build we are promoting
return super.scheduleBuild2(0, cause, actions.toArray(new Action[actions.size()]));
}

public Future<Promotion> scheduleBuild2(AbstractBuild<?,?> build, Cause cause) {
List<ParameterValue> params=new ArrayList<ParameterValue>();
List<ManualApproval> approvals = build.getActions(ManualApproval.class);
if (approvals!=null){
for(ManualApproval approval : approvals) {
params.addAll(approval.badge.getParameterValues());
}
}

// remember what build we are promoting
return scheduleBuild2(build, cause, params);
}

public boolean isInQueue(AbstractBuild<?,?> build) {
for (Item item : Hudson.getInstance().getQueue().getItems(this))
Expand Down
44 changes: 43 additions & 1 deletion src/main/java/hudson/plugins/promoted_builds/Status.java
Expand Up @@ -5,8 +5,14 @@
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Cause.UserCause;
import hudson.model.ParameterDefinition;
import hudson.model.ParameterValue;
import hudson.model.Result;
import hudson.plugins.promoted_builds.conditions.ManualCondition;
import hudson.util.Iterators;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;

Expand Down Expand Up @@ -71,6 +77,9 @@ public String getName() {
* Gets the parent {@link Status} that owns this object.
*/
public PromotedBuildAction getParent() {
if (parent==null){
parent=getTarget().getAction(PromotedBuildAction.class);
}
return parent;
}

Expand Down Expand Up @@ -279,13 +288,46 @@ public Promotion getPromotionBuild(int number) {
return p.getBuildByNumber(number);
}

public boolean isManuallyApproved(){
ManualCondition manualCondition=(ManualCondition) getProcess().getPromotionCondition(ManualCondition.class.getName());
return manualCondition!=null;
}
/**
* Schedules a new build.
*/
public void doBuild(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
if(!getTarget().hasPermission(Promotion.PROMOTE))
return;
Future<Promotion> f = getProcess().scheduleBuild2(getTarget(), new UserCause());


JSONObject formData = req.getSubmittedForm();

List<ParameterValue> paramValues=null;
if (formData!=null){
paramValues = new ArrayList<ParameterValue>();
ManualCondition manualCondition=(ManualCondition) getProcess().getPromotionCondition(ManualCondition.class.getName());
if (manualCondition!=null){
List<ParameterDefinition> parameterDefinitions=manualCondition.getParameterDefinitions();
if (parameterDefinitions != null && !parameterDefinitions.isEmpty()) {
JSONArray a = JSONArray.fromObject(formData.get("parameter"));

for (Object o : a) {
JSONObject jo = (JSONObject) o;
String name = jo.getString("name");

ParameterDefinition d = manualCondition.getParameterDefinition(name);
if (d==null)
throw new IllegalArgumentException("No such parameter definition: " + name);

paramValues.add(d.createValue(req, jo));
}
}
}
}
if (paramValues==null){
paramValues = new ArrayList<ParameterValue>();
}
Future<Promotion> f = getProcess().scheduleBuild2(getTarget(), new UserCause(), paramValues);
if (f==null)
LOGGER.warning("Failing to schedule the promotion of "+getTarget());
// TODO: we need better visual feed back so that the user knows that the build happened.
Expand Down
Expand Up @@ -13,6 +13,7 @@
import hudson.plugins.promoted_builds.PromotionBadge;
import hudson.plugins.promoted_builds.PromotionCondition;
import hudson.plugins.promoted_builds.PromotionConditionDescriptor;
import hudson.plugins.promoted_builds.Promotion;
import hudson.plugins.promoted_builds.PromotionProcess;
import java.io.IOException;
import java.util.ArrayList;
Expand Down Expand Up @@ -209,9 +210,12 @@ public List<ParameterValue> getParameterValues() {

@Override
public void buildEnvVars(AbstractBuild<?, ?> build, EnvVars env) {
for (ParameterValue value : getParameterValues()) {
value.buildEnvVars(build, env);
}
List<ParameterValue> params=((Promotion)build).getParameterValues();
if (params!=null){
for(ParameterValue value : params) {
value.buildEnvVars(build, env);
}
}
}
}

Expand Down
@@ -1,15 +1,4 @@
<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" xmlns:i="jelly:fmt" xmlns:local="local">
<d:taglib uri="local">
<d:tag name="re-promote-button">
<j:choose>
<j:when test="${it.getPromotionProcess(p.name)!=null and it.canPromote()}">
<form style="float:right" method="post" action="${p.name}/build">
<f:submit value="${%Re-execute promotion}"/>
</form>
</j:when>
</j:choose>
</d:tag>
</d:taglib>
<l:layout title="${%Promotions} : ${it.project.displayName} ${it.owner.displayName}" xmlns:local="local">
<st:include page="sidepanel.jelly" it="${it.owner}" />
<l:main-panel>
Expand Down Expand Up @@ -46,8 +35,16 @@
<!-- promotion activity -->
<h4>Status</h4>
<div>
<j:if test="${!p.isManuallyApproved()}">
<j:choose>
<j:when test="${it.getPromotionProcess(p.name)!=null and it.canPromote()}">
<form style="float:right" method="post" action="${p.name}/build">
<f:submit value="${%Re-execute promotion}"/>
</form>
</j:when>
</j:choose>
</j:if>
<j:choose>
<local:re-promote-button />
<j:when test="${p.isPromotionSuccessful()}">
<img src="${imagesURL}/16x16/blue.png" alt="Unstable" width="16" height="16" />
${%Successfully promoted} (<a href="${p.name}/lastSuccessful">${%log}</a>)
Expand Down
@@ -1,12 +1,16 @@
<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" xmlns:i="jelly:fmt">
<l:pane title="${%Manually Approved}" width="100">
<tr><td colspan="4">${%Approved by} ${it.userName}</td></tr>
<j:if test="${!it.parameterValues.isEmpty()}">
<f:section title="${%Parameters}">
<j:forEach var="parameterValue" items="${it.parameterValues}">
<st:include it="${parameterValue}" page="value.jelly" />
</j:forEach>
</f:section>
</j:if>
</l:pane>
</j:jelly>
<l:pane title="${%Manually Approved}" width="100"><tr><td>
<f:form method="post" action="${h.encode(p.name)}/build" name="build">
<j:if test="${!p.last.parameterDefinitionsWithValue.isEmpty()}">
<f:section title="${%Parameters}">
<j:forEach var="parameterDefinition" items="${p.last.parameterDefinitionsWithValue}">
<st:include it="${parameterDefinition}" page="${parameterDefinition.descriptor.valuePage}" />
</j:forEach>
</f:section>
</j:if>
<f:block>
<f:submit value="${%Re-execute promotion}" />
</f:block>
</f:form>
</td></tr></l:pane>
</j:jelly>