diff --git a/pom.xml b/pom.xml index 1462d644..d896cc0b 100644 --- a/pom.xml +++ b/pom.xml @@ -105,6 +105,12 @@ 1.10 true + + hudson.plugins + project-inheritance + 1.5.3 + true + diff --git a/src/main/java/hudson/plugins/promoted_builds/JobPropertyImpl.java b/src/main/java/hudson/plugins/promoted_builds/JobPropertyImpl.java index c809929d..82d2a76c 100644 --- a/src/main/java/hudson/plugins/promoted_builds/JobPropertyImpl.java +++ b/src/main/java/hudson/plugins/promoted_builds/JobPropertyImpl.java @@ -64,13 +64,6 @@ public final class JobPropertyImpl extends JobProperty> imp * These {@link PromotionProcess}es are active. */ private final Set activeProcessNames = new HashSet(); - -// /** -// * Names of the processes that are configured. -// * Used to construct {@link #processes}. -// */ -// private final List names = new ArrayList(); - /** * Programmatic construction. */ @@ -78,7 +71,11 @@ public JobPropertyImpl(AbstractProject owner) throws Descriptor.FormExcepti this.owner = owner; init(); } - + public JobPropertyImpl(JobPropertyImpl other, AbstractProject owner) throws Descriptor.FormException, IOException { + this.owner = owner; + this.activeProcessNames.addAll(other.activeProcessNames); + loadAllProcesses(other.getRootDir()); + } private JobPropertyImpl(StaplerRequest req, JSONObject json) throws Descriptor.FormException, IOException { // a hack to get the owning AbstractProject. // this is needed here so that we can load items @@ -112,7 +109,15 @@ private JobPropertyImpl(StaplerRequest req, JSONObject json) throws Descriptor.F } init(); } + private void loadAllProcesses(File rootDir) throws IOException { + File[] subdirs = rootDir.listFiles(new FileFilter() { + public boolean accept(File child) { + return child.isDirectory(); + } + }); + loadProcesses(subdirs); + } private void init() throws IOException { // load inactive processes File[] subdirs = getRootDir().listFiles(new FileFilter() { @@ -120,6 +125,9 @@ public boolean accept(File child) { return child.isDirectory() && !isActiveProcessNameIgnoreCase(child.getName()); } }); + loadProcesses(subdirs); + } + private void loadProcesses(File[] subdirs) throws IOException { if(subdirs!=null) { for (File subdir : subdirs) { try { @@ -179,7 +187,7 @@ protected synchronized void setOwner(AbstractProject owner) { // so use this as the initialization opportunity. // CopyListener is also using setOwner to re-init after copying config from another job. processes = new ArrayList(ItemGroupMixIn.loadChildren( - this,getRootDir(),ItemGroupMixIn.KEYED_BY_NAME).values()); + this,getRootDir(),ItemGroupMixIn.KEYED_BY_NAME).values()); try { buildActiveProcess(); } catch (IOException e) { @@ -201,7 +209,11 @@ private void buildActiveProcess() throws IOException { // ensure that the name casing matches what's given in the activeProcessName // this is because in case insensitive file system, we may end up resolving // to a directory name that differs only in their case. - p.renameTo(getActiveProcessName(p.getName())); + String processName = p.getName(); + String activeProcessName = getActiveProcessName(processName); + if (!activeProcessName.equals(processName)){ + p.renameTo(activeProcessName); + } } } @@ -352,16 +364,16 @@ public Action getJobAction(AbstractProject job) { @Extension public static final class DescriptorImpl extends JobPropertyDescriptor { - + public DescriptorImpl() { - super(); - } + super(); + } - public DescriptorImpl(Class> clazz) { - super(clazz); - } + public DescriptorImpl(Class> clazz) { + super(clazz); + } - public String getDisplayName() { + public String getDisplayName() { return "Promote Builds When..."; } diff --git a/src/main/java/hudson/plugins/promoted_builds/PromotionProcess.java b/src/main/java/hudson/plugins/promoted_builds/PromotionProcess.java index 7c7f1561..ab331831 100644 --- a/src/main/java/hudson/plugins/promoted_builds/PromotionProcess.java +++ b/src/main/java/hudson/plugins/promoted_builds/PromotionProcess.java @@ -415,9 +415,7 @@ public boolean scheduleBuild(AbstractBuild build, Cause cause) { } public Future scheduleBuild2(AbstractBuild build, Cause cause, List params) { - assert build.getProject()==getOwner(); - List actions = new ArrayList(); Promotion.buildParametersAction(actions, build, params); actions.add(new PromotionTargetAction(build)); diff --git a/src/main/java/hudson/plugins/promoted_builds/PromotionTargetAction.java b/src/main/java/hudson/plugins/promoted_builds/PromotionTargetAction.java index 1d5f0061..55f2bfb2 100644 --- a/src/main/java/hudson/plugins/promoted_builds/PromotionTargetAction.java +++ b/src/main/java/hudson/plugins/promoted_builds/PromotionTargetAction.java @@ -26,6 +26,11 @@ public AbstractBuild resolve() { } public AbstractBuild resolve(PromotionProcess parent) { + AbstractBuild build = this.resolve(); + if (build !=null){ + return build; + } + //In case of project renamed. AbstractProject j = parent.getOwner(); if (j==null) return null; return j.getBuildByNumber(number); diff --git a/src/main/java/hudson/plugins/promoted_builds/inheritance/JobPropertyImplSelector.java b/src/main/java/hudson/plugins/promoted_builds/inheritance/JobPropertyImplSelector.java new file mode 100644 index 00000000..342095f3 --- /dev/null +++ b/src/main/java/hudson/plugins/promoted_builds/inheritance/JobPropertyImplSelector.java @@ -0,0 +1,67 @@ + +package hudson.plugins.promoted_builds.inheritance; + +import org.apache.log4j.Logger; + +import hudson.Extension; +import hudson.model.JobProperty; + +import hudson.plugins.project_inheritance.projects.InheritanceProject; +import hudson.plugins.project_inheritance.projects.inheritance.InheritanceSelector; + +import hudson.plugins.promoted_builds.JobPropertyImpl; + +/** + * + * @author Jacek Tomaka + * @since TODO + */ +@Extension(optional=true) +public class JobPropertyImplSelector extends InheritanceSelector> { + private static final long serialVersionUID = 1L; + private static final Logger logger = Logger.getLogger(JobPropertyImplSelector.class); + + @Override + public boolean isApplicableFor(Class clazz){ + return JobProperty.class.isAssignableFrom(clazz); + } + + @Override + public InheritanceSelector.MODE getModeFor(Class clazz){ + if (JobPropertyImpl.class.isAssignableFrom(clazz)) return MODE.USE_LAST; + return MODE.NOT_RESPONSIBLE; + } + + @Override + public String getObjectIdentifier(JobProperty obj){ + if ( obj!=null && JobPropertyImpl.class.getName().equals(obj.getClass().getName())){ + return JobPropertyImplSelector.class.getName(); + } + return null; + } + + @Override + public JobPropertyImpl merge(JobProperty prior, JobProperty latter, InheritanceProject caller){ + return null; + } + + @Override + public JobProperty handleSingleton(JobProperty jobProperty, InheritanceProject caller){ + if (jobProperty == null || caller == null) return jobProperty; + if (caller.isAbstract) return jobProperty; + + if (!JobPropertyImpl.class.isAssignableFrom(jobProperty.getClass())) return jobProperty; + + + JobPropertyImpl jobPropertyImpl = (JobPropertyImpl)jobProperty; + + try { + JobPropertyImpl newJobProperty = new JobPropertyImpl(jobPropertyImpl, caller); + return newJobProperty; + } catch (Exception ex){ + logger.error("Error during hacking up JobPropertyImpl", ex ); + } + return jobProperty; + } +} + diff --git a/src/test/java/hudson/plugins/promoted_builds/conditions/inheritance/DownstreamPassConditionInheritanceTest.java b/src/test/java/hudson/plugins/promoted_builds/conditions/inheritance/DownstreamPassConditionInheritanceTest.java new file mode 100644 index 00000000..130cf9b5 --- /dev/null +++ b/src/test/java/hudson/plugins/promoted_builds/conditions/inheritance/DownstreamPassConditionInheritanceTest.java @@ -0,0 +1,99 @@ +/* + * The MIT License + * + * Copyright 2015 Franta Mejta + * + * 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.conditions.inheritance; + +import static org.junit.Assert.*; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.Bug; + +import hudson.model.Result; +import hudson.plugins.project_inheritance.projects.InheritanceBuild; +import hudson.plugins.project_inheritance.projects.InheritanceProject.IMode; +import hudson.plugins.promoted_builds.JobPropertyImpl; +import hudson.plugins.promoted_builds.PromotedBuildAction; +import hudson.plugins.promoted_builds.PromotionProcess; +import hudson.plugins.promoted_builds.Status; +import hudson.plugins.promoted_builds.conditions.DownstreamPassCondition; +import hudson.plugins.promoted_builds.inheritance.helpers.InheritanceProjectRule; +import hudson.plugins.promoted_builds.inheritance.helpers.InheritanceProjectsPair; +import hudson.tasks.BuildTrigger; +import jenkins.model.Jenkins; + +public final class DownstreamPassConditionInheritanceTest { + + @Rule + public InheritanceProjectRule j = new InheritanceProjectRule(); + + @Test + @Bug(7739) + public void shouldEvaluateUpstreamRecursively() throws Exception { + final InheritanceProjectsPair pair1 = j.createInheritanceProjectDerivedWithBase(); + final InheritanceProjectsPair pair2 = j.createInheritanceProjectDerivedWithBase(); + final InheritanceProjectsPair pair3 = j.createInheritanceProjectDerivedWithBase(); + + + final JobPropertyImpl property = new JobPropertyImpl(pair1.getBase()); + pair1.getBase().addProperty(property); + + final PromotionProcess process = property.addProcess("promotion"); + process.conditions.add(new DownstreamPassCondition(pair3.getDerived().getFullName())); + + pair1.getDerived().getPublishersList().add(new BuildTrigger(pair2.getDerived().getFullName(), Result.SUCCESS)); + pair2.getDerived().getPublishersList().add(new BuildTrigger(pair3.getDerived().getFullName(), Result.SUCCESS)); + Jenkins.getInstance().rebuildDependencyGraph(); + + final InheritanceBuild run1 = j.buildAndAssertSuccess(pair1.getDerived()); + j.assertBuildStatusSuccess(run1); + j.waitUntilNoActivity(); + j.assertBuildStatusSuccess(pair2.getDerived().getLastBuild()); + j.waitUntilNoActivity(); + final InheritanceBuild run3 = j.assertBuildStatusSuccess(pair3.getDerived().getLastBuild()); + j.waitUntilNoActivity(); + + //We cannot assume that the process will contain builds because the process added to base project is different to the one in derived. + JobPropertyImpl jobProperty = pair1.getDerived().getProperty(JobPropertyImpl.class, + /*Forcing inheritance as temporary hack for inheritance plugin 1.53 + because that version of the plugin uses inheritance only for certain predefined cases: + -specific methods on the call stack + -url paths. + This has been changed as pull request https://github.com/i-m-c/jenkins-inheritance-plugin/pull/40 + */ + IMode.INHERIT_FORCED); + + assertNotNull("derived jobProperty is null", jobProperty); + PromotionProcess processDerived = jobProperty.getItem("promotion"); + + assertEquals("fingerprint relation", run3.getUpstreamRelationship(pair1.getDerived()), -1); + assertFalse("no promotion process", processDerived.getBuilds().isEmpty()); + + final PromotedBuildAction action = run1.getAction(PromotedBuildAction.class); + assertNotNull("no promoted action", action); + + final Status promotion = action.getPromotion("promotion"); + assertNotNull("promotion not found", promotion); + assertTrue("promotion not successful", promotion.isPromotionSuccessful()); + } + +} diff --git a/src/test/java/hudson/plugins/promoted_builds/conditions/inheritance/ManualConditionInheritanceTest.java b/src/test/java/hudson/plugins/promoted_builds/conditions/inheritance/ManualConditionInheritanceTest.java new file mode 100644 index 00000000..c6071604 --- /dev/null +++ b/src/test/java/hudson/plugins/promoted_builds/conditions/inheritance/ManualConditionInheritanceTest.java @@ -0,0 +1,204 @@ +package hudson.plugins.promoted_builds.conditions.inheritance; + +import hudson.ExtensionList; +import hudson.model.FreeStyleBuild; +import hudson.model.ParameterDefinition; +import hudson.model.ParameterValue; +import hudson.model.Descriptor; +import hudson.model.FreeStyleProject; +import hudson.model.StringParameterDefinition; +import hudson.plugins.project_inheritance.projects.InheritanceBuild; +import hudson.plugins.project_inheritance.projects.InheritanceProject.IMode; +import hudson.plugins.promoted_builds.JobPropertyImpl; +import hudson.plugins.promoted_builds.PromotedBuildAction; +import hudson.plugins.promoted_builds.Promotion; +import hudson.plugins.promoted_builds.PromotionProcess; +import hudson.plugins.promoted_builds.Status; + +import hudson.plugins.promoted_builds.conditions.ManualCondition; +import hudson.plugins.promoted_builds.conditions.ManualCondition.ManualApproval; +import hudson.plugins.promoted_builds.inheritance.helpers.InheritanceProjectRule; +import hudson.plugins.promoted_builds.inheritance.helpers.InheritanceProjectsPair; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.SortedMap; + +import org.junit.Rule; +import org.junit.Test; + +import jenkins.model.Jenkins; + +import com.gargoylesoftware.htmlunit.html.HtmlElement; +import com.gargoylesoftware.htmlunit.html.HtmlForm; +import com.gargoylesoftware.htmlunit.html.HtmlPage; + +/** + * @author Jacek Tomaka + */ +public class ManualConditionInheritanceTest { + @Rule + public InheritanceProjectRule j = new InheritanceProjectRule(); + public static List getFormsByName(HtmlPage page, String name){ + List forms=new ArrayList(); + for (HtmlForm f:page.getForms()){ + if (name.equals(f.getNameAttribute())){ + forms.add(f); + } + } + return forms; + } + public static List getFormParameters(HtmlForm form){ + return form.getElementsByAttribute("div", "name", "parameter"); + } + @Test + public void testManualPromotionProcess() throws Exception { + InheritanceProjectsPair inheritanceProjectsPair = j.createInheritanceProjectDerivedWithBase(); + + ExtensionList list=Jenkins.getInstance().getExtensionList(Descriptor.class); + list.add(new JobPropertyImpl.DescriptorImpl(JobPropertyImpl.class)); + JobPropertyImpl base = new JobPropertyImpl(inheritanceProjectsPair.getBase()); + inheritanceProjectsPair.getBase().addProperty(base); + PromotionProcess foo = base.addProcess("foo"); + + ManualCondition condition=new ManualCondition(); + condition.getParameterDefinitions().add(new StringParameterDefinition("bogus_string_param_1", "bogus_value_1", "Bog parameter")); + condition.getParameterDefinitions().add(new StringParameterDefinition("bogus_string_param_2", "bogus_value_2", "Bog parameter")); + foo.conditions.add(condition); + + InheritanceBuild b1 = j.assertBuildStatusSuccess(inheritanceProjectsPair.getDerived().scheduleBuild2(0)); + + // promote a build + + List paramValues = condition.createDefaultValues(); + //try to add duplicate values + paramValues.addAll(condition.createDefaultValues()); + //We cannot assume that the process will contain builds because the process added to base project is different to the one in derived. + JobPropertyImpl jobProperty = inheritanceProjectsPair.getDerived().getProperty(JobPropertyImpl.class, + /*Forcing inheritance as temporary hack for inheritance plugin 1.53 + because that version of the plugin uses inheritance only for certain predefined cases: + -specific methods on the call stack + -url paths. + This has been changed as pull request https://github.com/i-m-c/jenkins-inheritance-plugin/pull/40 + */ + IMode.INHERIT_FORCED); + assertNotNull("derived jobProperty is null", jobProperty); + PromotionProcess fooDerived = jobProperty.getItem("foo"); + + j.assertBuildStatusSuccess(condition.approve(b1, fooDerived, paramValues)); + ManualApproval manualApproval=b1.getAction(ManualApproval.class); + assertNotNull(manualApproval); + + PromotedBuildAction statuses=b1.getAction(PromotedBuildAction.class); + assertNotNull(statuses); + assertNotNull(statuses.getPromotions()); + assertFalse(statuses.getPromotions().isEmpty()); + } + + + @Test + public void testManualPromotionProcessViaWebClient() throws Exception { + InheritanceProjectsPair inheritanceProjectsPair = j.createInheritanceProjectDerivedWithBase(); + + ExtensionList list=Jenkins.getInstance().getExtensionList(Descriptor.class); + list.add(new JobPropertyImpl.DescriptorImpl(JobPropertyImpl.class)); + JobPropertyImpl base = new JobPropertyImpl(inheritanceProjectsPair.getBase()); + inheritanceProjectsPair.getDerived().addProperty(base); + PromotionProcess foo = base.addProcess("foo"); + ManualCondition condition=new ManualCondition(); + condition.getParameterDefinitions().add(new StringParameterDefinition("bogus_string_param_1", "bogus_value_1", "Bog parameter")); + condition.getParameterDefinitions().add(new StringParameterDefinition("bogus_string_param_2", "bogus_value_2", "Bog parameter")); + foo.conditions.add(condition); + + InheritanceBuild b1 = j.assertBuildStatusSuccess(inheritanceProjectsPair.getDerived().scheduleBuild2(0)); + assertNull(b1.getAction(ManualApproval.class)); + HtmlPage page=j.createWebClient().getPage(b1, "promotion"); + //Approve Promotion + List forms=getFormsByName(page, "approve"); + assertFalse(forms.isEmpty()); + assertTrue(forms.size()==1); + + HtmlForm form=forms.get(0); + List parameters=getFormParameters(form); + assertTrue(parameters.size()==condition.getParameterDefinitions().size()); + for(HtmlElement param:parameters){ + HtmlElement v=param.getElementsByAttribute("input", "name", "value").get(0); + v.setAttribute("value", v.getAttribute("value")+"1"); + } + j.submit(forms.get(0)); + j.waitUntilNoActivity(); + //We cannot assume that the process will contain builds because the process added to base project is different to the one in derived. + final JobPropertyImpl jobProperty = inheritanceProjectsPair.getDerived().getProperty(JobPropertyImpl.class, + /*Forcing inheritance as temporary hack for inheritance plugin 1.53 + because that version of the plugin uses inheritance only for certain predefined cases: + -specific methods on the call stack + -url paths. + This has been changed as pull request https://github.com/i-m-c/jenkins-inheritance-plugin/pull/40 + */ + IMode.INHERIT_FORCED); + assertNotNull("derived jobProperty is null", jobProperty); + final PromotionProcess fooDerived = jobProperty.getItem("foo"); + ManualApproval approval=b1.getAction(ManualApproval.class); + assertNotNull(approval); + SortedMap builds=fooDerived.getBuildsAsMap(); + assertNotNull(builds); + assertTrue(builds.size()==1); + + //Re-Execute approved promotion + page=j.createWebClient().getPage(b1, "promotion"); + forms=getFormsByName(page,"build"); + assertFalse(forms.isEmpty()); + assertTrue(forms.size()==1); + form=forms.get(0); + parameters=getFormParameters(form); + assertTrue(parameters.size()==condition.getParameterDefinitions().size()); + + for(HtmlElement param:parameters){ + HtmlElement v=param.getElementsByAttribute("input", "name", "value").get(0); + v.setAttribute("value", v.getAttribute("value")+"2"); + } + j.submit(form); + j.waitUntilNoActivity(); + final JobPropertyImpl jobProperty2 = inheritanceProjectsPair.getDerived().getProperty(JobPropertyImpl.class, + /*Forcing inheritance as temporary hack for inheritance plugin 1.53 + because that version of the plugin uses inheritance only for certain predefined cases: + -specific methods on the call stack + -url paths. + This has been changed as pull request https://github.com/i-m-c/jenkins-inheritance-plugin/pull/40 + */ + IMode.INHERIT_FORCED); + assertNotNull("derived jobProperty is null", jobProperty2); + final PromotionProcess fooDerived2 = jobProperty2.getItem("foo"); + + builds=fooDerived2.getBuildsAsMap(); + assertTrue(builds.size()==2); + List actions=b1.getActions(ManualApproval.class); + assertTrue(actions.size()==1); + + PromotedBuildAction buildActions=b1.getAction(PromotedBuildAction.class); + int buildIndex=1; + String valueSufix="1"; + List promotions=new ArrayList(); + promotions.addAll(builds.values()); + + Collections.reverse(promotions); + for (Promotion build:promotions){ + List values=build.getParameterDefinitionsWithValue(); + assertTrue(values.size()==condition.getParameterDefinitions().size()); + for (ParameterDefinition v:values){ + assertTrue(v instanceof StringParameterDefinition); + String pvalue=((StringParameterDefinition)v).getDefaultValue(); + assertTrue(pvalue.endsWith(valueSufix)); + } + buildIndex++; + valueSufix+=buildIndex; + } + + } +} diff --git a/src/test/java/hudson/plugins/promoted_builds/conditions/inheritance/SelfPromotionInheritanceTest.java b/src/test/java/hudson/plugins/promoted_builds/conditions/inheritance/SelfPromotionInheritanceTest.java new file mode 100644 index 00000000..912ceab1 --- /dev/null +++ b/src/test/java/hudson/plugins/promoted_builds/conditions/inheritance/SelfPromotionInheritanceTest.java @@ -0,0 +1,215 @@ +package hudson.plugins.promoted_builds.conditions.inheritance; + +import hudson.model.Cause; +import hudson.model.ParametersAction; +import hudson.model.ParametersDefinitionProperty; +import hudson.model.Result; +import hudson.model.StringParameterDefinition; +import hudson.model.StringParameterValue; +import hudson.plugins.project_inheritance.projects.InheritanceBuild; +import hudson.plugins.project_inheritance.projects.InheritanceProject.IMode; +import hudson.plugins.promoted_builds.JobPropertyImpl; +import hudson.plugins.promoted_builds.PromotedBuildAction; +import hudson.plugins.promoted_builds.Promotion; +import hudson.plugins.promoted_builds.PromotionProcess; +import hudson.plugins.promoted_builds.conditions.FixedResultBuilder; +import hudson.plugins.promoted_builds.conditions.SelfPromotionCondition; +import hudson.plugins.promoted_builds.inheritance.helpers.InheritanceProjectRule; +import hudson.plugins.promoted_builds.inheritance.helpers.InheritanceProjectsPair; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.Bug; + + +/** + * @author Jacek Tomaka + */ +public class SelfPromotionInheritanceTest { + @Rule + public InheritanceProjectRule j = new InheritanceProjectRule(); + @Test + public void testBasic() throws Exception { + InheritanceProjectsPair inheritanceProjectPair = j.createInheritanceProjectDerivedWithBase(); + + // promote if the downstream passes + JobPropertyImpl promotion = new JobPropertyImpl(inheritanceProjectPair.getBase()); + inheritanceProjectPair.getBase().addProperty(promotion); + + PromotionProcess promo1 = promotion.addProcess("promo1"); + promo1.conditions.add(new SelfPromotionCondition(false)); + + PromotionProcess promo2 = promotion.addProcess("promo2"); + promo2.conditions.add(new SelfPromotionCondition(false)); + + + InheritanceBuild b = j.assertBuildStatusSuccess(inheritanceProjectPair.getDerived().scheduleBuild2(0)); + + // internally, the promotion is still an asynchronous process. It just happens + // right away after the build is complete. + j.waitUntilNoActivity(); + + // rebind + promotion = inheritanceProjectPair.getDerived().getProperty(JobPropertyImpl.class, + /*Forcing inheritance as temporary hack for inheritance plugin 1.53 + because that version of the plugin uses inheritance only for certain predefined cases: + -specific methods on the call stack + -url paths. + This has been changed as pull request https://github.com/i-m-c/jenkins-inheritance-plugin/pull/40 + */ + IMode.INHERIT_FORCED); + promo1 = promotion.getItem("promo1"); + promo2 = promotion.getItem("promo2"); + + + // verify that both promotions happened + Promotion pb = promo1.getBuilds().get(0); + assertSame(pb.getTarget(),b); + + pb = promo2.getBuilds().get(0); + assertSame(pb.getTarget(),b); + + PromotedBuildAction badge = (PromotedBuildAction) b.getBadgeActions().get(0); + assertTrue(badge.contains(promo1)); + assertTrue(badge.contains(promo2)); + } + @Test + public void testUnstable() throws Exception { + InheritanceProjectsPair inheritanceProjectPair = j.createInheritanceProjectDerivedWithBase(); + + // promote if the downstream passes + JobPropertyImpl promotion = new JobPropertyImpl(inheritanceProjectPair.getBase()); + inheritanceProjectPair.getBase().addProperty(promotion); + + PromotionProcess promo1 = promotion.addProcess("promo1"); + promo1.conditions.add(new SelfPromotionCondition(false)); + + PromotionProcess promo2 = promotion.addProcess("promo2"); + promo2.conditions.add(new SelfPromotionCondition(true)); + + + + inheritanceProjectPair.getDerived().getBuildersList().add(unstableBuilder()); + InheritanceBuild b = j.assertBuildStatus(Result.UNSTABLE, inheritanceProjectPair.getDerived().scheduleBuild2(0).get()); + j.waitUntilNoActivity(); + // rebind + promotion = inheritanceProjectPair.getDerived().getProperty(JobPropertyImpl.class, + /*Forcing inheritance as temporary hack for inheritance plugin 1.53 + because that version of the plugin uses inheritance only for certain predefined cases: + -specific methods on the call stack + -url paths. + This has been changed as pull request https://github.com/i-m-c/jenkins-inheritance-plugin/pull/40 + */ + IMode.INHERIT_FORCED); + promo1 = promotion.getItem("promo1"); + promo2 = promotion.getItem("promo2"); + // internally, the promotion is still an asynchronous process. It just happens + // right away after the build is complete. + + + // verify that only one promotions happened + assertTrue(promo1.getBuilds().isEmpty()); + + Promotion pb = promo2.getBuilds().get(0); + assertSame(pb.getTarget(),b); + + PromotedBuildAction badge = (PromotedBuildAction) b.getBadgeActions().get(0); + assertFalse(badge.contains(promo1)); + assertTrue(badge.contains(promo2)); + } + + @Test + public void testFailure() throws Exception { + InheritanceProjectsPair inheritanceProjectPair = j.createInheritanceProjectDerivedWithBase(); + + // promote if the downstream passes + JobPropertyImpl promotion = new JobPropertyImpl(inheritanceProjectPair.getBase()); + inheritanceProjectPair.getBase().addProperty(promotion); + + PromotionProcess promo1 = promotion.addProcess("promo1"); + promo1.conditions.add(new SelfPromotionCondition(false)); + + PromotionProcess promo2 = promotion.addProcess("promo2"); + promo2.conditions.add(new SelfPromotionCondition(true)); + + inheritanceProjectPair.getDerived().getBuildersList().add(failureBuilder()); + InheritanceBuild b = j.assertBuildStatus(Result.FAILURE, inheritanceProjectPair.getDerived().scheduleBuild2(0).get()); + + // internally, the promotion is still an asynchronous process. It just happens + // right away after the build is complete. + j.waitUntilNoActivity(); + + // rebind + promotion = inheritanceProjectPair.getDerived().getProperty(JobPropertyImpl.class, + /*Forcing inheritance as temporary hack for inheritance plugin 1.53 + because that version of the plugin uses inheritance only for certain predefined cases: + -specific methods on the call stack + -url paths. + This has been changed as pull request https://github.com/i-m-c/jenkins-inheritance-plugin/pull/40 + */ + IMode.INHERIT_FORCED); + promo1 = promotion.getItem("promo1"); + promo2 = promotion.getItem("promo2"); + + + // verify that neither promotions happened + assertTrue("promo1 did not occur", promo1.getBuilds().isEmpty()); + assertTrue("promo2 did not occur", promo2.getBuilds().isEmpty()); + + PromotedBuildAction badge = (PromotedBuildAction) b.getBadgeActions().get(0); + assertFalse(badge.contains(promo1)); + assertFalse(badge.contains(promo2)); + } + + @Test + @Bug(22679) + public void testPromotionEnvironmentShouldIncludeTargetParameters() throws Exception { + String paramName = "param"; + + InheritanceProjectsPair inheritanceProjectPair = j.createInheritanceProjectDerivedWithBase(); + + // promote if the downstream passes + JobPropertyImpl promotion = new JobPropertyImpl(inheritanceProjectPair.getBase()); + inheritanceProjectPair.getBase().addProperty(promotion); + + inheritanceProjectPair.getBase().addProperty(new ParametersDefinitionProperty(new StringParameterDefinition(paramName, ""))); + PromotionProcess promo1 = promotion.addProcess("promo1"); + promo1.conditions.add(new SelfPromotionCondition(false)); + + String paramValue = "someString"; + j.assertBuildStatusSuccess(inheritanceProjectPair.getDerived().scheduleBuild2(0, new Cause.UserCause(), + new ParametersAction(new StringParameterValue(paramName, paramValue)))); + // internally, the promotion is still an asynchronous process. It just happens + // right away after the build is complete. + j.waitUntilNoActivity(); + + // rebind + promotion = inheritanceProjectPair.getDerived().getProperty(JobPropertyImpl.class, + /*Forcing inheritance as temporary hack for inheritance plugin 1.53 + because that version of the plugin uses inheritance only for certain predefined cases: + -specific methods on the call stack + -url paths. + This has been changed as pull request https://github.com/i-m-c/jenkins-inheritance-plugin/pull/40 + */ + IMode.INHERIT_FORCED); + promo1 = promotion.getItem("promo1"); + + // verify that the promotion's environment contains the parameter from the target build. + Promotion pb = promo1.getBuildByNumber(1); + assertEquals(paramValue, pb.getEnvironment(null).get(paramName, null)); + } + + private FixedResultBuilder failureBuilder() { + return new FixedResultBuilder(Result.FAILURE); + } + + private FixedResultBuilder unstableBuilder() { + return new FixedResultBuilder(Result.UNSTABLE); + } + +} diff --git a/src/test/java/hudson/plugins/promoted_builds/inheritance/helpers/InheritanceProjectRule.java b/src/test/java/hudson/plugins/promoted_builds/inheritance/helpers/InheritanceProjectRule.java new file mode 100644 index 00000000..af3fd938 --- /dev/null +++ b/src/test/java/hudson/plugins/promoted_builds/inheritance/helpers/InheritanceProjectRule.java @@ -0,0 +1,28 @@ +package hudson.plugins.promoted_builds.inheritance.helpers; + +import java.io.IOException; + +import org.jvnet.hudson.test.JenkinsRule; + +import hudson.plugins.project_inheritance.projects.InheritanceProject; +import hudson.plugins.project_inheritance.projects.references.SimpleProjectReference; + +public class InheritanceProjectRule extends JenkinsRule { + InheritanceProject createInheritanceProject() throws IOException{ + return createInheritanceProject(createUniqueProjectName()); + } + InheritanceProject createInheritanceProject(String name) throws IOException{ + return jenkins.createProject(InheritanceProject.class, name); + } + /** + * Returns BASE,DERIVED projects + * @throws IOException + */ + public InheritanceProjectsPair createInheritanceProjectDerivedWithBase() throws IOException{ + String baseProjectName = createUniqueProjectName(); + InheritanceProject base = createInheritanceProject(baseProjectName); + InheritanceProject derived = createInheritanceProject(); + derived.addParentReference(new SimpleProjectReference(baseProjectName)); + return new InheritanceProjectsPair(base, derived); + } +} diff --git a/src/test/java/hudson/plugins/promoted_builds/inheritance/helpers/InheritanceProjectsPair.java b/src/test/java/hudson/plugins/promoted_builds/inheritance/helpers/InheritanceProjectsPair.java new file mode 100644 index 00000000..3c839064 --- /dev/null +++ b/src/test/java/hudson/plugins/promoted_builds/inheritance/helpers/InheritanceProjectsPair.java @@ -0,0 +1,22 @@ +package hudson.plugins.promoted_builds.inheritance.helpers; + +import hudson.plugins.project_inheritance.projects.InheritanceProject; +/** + * @author Jacek Tomaka + */ +public class InheritanceProjectsPair { + + private InheritanceProject base; + private InheritanceProject derived; + public InheritanceProject getBase() { + return base; + } + public InheritanceProject getDerived() { + return derived; + } + + public InheritanceProjectsPair(InheritanceProject base, InheritanceProject derived){ + this.base = base; + this.derived = derived; + } +}