Skip to content

Commit

Permalink
Merge pull request #12
Browse files Browse the repository at this point in the history
  • Loading branch information
samrocketman committed Sep 12, 2019
2 parents 1f2f0d7 + 33d5028 commit 182f958
Show file tree
Hide file tree
Showing 6 changed files with 340 additions and 0 deletions.
@@ -0,0 +1,181 @@
/*
* The MIT License
*
* Copyright (c) 2016 Saponenko Denis
* Copyright (c) 2018 Sam Gleske - https://github.com/samrocketman
*
* 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 org.jenkinsci.plugins.pipeline.multibranch.defaults;

import hudson.Extension;
import hudson.model.Action;
import hudson.model.Item;
import hudson.model.ItemGroup;
import hudson.model.TaskListener;
import jenkins.branch.MultiBranchProject;
import jenkins.branch.MultiBranchProjectFactory;
import jenkins.branch.MultiBranchProjectFactoryDescriptor;
import jenkins.branch.OrganizationFolder;
import jenkins.model.TransientActionFactory;
import jenkins.scm.api.SCMSource;
import jenkins.scm.api.SCMSourceCriteria;
import org.apache.commons.lang.StringUtils;
import org.jenkinsci.plugins.workflow.cps.Snippetizer;
import org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;

import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;

/**
* Recognizes and builds by default {@code Jenkinsfile}.
*/
public class PipelineMultiBranchDefaultsProjectFactory extends MultiBranchProjectFactory.BySCMSourceCriteria {
public static final String SCRIPT = "Jenkinsfile";

private String scriptId = SCRIPT;
private boolean useSandbox = false;

@DataBoundConstructor
public PipelineMultiBranchDefaultsProjectFactory() { }

/**
* Set the script ID which will be used to reference the config file
* management for the contents of a Jenkinsfile.
*
* @param scriptId The ID of the groovy script to read as a Jenkinsfile.
*/
@DataBoundSetter
public void setScriptId(String scriptId) {
if(StringUtils.isEmpty(scriptId)) {
this.scriptId = SCRIPT;
} else {
this.scriptId = scriptId;
}
}

/**
* Get the script ID which will be used to read the Jenkinsfile from config
* file management.
*
* @return The Jenkinsfile script ID.
*/
public String getScriptId() {
return scriptId;
}

/**
* Set whether or not a Jenkinsfile should run within a Groovy sandbox.
*
* @param useSandbox Set true to enable Groovy sandbox or false to run in
* Jenkins master runtime.
*/
@DataBoundSetter
public void setUseSandbox(boolean useSandbox) {
this.useSandbox = useSandbox;
}

/**
* Get the current setting for whether or not to use a groovy sandbox.
*
* @return true if using a groovy sandbox is desired.
*/
public boolean getUseSandbox() {
return this.useSandbox;
}

@Override
protected WorkflowMultiBranchProject doCreateProject(ItemGroup<?> parent, String name, Map<String,Object> attributes){
WorkflowMultiBranchProject project = new WorkflowMultiBranchProject(parent, name);
configureProjectFactoryFor(project);
return project;
}

@Override
public void updateExistingProject(MultiBranchProject<?, ?> project, Map<String, Object> attributes, TaskListener listener) throws IOException, InterruptedException {
if (project instanceof WorkflowMultiBranchProject) {
configureProjectFactoryFor((WorkflowMultiBranchProject) project);
}
}

@Override
protected SCMSourceCriteria getSCMSourceCriteria(SCMSource source) {
return new SCMSourceCriteria() {
@Override
public boolean isHead(Probe probe, TaskListener listener) throws IOException {
return true;
}

@Override
public int hashCode() {
return getClass().hashCode();
}

@Override
public boolean equals(Object obj) {
return getClass().isInstance(obj);
}
};
}

@Extension
public static class PerFolderAdder extends TransientActionFactory<OrganizationFolder> {

@Override
public Class<OrganizationFolder> type() {
return OrganizationFolder.class;
}

@Override
public Collection<? extends Action> createFor(OrganizationFolder target) {
if (target.getProjectFactories().get(PipelineMultiBranchDefaultsProjectFactory.class) != null && target.hasPermission(Item.EXTENDED_READ)) {
return Collections.singleton(new Snippetizer.LocalAction());
} else {
return Collections.emptySet();
}
}
}

@Extension
public static class DescriptorImpl extends MultiBranchProjectFactoryDescriptor {
@Override
public MultiBranchProjectFactory newInstance() {
return null;
}

@Nonnull
@Override
public String getDisplayName() {
return "by default " + SCRIPT;
}
}

private void configureProjectFactoryFor(WorkflowMultiBranchProject project) {
PipelineBranchDefaultsProjectFactory projectFactory = new PipelineBranchDefaultsProjectFactory();
projectFactory.setScriptId(scriptId);
projectFactory.setUseSandbox(useSandbox);
project.setProjectFactory(projectFactory);
}
}
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
The MIT License
Copyright (c) 2016 Saponenko Denis
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.
-->

<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
<f:entry title="${%Script ID}" field="scriptId">
<f:textbox value="${instance.scriptId}" default="Jenkinsfile" />
</f:entry>
<f:entry title="${%Run default Jenkinsfile within Groovy sandbox}" field="useSandbox">
<f:checkbox name="useSandbox" checked="${instance.useSandbox}" default="false" />
</f:entry>
</j:jelly>
@@ -0,0 +1,39 @@
<!--
~ The MIT License
~
~ Copyright (c) 2016 Saponenko Denis
~
~ 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.
-->
<?jelly escape-by-default='true'?>
<st:compress xmlns:st="jelly:stapler">
Pipeline Branch projects support building branches within a repository with a file named
<code>Jenkinsfile</code>
in the Jenkins global files or scm module root directory.
This file should contain a valid
<a target="_blank"
href="https://github.com/jenkinsci/workflow-plugin/blob/master/TUTORIAL.md#understanding-flow-scripts">Jenkins
Pipeline script</a>. See also:
<a target="_blank"
href="https://github.com/jenkinsci/workflow-multibranch-plugin">
Workflow Multibranch Plugin</a>.
<a target="_blank"
href="https://github.com/jenkinsci/workflow-plugin/blob/master/TUTORIAL.md#creating-multibranch-projects">
Creating Multibranch Projects</a>.
</st:compress>
@@ -0,0 +1,4 @@
<div>
The ID of the default <code>Jenkinsfile</code> to use from the global
Config File Management.
</div>
@@ -0,0 +1,6 @@
<div>
If enabled, the configured default <code>Jenkinsfile</code> will be run
within a Groovy sandbox. This option is <b>strongly recommended</b> if the
Jenkinsfile is using <a href="https://jenkins.io/doc/pipeline/steps/workflow-cps/"><code>load</code>
to evaluate a groovy source file</a> from an SCM repository.
</div>
@@ -0,0 +1,76 @@
/*
* The MIT License
*
* Copyright (c) 2016 Saponenko Denis
*
* 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 org.jenkinsci.plugins.pipeline.multibranch.defaults;

import hudson.model.Result;
import hudson.util.DescribableList;
import jenkins.branch.MultiBranchProjectFactory;
import jenkins.branch.OrganizationFolder;
import jenkins.scm.api.SCMNavigator;
import jenkins.scm.api.SCMNavigatorDescriptor;
import jenkins.scm.impl.mock.*;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.JenkinsRule;

import java.util.List;

import static net.sf.ezmorph.test.ArrayAssertions.assertEquals;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.assertThat;

public class PipelineMultiBranchDefaultsProjectFactoryTest {
@Rule
public JenkinsRule r = new JenkinsRule();

@Test
public void configureAndIndexChildren() throws Exception {
try (MockSCMController c = MockSCMController.create()) {
OrganizationFolder folder = r.jenkins.createProject(OrganizationFolder.class, "p");
List<MultiBranchProjectFactory> projectFactories = folder.getProjectFactories();
projectFactories.clear();
projectFactories.add(new PipelineMultiBranchDefaultsProjectFactory());

c.createRepository("sample");
MockSCMNavigator navigator = new MockSCMNavigator(c, new MockSCMDiscoverBranches(), new MockSCMDiscoverTags(), new MockSCMDiscoverChangeRequests());

DescribableList<SCMNavigator, SCMNavigatorDescriptor> navigators = folder.getNavigators();
navigators.add(navigator);

assertThat("Folder has not been scanned", folder.getItem("sample"), nullValue());

folder.scheduleBuild(0);
r.waitUntilNoActivity();
assertEquals(1, folder.getItems().size());

assertThat("Folder has been scanned", folder.getItem("sample"), notNullValue());
assertThat("We have run an index on the child item",
folder.getItem("sample").getComputation().getResult(), is(Result.SUCCESS)
);
}
}
}

0 comments on commit 182f958

Please sign in to comment.