Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[JENKINS-41759] First make the function calls in environment extensible
Work in Progress
  • Loading branch information
rsandell authored and abayer committed Feb 10, 2017
1 parent aaa0593 commit 331e432
Show file tree
Hide file tree
Showing 10 changed files with 328 additions and 30 deletions.
Expand Up @@ -26,8 +26,10 @@ package org.jenkinsci.plugins.pipeline.modeldefinition.model
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings
import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString

import org.jenkinsci.plugins.pipeline.modeldefinition.environment.DeclarativeEnvironmentContributor
import org.jenkinsci.plugins.pipeline.modeldefinition.environment.impl.Credentials
import org.jenkinsci.plugins.pipeline.modeldefinition.steps.CredentialWrapper
import org.jenkinsci.plugins.workflow.cps.CpsScript
import org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper

/**
Expand Down Expand Up @@ -101,16 +103,26 @@ public class Root implements NestedModel, Serializable {
*
* @return a list of "key=value" strings.
*/
List<String> getEnvVars() {
return environment.findAll{k, v -> !(v instanceof CredentialWrapper)}.collect { k, v ->
List<String> getEnvVars(CpsScript script) {
List<String> e = environment.findAll{k, v -> !(v instanceof DeclarativeEnvironmentContributor)}.collect { k, v ->
"${k}=${v}"
}

environment.each {k, v ->
if (v instanceof DeclarativeEnvironmentContributor && !(v instanceof DeclarativeEnvironmentContributor.MutedGenerator)) {
List<String> ee = v.generate(script, k)
if (ee != null) {
e.addAll(ee)
}
}
}
return e
}

Map<String, CredentialWrapper> getEnvCredentials() {
Map<String, CredentialWrapper> m = [:]
Map<String, Credentials> getEnvCredentials() {
Map<String, Credentials> m = [:]
environment.each {k, v ->
if (v instanceof CredentialWrapper) {
if (v instanceof Credentials) {
m["${k}"] = v;
}
}
Expand Down
Expand Up @@ -26,7 +26,10 @@ package org.jenkinsci.plugins.pipeline.modeldefinition.model
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings
import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
import org.jenkinsci.plugins.pipeline.modeldefinition.environment.DeclarativeEnvironmentContributor
import org.jenkinsci.plugins.pipeline.modeldefinition.environment.impl.Credentials
import org.jenkinsci.plugins.pipeline.modeldefinition.steps.CredentialWrapper
import org.jenkinsci.plugins.workflow.cps.CpsScript

import javax.annotation.Nonnull

Expand Down Expand Up @@ -95,17 +98,26 @@ public class Stage implements NestedModel, Serializable {
*
* @return a list of "key=value" strings.
*/
List<String> getEnvVars() {
return environment.findAll{k, v -> !(v instanceof CredentialWrapper)}.collect { k, v ->
List<String> getEnvVars(CpsScript script) {
List<String> e = environment.findAll{k, v -> !(v instanceof DeclarativeEnvironmentContributor)}.collect { k, v ->
"${k}=${v}"
}
environment.each {k, v ->
if (v instanceof DeclarativeEnvironmentContributor && !(v instanceof DeclarativeEnvironmentContributor.MutedGenerator)) {
List<String> ee = v.generate(script, k)
if (ee != null) {
e.addAll(ee)
}
}
}
return e
}

@Nonnull
Map<String, CredentialWrapper> getEnvCredentials() {
Map<String, CredentialWrapper> m = [:]
Map<String, Credentials> getEnvCredentials() {
Map<String, Credentials> m = [:]
environment.each {k, v ->
if (v instanceof CredentialWrapper) {
if (v instanceof Credentials) {
m["${k}"] = v;
}
}
Expand Down
@@ -0,0 +1,50 @@
/*
* The MIT License
*
* Copyright (c) 2017, 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 org.jenkinsci.plugins.pipeline.modeldefinition.environment;

import org.jenkinsci.plugins.pipeline.modeldefinition.withscript.WithScriptDescribable;
import org.jenkinsci.plugins.workflow.cps.CpsScript;

import java.util.List;

/**
* Defines special functions within the environment directive.
*/
public abstract class DeclarativeEnvironmentContributor<C extends WithScriptDescribable<C>> extends WithScriptDescribable<C> {

public List<String> generate(CpsScript script, String key) throws Exception {
return ((DeclarativeEnvironmentContributorScript)getScript(script)).generate(key);
}

/**
* Marker interface for a generator that is not part of the standard "withEnv" flow.
* But one that needs special handling.
* @see com.cloudbees.plugins.credentials.CredentialsStoreAction.CredentialsWrapper
*/
public interface MutedGenerator {

}
}
@@ -0,0 +1,36 @@
/*
* The MIT License
*
* Copyright (c) 2017, 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 org.jenkinsci.plugins.pipeline.modeldefinition.environment;

import org.jenkinsci.plugins.pipeline.modeldefinition.withscript.WithScriptDescriptor;

/**
* Created by rsandell on 2017-02-06.
*/
public class DeclarativeEnvironmentContributorDescriptor<C extends DeclarativeEnvironmentContributor<C>> extends WithScriptDescriptor<C> {


}
@@ -0,0 +1,44 @@
/*
* The MIT License
*
* Copyright (c) 2017, 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 org.jenkinsci.plugins.pipeline.modeldefinition.environment;

import org.jenkinsci.plugins.pipeline.modeldefinition.withscript.WithScriptScript;
import org.jenkinsci.plugins.workflow.cps.CpsScript;

import java.util.List;

/**
* Script base for {@link DeclarativeEnvironmentContributor}s.
*/
public abstract class DeclarativeEnvironmentContributorScript<C extends DeclarativeEnvironmentContributor<C>> extends WithScriptScript<C> {


public DeclarativeEnvironmentContributorScript(CpsScript s, C d) {
super(s, d);
}

public abstract List<String> generate(String key);
}
@@ -0,0 +1,87 @@
/*
* The MIT License
*
* Copyright (c) 2017, 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 org.jenkinsci.plugins.pipeline.modeldefinition.environment.impl;

import hudson.Extension;
import org.jenkinsci.Symbol;
import org.jenkinsci.plugins.credentialsbinding.impl.CredentialNotFoundException;
import org.jenkinsci.plugins.pipeline.modeldefinition.environment.DeclarativeEnvironmentContributor;
import org.jenkinsci.plugins.pipeline.modeldefinition.environment.DeclarativeEnvironmentContributorDescriptor;
import org.jenkinsci.plugins.pipeline.modeldefinition.model.CredentialsBindingHandler;
import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.Whitelisted;
import org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper;
import org.kohsuke.stapler.DataBoundConstructor;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* Provides credentials function.
*/
public class Credentials extends DeclarativeEnvironmentContributor<Credentials> implements DeclarativeEnvironmentContributor.MutedGenerator {

private final String credentialsId;
private List<Map<String, Object>> withCredentialsParameters;

@DataBoundConstructor
public Credentials(String credentialsId) {
this.credentialsId = credentialsId;
}

public String getCredentialsId() {
return credentialsId;
}

public void prepare(RunWrapper currentBuild) throws CredentialNotFoundException {
CredentialsBindingHandler handler = CredentialsBindingHandler.forId(credentialsId, currentBuild.getRawBuild());
withCredentialsParameters = handler.getWithCredentialsParameters(credentialsId);
}

@Whitelisted
public List<Map<String, Object>> resolveParameters(String envVarName) {
List<Map<String, Object>> newList = new ArrayList<>(withCredentialsParameters.size());
for (Map<String, Object> params : withCredentialsParameters) {
Map<String, Object> newP = new HashMap<>();
for (Map.Entry<String, Object> p : params.entrySet()) {
Object value = p.getValue();
if (value instanceof CredentialsBindingHandler.EnvVarResolver) {
newP.put(p.getKey(), ((CredentialsBindingHandler.EnvVarResolver)value).resolve(envVarName));
} else {
newP.put(p.getKey(), p.getValue());
}
}
newList.add(newP);
}
return newList;
}

@Extension @Symbol("credentials")
public static class DescriptorImpl extends DeclarativeEnvironmentContributorDescriptor<Credentials> {

}
}
Expand Up @@ -38,7 +38,9 @@

/**
* Helper for simplified Credentials handling in {@code environment{}}
* @deprecated see {@link org.jenkinsci.plugins.pipeline.modeldefinition.environment.impl.Credentials}
*/
@Deprecated
public class CredentialWrapper implements Serializable {
private static final long serialVersionUID = 1L;

Expand Down
Expand Up @@ -28,6 +28,7 @@ import com.cloudbees.groovy.cps.impl.CpsClosure
import hudson.FilePath
import hudson.Launcher
import hudson.model.Result
import org.jenkinsci.plugins.pipeline.modeldefinition.environment.impl.Credentials
import org.jenkinsci.plugins.pipeline.modeldefinition.model.*
import org.jenkinsci.plugins.pipeline.modeldefinition.steps.CredentialWrapper
import org.jenkinsci.plugins.pipeline.modeldefinition.when.DeclarativeStageConditional
Expand Down Expand Up @@ -68,7 +69,7 @@ public class ModelInterpreter implements Serializable {
executeProperties(root)

// Entire build, including notifications, runs in the withEnv.
withEnvBlock(root.getEnvVars()) {
withEnvBlock(root.getEnvVars(script)) {
inWrappers(root.options) {
// Stage execution and post-build actions run in try/catch blocks, so we still run post-build actions
// even if the build fails.
Expand All @@ -81,7 +82,7 @@ public class ModelInterpreter implements Serializable {
try {
script.stage(thisStage.name) {
if (firstError == null) {
withEnvBlock(thisStage.getEnvVars()) {
withEnvBlock(thisStage.getEnvVars(script)) {
if (evaluateWhen(thisStage.when)) {
inDeclarativeAgent(thisStage, thisStage.agent) {
withCredentialsBlock(thisStage.getEnvCredentials()) {
Expand Down Expand Up @@ -203,7 +204,7 @@ public class ModelInterpreter implements Serializable {
* @param body The closure to execute
* @return The return of the resulting executed closure
*/
def withCredentialsBlock(@Nonnull Map<String, CredentialWrapper> credentials, Closure body) {
def withCredentialsBlock(@Nonnull Map<String, Credentials> credentials, Closure body) {
if (!credentials.isEmpty()) {
List<Map<String, Object>> parameters = createWithCredentialsParameters(credentials)
return {
Expand All @@ -225,11 +226,11 @@ public class ModelInterpreter implements Serializable {
*/
@NonCPS
private List<Map<String, Object>> createWithCredentialsParameters(
@Nonnull Map<String, CredentialWrapper> credentials) {
@Nonnull Map<String, Credentials> credentials) {
List<Map<String, Object>> parameters = []
Set<Map.Entry<String, CredentialWrapper>> set = credentials.entrySet()
for (Map.Entry<String, CredentialWrapper> entry : set) {
entry.value.addParameters(entry.key, parameters)
Set<Map.Entry<String, Credentials>> set = credentials.entrySet()
for (Map.Entry<String, Credentials> entry : set) {
entry.value.getScript(script).addParameters(entry.key, parameters)
}
parameters
}
Expand Down

0 comments on commit 331e432

Please sign in to comment.