Skip to content

Commit

Permalink
[JENKINS-31155] Extended GlobalVariableSet API to allow a Run context…
Browse files Browse the repository at this point in the history
… to be supplied.
  • Loading branch information
jglick committed Aug 18, 2016
1 parent d253c81 commit 964295f
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 38 deletions.
41 changes: 26 additions & 15 deletions src/main/java/org/jenkinsci/plugins/workflow/cps/CpsScript.java
Expand Up @@ -34,6 +34,8 @@
import hudson.model.Run;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.CheckForNull;
import org.codehaus.groovy.control.CompilationFailedException;
import org.codehaus.groovy.runtime.DefaultGroovyMethods;
Expand All @@ -55,6 +57,8 @@
@PersistIn(PROGRAM)
public abstract class CpsScript extends SerializableScript {

private static final Logger LOGGER = Logger.getLogger(CpsScript.class.getName());

private static final String STEPS_VAR = "steps";

transient CpsFlowExecution execution;
Expand Down Expand Up @@ -101,14 +105,13 @@ public CpsScript() throws IOException {
public final Object invokeMethod(String name, Object args) {
// if global variables are defined by that name, try to call it.
// the 'call' convention comes from Closure
for (GlobalVariable v : GlobalVariable.ALL) {
if (v.getName().equals(name)) {
try {
Object o = v.getValue(this);
return InvokerHelper.getMetaClass(o).invokeMethod(o,"call",args);
} catch (Exception x) {
throw new InvokerInvocationException(x);
}
GlobalVariable v = GlobalVariable.byName(name, $buildNoException());
if (v != null) {
try {
Object o = v.getValue(this);
return InvokerHelper.getMetaClass(o).invokeMethod(o, "call", args);
} catch (Exception x) {
throw new InvokerInvocationException(x);
}
}

Expand All @@ -119,13 +122,12 @@ public final Object invokeMethod(String name, Object args) {

@Override
public Object getProperty(String property) {
for (GlobalVariable v : GlobalVariable.ALL) {
if (v.getName().equals(property)) {
try {
return v.getValue(this);
} catch (Exception x) {
throw new InvokerInvocationException(x);
}
GlobalVariable v = GlobalVariable.byName(property, $buildNoException());
if (v != null) {
try {
return v.getValue(this);
} catch (Exception x) {
throw new InvokerInvocationException(x);
}
}
return super.getProperty(property);
Expand All @@ -141,6 +143,15 @@ public Object getProperty(String property) {
}
}

public @CheckForNull Run<?,?> $buildNoException() {
try {
return $build();
} catch (IOException x) {
LOGGER.log(Level.WARNING, null, x);
return null;
}
}

@Override
public Object evaluate(String script) throws CompilationFailedException {
// this might throw the magic CpsCallableInvocation to execute the script asynchronously
Expand Down
Expand Up @@ -38,10 +38,8 @@ public boolean permitsMethod(Method method, Object receiver, Object[] args) {
return true;
}
if (name.equals("getProperty") && args.length == 1 && args[0] instanceof String) {
for (GlobalVariable v : GlobalVariable.ALL) {
if (v.getName().equals(args[0])) {
return true;
}
if (GlobalVariable.byName((String) args[0], ((CpsScript) receiver).$buildNoException()) != null) {
return true;
}
}
}
Expand Down Expand Up @@ -80,7 +78,7 @@ public boolean permitsStaticMethod(Method method, Object[] args) {
*/
private static final Map<Jenkins,Whitelist> wrappedByJenkins = new WeakHashMap<Jenkins,Whitelist>();

public static synchronized Whitelist get() {
static synchronized Whitelist get() {
Jenkins j = Jenkins.getInstance();
if (j == null) {
return new ProxyWhitelist();
Expand Down
Expand Up @@ -133,10 +133,10 @@ private EnvActionImpl() {
@Override public String getName() {
return "env";
}
@Override public Object getValue(CpsScript script) throws Exception {
@Override public EnvActionImpl getValue(CpsScript script) throws Exception {
Run<?,?> run = script.$build();
if (run != null) {
return forRun(run);
return EnvActionImpl.forRun(run);
} else {
throw new IllegalStateException("no associated build");
}
Expand Down
Expand Up @@ -27,11 +27,13 @@
import groovy.lang.GroovyObject;
import hudson.ExtensionList;
import hudson.ExtensionPoint;
import hudson.model.Run;
import hudson.util.Iterators.FlattenIterator;
import jenkins.model.RunAction2;

import javax.annotation.Nonnull;
import java.util.Iterator;
import javax.annotation.CheckForNull;

/**
* Defines a provider of a global variable offered to flows.
Expand Down Expand Up @@ -63,17 +65,41 @@ public abstract class GlobalVariable implements ExtensionPoint {
public abstract @Nonnull Object getValue(@Nonnull CpsScript script) throws Exception;

/**
* Returns all the registered {@link GlobalVariable}s.
* @deprecated use {@link #forRun} instead
*/
public static final Iterable<GlobalVariable> ALL = new Iterable<GlobalVariable>() {
@Override
public Iterator<GlobalVariable> iterator() {
return new FlattenIterator<GlobalVariable,GlobalVariableSet>(ExtensionList.lookup(GlobalVariableSet.class).iterator()) {
@Override
protected Iterator<GlobalVariable> expand(GlobalVariableSet vs) {
return vs.iterator();
}
};
@Deprecated
public static final Iterable<GlobalVariable> ALL = forRun(null);

/**
* Returns all the registered {@link GlobalVariable}s for some context.
* @param run see {@link GlobalVariableSet#forRun}
* @return a possibly empty list
*/
public static @Nonnull Iterable<GlobalVariable> forRun(@CheckForNull final Run<?,?> run) {
return new Iterable<GlobalVariable>() {
@Override public Iterator<GlobalVariable> iterator() {
return new FlattenIterator<GlobalVariable,GlobalVariableSet>(ExtensionList.lookup(GlobalVariableSet.class).iterator()) {
@Override protected Iterator<GlobalVariable> expand(GlobalVariableSet vs) {
return vs.forRun(run).iterator();
}
};
}
};
}

/**
* Finds a particular variable by name.
* @param name see {@link #getName}
* @param run see {@link GlobalVariableSet#forRun}
* @return the first matching variable, or null if there is none
*/
public static @CheckForNull GlobalVariable byName(@Nonnull String name, @CheckForNull Run<?,?> run) {
for (GlobalVariable var : forRun(run)) {
if (var.getName().equals(name)) {
return var;
}
}
};
return null;
}

}
@@ -1,13 +1,18 @@
package org.jenkinsci.plugins.workflow.cps;

import com.google.common.collect.Lists;
import hudson.Extension;
import hudson.ExtensionList;
import hudson.ExtensionPoint;
import hudson.Util;
import hudson.model.Run;
import java.util.Collection;
import java.util.Iterator;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;

import java.util.Iterator;

/**
* Extension point that defines a collection of global variables.
*
Expand All @@ -16,6 +21,25 @@
*/
public abstract class GlobalVariableSet implements ExtensionPoint, Iterable<GlobalVariable> {

/**
* Enumerate all global variables from this provider which should be associated with a given build.
* @param run a build, which may or may not still be running; or may be left null to look for variables that exist without any context
* @return a possibly empty set
*/
public /* abstract */ @Nonnull Collection<GlobalVariable> forRun(@CheckForNull Run<?,?> run) {
return Lists.newArrayList(iterator());
}

/** @deprecated implement {@link #forJob} instead */
@Deprecated
@Override public Iterator<GlobalVariable> iterator() {
if (Util.isOverridden(GlobalVariableSet.class, getClass(), "forRun", Run.class)) {
return forRun(null).iterator();
} else {
throw new AbstractMethodError(getClass().getName() + " must implement forRun");
}
}

/**
* Allow {@link GlobalVariable}s to be defined with {@link Extension}, and make them discoverable
* via {@link GlobalVariableSet}. This simplifies the registration of single global variable.
Expand All @@ -24,8 +48,8 @@ public abstract class GlobalVariableSet implements ExtensionPoint, Iterable<Glob
@Restricted(NoExternalUse.class)
public static class GlobalVariableProvider extends GlobalVariableSet {
@Override
public Iterator<GlobalVariable> iterator() {
return ExtensionList.lookup(GlobalVariable.class).iterator();
public Collection<GlobalVariable> forRun(Run<?,?> run) {
return ExtensionList.lookup(GlobalVariable.class);
}
}
}
Expand Up @@ -426,7 +426,7 @@ public String getSymbol() {
@Restricted(DoNotUse.class) // for stapler
public Iterable<GlobalVariable> getGlobalVariables() {
// TODO order TBD. Alphabetical? Extension.ordinal?
return GlobalVariable.ALL;
return GlobalVariable.forRun(/* TODO use lastBuild if context is known */null);
}

@Restricted(NoExternalUse.class)
Expand Down

0 comments on commit 964295f

Please sign in to comment.