Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[FIXED JENKINS-30411] - Add the PROMOTION_ENV token macro
- Loading branch information
1 parent
54fd9a0
commit 71dd420
Showing
4 changed files
with
267 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
81 changes: 81 additions & 0 deletions
81
src/main/java/hudson/plugins/promoted_builds/tokenmacro/PromotedEnvVarTokenMacro.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/* | ||
* The MIT License | ||
* | ||
* Copyright (c) 2015 Oleg Nenashev. | ||
* | ||
* 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.promoted_builds.tokenmacro; | ||
|
||
import com.google.common.collect.ListMultimap; | ||
import hudson.Extension; | ||
import hudson.model.AbstractBuild; | ||
import hudson.model.Executor; | ||
import hudson.model.Queue; | ||
import hudson.model.TaskListener; | ||
import hudson.plugins.promoted_builds.Promotion; | ||
import java.io.IOException; | ||
import java.util.Map; | ||
import org.jenkinsci.plugins.tokenmacro.DataBoundTokenMacro; | ||
import org.jenkinsci.plugins.tokenmacro.DataBoundTokenMacro.Parameter; | ||
import org.jenkinsci.plugins.tokenmacro.MacroEvaluationException; | ||
import org.jenkinsci.plugins.tokenmacro.impl.EnvironmentVariableMacro; | ||
|
||
/** | ||
* Retrieves an environment variable from the {@link Promotion} build. | ||
* The {@link Promotion} build is being determined by the current {@link Executor}, | ||
* so the macro is tolerant against context switches when the variable is being | ||
* resolved against the parent build instead of the {@link Promotion}. | ||
* In other cases the macro will behave similarly to {@link EnvironmentVariableMacro} from | ||
* Token Macro plugin. | ||
* @author Oleg Nenashev | ||
*/ | ||
@Extension(optional = true) | ||
public class PromotedEnvVarTokenMacro extends DataBoundTokenMacro { | ||
|
||
@Parameter(required=true) | ||
public String var = ""; | ||
|
||
@Override | ||
public String evaluate(AbstractBuild<?, ?> build, TaskListener listener, String macroName) | ||
throws MacroEvaluationException, IOException, InterruptedException { | ||
|
||
Executor currentExecutor = Executor.currentExecutor(); | ||
if (currentExecutor == null) { | ||
return null; | ||
} | ||
|
||
Queue.Executable executable = currentExecutor.getCurrentExecutable(); | ||
if (!(executable instanceof Promotion)) { | ||
return ""; // Nothing to do if it is not promotion | ||
} | ||
|
||
Map<String, String> env = ((Promotion)executable).getEnvironment(listener); | ||
if(env.containsKey(var)){ | ||
return env.get(var); | ||
} | ||
return ""; | ||
} | ||
|
||
@Override | ||
public boolean acceptsMacroName(String macroName) { | ||
return macroName.equals("PROMOTION_ENV"); | ||
} | ||
|
||
} |
11 changes: 11 additions & 0 deletions
11
src/main/resources/hudson/plugins/promoted_builds/tokenmacro/help.jelly
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<j:jelly xmlns:j="jelly:core"> | ||
<dt>$${PROMOTION_ENV,var="VARIABLENAME"}</dt> | ||
<dd> | ||
Expands to an environment variable (specified here as VARIABLENAME) from the | ||
<a href="https://wiki.jenkins-ci.org/display/JENKINS/Promoted+Builds+Plugin">Promotion build</a> environment. | ||
If current build is not a promotion, returns empty string. | ||
<p/> | ||
Note that this does not include any variables set by the build scripts themselves, | ||
only those set by Jenkins and other plugins. | ||
</dd> | ||
</j:jelly> |
169 changes: 169 additions & 0 deletions
169
src/test/java/hudson/plugins/promoted_builds/tokenmacro/PromotedEnvVarTokenMacroTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
/* | ||
* The MIT License | ||
* | ||
* Copyright (c) 2015 CloudBees, Inc.. | ||
* | ||
* 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.promoted_builds.tokenmacro; | ||
|
||
import hudson.EnvVars; | ||
import hudson.Launcher; | ||
import hudson.model.AbstractBuild; | ||
import hudson.model.AbstractProject; | ||
import hudson.model.Action; | ||
import hudson.model.Build; | ||
import hudson.model.BuildListener; | ||
import hudson.model.FreeStyleBuild; | ||
import hudson.model.FreeStyleProject; | ||
import hudson.model.ParameterValue; | ||
import hudson.model.StringParameterDefinition; | ||
import hudson.model.StringParameterValue; | ||
import hudson.model.TaskListener; | ||
import hudson.model.User; | ||
import hudson.plugins.promoted_builds.JobPropertyImpl; | ||
import hudson.plugins.promoted_builds.Promotion; | ||
import hudson.plugins.promoted_builds.PromotionProcess; | ||
import hudson.plugins.promoted_builds.conditions.ManualCondition; | ||
import hudson.tasks.BuildStepDescriptor; | ||
import hudson.tasks.BuildStepMonitor; | ||
import hudson.tasks.Publisher; | ||
import hudson.tasks.Recorder; | ||
import hudson.util.StreamTaskListener; | ||
import java.io.IOException; | ||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.LinkedList; | ||
import org.acegisecurity.context.SecurityContextHolder; | ||
import org.jenkinsci.plugins.tokenmacro.MacroEvaluationException; | ||
import org.jenkinsci.plugins.tokenmacro.TokenMacro; | ||
import static org.junit.Assert.assertEquals; | ||
import org.junit.Rule; | ||
import org.junit.Test; | ||
import org.jvnet.hudson.test.JenkinsRule; | ||
import org.jvnet.hudson.test.MockFolder; | ||
import org.jvnet.hudson.test.TestExtension; | ||
import org.kohsuke.stapler.DataBoundConstructor; | ||
|
||
/** | ||
* Tests for {@link PromotedEnvVarTokenMacro}. | ||
* @author Oleg Nenashev | ||
*/ | ||
public class PromotedEnvVarTokenMacroTest { | ||
|
||
@Rule | ||
public final JenkinsRule r = new JenkinsRule(); | ||
|
||
@Test | ||
public void testEnvironmentVariableExpansion() throws Exception { | ||
// Assemble | ||
r.jenkins.setSecurityRealm(r.createDummySecurityRealm()); | ||
User u = User.get("foo"); | ||
u.setFullName("Foobar"); | ||
|
||
SecurityContextHolder.getContext().setAuthentication(u.impersonate()); | ||
|
||
MockFolder parent = r.createFolder("Folder"); | ||
FreeStyleProject project = parent.createProject(FreeStyleProject.class, "Project"); | ||
|
||
JobPropertyImpl promotionProperty = new JobPropertyImpl(project); | ||
PromotionProcess promotionProcess = promotionProperty.addProcess("promo"); | ||
promotionProcess.conditions.clear(); | ||
ManualCondition manualCondition = new ManualCondition(); | ||
manualCondition.getParameterDefinitions().add(new StringParameterDefinition("PROMOTION_PARAM", "defaultValue")); | ||
promotionProcess.conditions.add(manualCondition); | ||
Action approvalAction = new ManualCondition.ManualApproval(promotionProcess.getName(), | ||
new LinkedList<ParameterValue>()); | ||
TokenMacroExpressionRecorder recorder = new TokenMacroExpressionRecorder("${PROMOTION_ENV,var=\"PROMOTION_PARAM\"}"); | ||
promotionProcess.getBuildSteps().add(recorder); | ||
|
||
// Act & promote | ||
FreeStyleBuild build = project.scheduleBuild2(0).get(); | ||
build.addAction(approvalAction); | ||
build.save(); | ||
Promotion promotion = promotionProcess.considerPromotion2(build, | ||
Arrays.asList((ParameterValue)new StringParameterValue("PROMOTION_PARAM", "FOO"))).get(); | ||
|
||
// Check results | ||
EnvVars env = promotion.getEnvironment(TaskListener.NULL); | ||
assertEquals("The PROMOTION_PARAM variable has not been injected" | ||
, "FOO", env.get("PROMOTION_PARAM")); | ||
assertEquals("The promotion variable value has not been resolved by the PROMOTION_PARAM macro" | ||
, "FOO", recorder.getCaptured()); | ||
} | ||
|
||
private static class TokenMacroExpressionRecorder extends Recorder { | ||
|
||
private final String expression; | ||
private transient String captured; | ||
|
||
@DataBoundConstructor | ||
public TokenMacroExpressionRecorder(String expression) { | ||
|
||
this.expression = expression; | ||
} | ||
|
||
public String getCaptured() { | ||
return captured; | ||
} | ||
|
||
public String getExpression() { | ||
return expression; | ||
} | ||
|
||
@Override | ||
public BuildStepMonitor getRequiredMonitorService() { | ||
return BuildStepMonitor.NONE; | ||
} | ||
|
||
@Override | ||
public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) | ||
throws InterruptedException, IOException { | ||
if (build instanceof Promotion) { | ||
AbstractBuild<?, ?> target = ((Promotion)build).getTarget(); | ||
return performWithParentBuild(build, listener); | ||
} | ||
return false; | ||
} | ||
|
||
private boolean performWithParentBuild(AbstractBuild<?, ?> build, BuildListener listener) | ||
throws InterruptedException, IOException { | ||
try { | ||
captured = TokenMacro.expand(build, listener, expression); | ||
} catch (MacroEvaluationException ex) { | ||
throw new IOException(ex); | ||
} | ||
return true; | ||
} | ||
|
||
@TestExtension("testEnvironmentVariableExpansion") | ||
public static class DescriptorImpl extends BuildStepDescriptor<Publisher> { | ||
|
||
@Override | ||
public boolean isApplicable(Class<? extends AbstractProject> jobType) { | ||
return true; | ||
} | ||
|
||
@Override | ||
public String getDisplayName() { | ||
return "Perform Token Macro expression using the parent build"; | ||
} | ||
} | ||
} | ||
} |