Skip to content

Commit

Permalink
[JENKINS-28881] - Allow blocking ItemGroup inheritance
Browse files Browse the repository at this point in the history
  • Loading branch information
oleg-nenashev committed Jan 8, 2016
1 parent 8d1fd0e commit 3589ce8
Show file tree
Hide file tree
Showing 9 changed files with 217 additions and 28 deletions.
Expand Up @@ -32,6 +32,7 @@
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import org.jenkinsci.plugins.ownership.config.DisplayOptions;
import org.jenkinsci.plugins.ownership.config.InheritanceOptions;
import org.jenkinsci.plugins.ownership.model.runs.OwnershipRunListener;
import org.jenkinsci.plugins.ownership.util.environment.EnvSetupOptions;
import org.kohsuke.stapler.DataBoundConstructor;
Expand All @@ -47,6 +48,7 @@ public class OwnershipPluginConfiguration
private final ItemOwnershipPolicy itemOwnershipPolicy;
private final @CheckForNull MailOptions mailOptions;
private final @CheckForNull DisplayOptions displayOptions;
private final @CheckForNull InheritanceOptions inheritanceOptions;

/**
* Enforces the injection of ownership variables in {@link OwnershipRunListener}.
Expand All @@ -55,14 +57,22 @@ public class OwnershipPluginConfiguration
*/
private final @CheckForNull EnvSetupOptions globalEnvSetupOptions;

@DataBoundConstructor
@Deprecated
public OwnershipPluginConfiguration(@Nonnull ItemOwnershipPolicy itemOwnershipPolicy,
@Nonnull MailOptions mailOptions, EnvSetupOptions globalEnvSetupOptions,
@Nonnull DisplayOptions displayOptions) {
this(itemOwnershipPolicy, mailOptions, globalEnvSetupOptions, displayOptions, InheritanceOptions.DEFAULT);
}

@DataBoundConstructor
public OwnershipPluginConfiguration(@Nonnull ItemOwnershipPolicy itemOwnershipPolicy,
@Nonnull MailOptions mailOptions, EnvSetupOptions globalEnvSetupOptions,
@Nonnull DisplayOptions displayOptions, @Nonnull InheritanceOptions inheritanceOptions) {
this.itemOwnershipPolicy = itemOwnershipPolicy;
this.mailOptions = mailOptions;
this.globalEnvSetupOptions = globalEnvSetupOptions;
this.displayOptions = displayOptions;
this.inheritanceOptions = inheritanceOptions;
}

@Deprecated
Expand Down Expand Up @@ -93,6 +103,10 @@ public OwnershipPluginConfiguration(@Nonnull ItemOwnershipPolicy itemOwnershipPo
public @Nonnull DisplayOptions getDisplayOptions() {
return displayOptions != null ? displayOptions : DisplayOptions.DEFAULT;
}

public InheritanceOptions getInheritanceOptions() {
return inheritanceOptions != null ? inheritanceOptions : InheritanceOptions.DEFAULT;
}

/**
* @return Global environment inject options. Null - global setup is disabled
Expand Down
Expand Up @@ -26,6 +26,7 @@
import com.synopsys.arc.jenkins.plugins.ownership.IOwnershipHelper;
import com.synopsys.arc.jenkins.plugins.ownership.OwnershipDescription;
import com.synopsys.arc.jenkins.plugins.ownership.OwnershipPlugin;
import com.synopsys.arc.jenkins.plugins.ownership.OwnershipPluginConfiguration;
import com.synopsys.arc.jenkins.plugins.ownership.security.itemspecific.ItemSpecificSecurity;
import com.synopsys.arc.jenkins.plugins.ownership.util.AbstractOwnershipHelper;
import com.synopsys.arc.jenkins.plugins.ownership.util.UserCollectionFilter;
Expand Down Expand Up @@ -112,19 +113,21 @@ public OwnershipInfo getOwnershipInfo(Job<?, ?> job) {
}

// We go to upper items in order to get the ownership description
ItemGroup parent = job.getParent();
AbstractOwnershipHelper<ItemGroup> located = OwnershipHelperLocator.locate(parent);
while (located != null) {
OwnershipInfo fromParent = located.getOwnershipInfo(parent);
if (fromParent.getDescription().isOwnershipEnabled()) {
return fromParent;
}
if (parent instanceof Item) {
Item parentItem = (Item)parent;
parent = parentItem.getParent();
located = OwnershipHelperLocator.locate(parent);
} else {
located = null;
if (!OwnershipPluginConfiguration.get().getInheritanceOptions().isBlockInheritanceFromItemGroups()) {
ItemGroup parent = job.getParent();
AbstractOwnershipHelper<ItemGroup> located = OwnershipHelperLocator.locate(parent);
while (located != null) {
OwnershipInfo fromParent = located.getOwnershipInfo(parent);
if (fromParent.getDescription().isOwnershipEnabled()) {
return fromParent;
}
if (parent instanceof Item) {
Item parentItem = (Item)parent;
parent = parentItem.getParent();
located = OwnershipHelperLocator.locate(parent);
} else {
located = null;
}
}
}

Expand Down
@@ -0,0 +1,81 @@
/*
* The MIT License
*
* Copyright 2016 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 org.jenkinsci.plugins.ownership.config;

import com.synopsys.arc.jenkins.plugins.ownership.OwnershipPlugin;
import com.synopsys.arc.jenkins.plugins.ownership.OwnershipPluginConfiguration;
import com.synopsys.arc.jenkins.plugins.ownership.jobs.JobOwnerHelper;
import hudson.Extension;
import hudson.model.Describable;
import hudson.model.Descriptor;
import hudson.model.ItemGroup;
import org.jenkinsci.plugins.ownership.model.folders.FolderOwnershipHelper;
import org.kohsuke.stapler.DataBoundConstructor;

/**
* Stores inheritance options for {@link OwnershipPlugin}.
* This section is attached as an advanced section to {@link OwnershipPluginConfiguration}.
* These options has been created
* @author Oleg Nenashev
* @since TODO
*/
public class InheritanceOptions implements Describable<InheritanceOptions> {

public static final InheritanceOptions DEFAULT = new InheritanceOptions(false);

private final boolean blockInheritanceFromItemGroups;

@DataBoundConstructor
public InheritanceOptions(boolean blockInheritanceFromItemGroups) {
this.blockInheritanceFromItemGroups = blockInheritanceFromItemGroups;
}

/**
* Blocks ownership inheritance from {@link ItemGroup}s.
* This inheritance is used in {@link JobOwnerHelper} and {@link FolderOwnershipHelper}
* in order to retrieve the info from parent folders.
* Such inheritance may impact the performance of Jenkins instance, hence it is possible to disable it.
* @return {@code true} if ownership inheritance should be blocked.
*/
public boolean isBlockInheritanceFromItemGroups() {
return blockInheritanceFromItemGroups;
}

@Extension
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();

@Override
public DescriptorImpl getDescriptor() {
return DESCRIPTOR;
}

public static class DescriptorImpl extends Descriptor<InheritanceOptions> {

@Override
public String getDisplayName() {
return "N/A";
}
}
}
Expand Up @@ -29,6 +29,7 @@
import com.synopsys.arc.jenkins.plugins.ownership.IOwnershipHelper;
import com.synopsys.arc.jenkins.plugins.ownership.OwnershipDescription;
import com.synopsys.arc.jenkins.plugins.ownership.OwnershipPlugin;
import com.synopsys.arc.jenkins.plugins.ownership.OwnershipPluginConfiguration;
import com.synopsys.arc.jenkins.plugins.ownership.jobs.JobOwnerHelper;
import com.synopsys.arc.jenkins.plugins.ownership.jobs.JobOwnerJobProperty;
import com.synopsys.arc.jenkins.plugins.ownership.util.AbstractOwnershipHelper;
Expand Down Expand Up @@ -110,19 +111,21 @@ public OwnershipInfo getOwnershipInfo(AbstractFolder<?> item) {
}

// We go to upper items in order to get the ownership description
ItemGroup parent = item.getParent();
AbstractOwnershipHelper<ItemGroup> located = OwnershipHelperLocator.locate(parent);
while (located != null) {
OwnershipInfo fromParent = located.getOwnershipInfo(parent);
if (fromParent.getDescription().isOwnershipEnabled()) {
return fromParent;
}
if (parent instanceof Item) {
Item parentItem = (Item)parent;
parent = parentItem.getParent();
located = OwnershipHelperLocator.locate(parent);
} else {
located = null;
if (!OwnershipPluginConfiguration.get().getInheritanceOptions().isBlockInheritanceFromItemGroups()) {
ItemGroup parent = item.getParent();
AbstractOwnershipHelper<ItemGroup> located = OwnershipHelperLocator.locate(parent);
while (located != null) {
OwnershipInfo fromParent = located.getOwnershipInfo(parent);
if (fromParent.getDescription().isOwnershipEnabled()) {
return fromParent;
}
if (parent instanceof Item) {
Item parentItem = (Item)parent;
parent = parentItem.getParent();
located = OwnershipHelperLocator.locate(parent);
} else {
located = null;
}
}
}

Expand Down
Expand Up @@ -38,4 +38,7 @@
<f:entry>
<f:property field="displayOptions"/>
</f:entry>
<f:entry>
<f:property field="inheritanceOptions"/>
</f:entry>
</j:jelly>
@@ -0,0 +1,35 @@
<!--
* The MIT License
*
* Copyright 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.
-->
<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:advanced title="${%Ownership Inheritance Options}">
<f:entry title="" description="">
<table width="100%">
<f:entry field="blockInheritanceFromItemGroups">
<f:checkbox title="${%Block inheritance from item groups}"/>
</f:entry>
</table>
</f:entry>
</f:advanced>
</j:jelly>
@@ -0,0 +1,13 @@
<div>
<p>
Blocks ownership inheritance from item groups like
<a href="https://wiki.jenkins-ci.org/display/JENKINS/CloudBees+Folders+Plugin">Folders</a> or
<a href="https://wiki.jenkins-ci.org/display/JENKINS/Multi-Branch+Project+Plugin">Multi-branch projects</a>.
</p>
<p>
By default the plugin inherits ownership info from upper items.
Such inheritance may impact the performance of the Jenkins instance (especially
<a href="https://wiki.jenkins-ci.org/display/JENKINS/Ownership-Based+security">Ownership-based security</a>),
hence it is possible to disable it.
</p>
</div>
Expand Up @@ -35,6 +35,7 @@
import hudson.security.SecurityRealm;
import java.util.Arrays;
import static org.hamcrest.Matchers.*;
import org.jenkinsci.plugins.ownership.config.InheritanceOptions;
import org.jenkinsci.plugins.ownership.model.OwnershipInfo;
import org.jenkinsci.plugins.ownership.test.util.OwnershipPluginConfigurer;
import org.jenkinsci.remoting.RoleChecker;
Expand Down Expand Up @@ -180,4 +181,33 @@ public void ownershipShouldBeInheritedFromTopLevelFolderByDefault() throws Excep
assertThat("OwnershipInfo should return the right reference",
(Object)ownershipInfo.getSource().getItem(), equalTo((Object)j.jenkins.getItemByFullName("folder1")));
}

@Test
public void ownershipShouldNotBeInheritedFromTopLevelFolderIfDisabled() throws Exception {
Folder folder1 = j.jenkins.createProject(Folder.class, "folder1");
Folder folder2 = folder1.createProject(Folder.class, "folder2");
FreeStyleProject project = folder2.createProject(FreeStyleProject.class, "projectInFolder");

// Set ownership via API
OwnershipDescription original = new OwnershipDescription(true, "ownerId", Arrays.asList("coowner1, coowner2"));
FolderOwnershipHelper.setOwnership(folder1, original);
assertThat("Folder ownership helper should return the inherited value",
JobOwnerHelper.Instance.getOwnershipDescription(project),
equalTo(original));

// Disable the inheritance
OwnershipPluginConfigurer.forJenkinsRule(j)
.withInheritanceOptions(new InheritanceOptions(true))
.configure();

// Ensure that Ownership is disabled for both nested job and folder
OwnershipInfo projectOwnershipInfo = JobOwnerHelper.Instance.getOwnershipInfo(
j.jenkins.getItemByFullName("folder1/folder2/projectInFolder", FreeStyleProject.class));
OwnershipInfo folderOwnershipInfo = FolderOwnershipHelper.getInstance().getOwnershipInfo(
j.jenkins.getItemByFullName("folder1/folder2", Folder.class));
assertThat("Folder should not inherit the ownership info when inheritance is disabled",
folderOwnershipInfo.getDescription(), equalTo(OwnershipDescription.DISABLED_DESCR));
assertThat("Project should not inherit the ownerhip info when inheritance is disabled",
projectOwnershipInfo.getDescription(), equalTo(OwnershipDescription.DISABLED_DESCR));
}
}
Expand Up @@ -35,6 +35,7 @@
import javax.annotation.Nonnull;
import jenkins.model.Jenkins;
import org.jenkinsci.plugins.ownership.config.DisplayOptions;
import org.jenkinsci.plugins.ownership.config.InheritanceOptions;
import org.jenkinsci.plugins.ownership.util.environment.EnvSetupOptions;
import org.jenkinsci.plugins.ownership.util.mail.MailOptions;
import org.jvnet.hudson.test.JenkinsRule;
Expand All @@ -54,6 +55,7 @@ public class OwnershipPluginConfigurer {
private MailOptions mailOptions;
private DisplayOptions displayOptions;
private EnvSetupOptions globalEnvSetupOptions;
private InheritanceOptions inheritanceOptions;

private OwnershipPluginConfigurer(Jenkins jenkins) {
this.jenkins = jenkins;
Expand Down Expand Up @@ -104,9 +106,14 @@ public OwnershipPluginConfigurer withGlobalEnvSetupOptions(EnvSetupOptions globa
return this;
}

public OwnershipPluginConfigurer withInheritanceOptions(InheritanceOptions inheritanceOptions) {
this.inheritanceOptions = inheritanceOptions;
return this;
}

public void configure() throws IOException {
OwnershipPluginConfiguration conf = new OwnershipPluginConfiguration
(itemOwnershipPolicy, mailOptions, globalEnvSetupOptions, displayOptions);
(itemOwnershipPolicy, mailOptions, globalEnvSetupOptions, displayOptions, inheritanceOptions);
jenkins.getPlugin(OwnershipPlugin.class).configure
(requiresConfigurePermissions, mailResolverClassName, defaultJobsSecurity, conf);
}
Expand Down

0 comments on commit 3589ce8

Please sign in to comment.