Permalink
Browse files

[JENKINS-28113] Allow freestyle builds to trigger downstream Pipeline…

… builds (#2873)

* Offering default methods on ParameterizedJob.

* Javadoc typo.

* Cleaner use of default methods in ParameterizedJob.

* Need to pick up infradna/bridge-method-injector#15 to be able to build.

* Sketch of pulling disabled functionality into ParameterizedJob.

* EnableJobCommandTest.groovy → EnableJobCommandTest.java, and replacing deprecated Remoting-based CLI calls with CLICommandInvoker.

* All CLI commands could be broken by a missing CLI.*.shortDescription key on just one!

* Forgot to move CLI method short descriptions to new package.

* Needed a @CLIResolver for ParameterizedJob. Adding an OptionHandler while we are here.

* Trying to fix up access-modifier versions; started failing in CI today for unknown reasons.

* Introduced <p:makeDisabled/> by analogy with <p:config-disableBuild/>.

* Using new type bounds.

* access-modifier 1.11 released.

* MatrixProject and MavenModuleSet both expect to have access to makeDisabled.jelly.

* Trying to generalize some more.

* Minor simplification.

* [JENKINS-34716] Generalizing doPolling and schedulePolling.

* isBuildable

* Obsolete comment.

* Updated comments.

* bridge-method-injector 1.17

* Unfortunately AbstractProject.schedulePolling cannot delegate to SCMTriggerItem.

* [FIXED JENKINS-28113] Generalize BuildTrigger to be able to trigger non-AbstractProject downstream ParameterizedJob’s without DependencyGraph.

* [JENKINS-22949] Dropping QueueItemAuthenticator trickiness, as in #2881.
  • Loading branch information...
jglick authored and oleg-nenashev committed May 14, 2017
1 parent 3af0cc6 commit f1a26582c1b25c470989d19b25378cff5c6d2497
@@ -1615,7 +1615,7 @@ void removeFromList(Descriptor<T> item, List<T> collection) throws IOException {
for (AbstractProject<?,?> ap : getUpstreamProjects()) {
BuildTrigger buildTrigger = ap.getPublishersList().get(BuildTrigger.class);
if (buildTrigger != null)
if (buildTrigger.getChildProjects(ap).contains(this))
if (buildTrigger.getChildJobs(ap).contains(this))
result.add(ap);
}
return result;
@@ -59,8 +59,10 @@
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import jenkins.model.DependencyDeclarer;
import jenkins.model.Jenkins;
import jenkins.model.ParameterizedJobMixIn;
import jenkins.security.QueueItemAuthenticatorConfiguration;
import jenkins.security.QueueItemAuthenticatorDescriptor;
import jenkins.triggers.ReverseBuildTrigger;
@@ -151,21 +153,31 @@ public Result getThreshold() {
return getChildProjects(Jenkins.getInstance());
}
/** @deprecated use {@link #getChildJobs} */
@Deprecated
public List<AbstractProject> getChildProjects(AbstractProject owner) {
return getChildProjects(owner==null?null:owner.getParent());
}
@Deprecated
public List<AbstractProject> getChildProjects(ItemGroup base) {
return Items.fromNameList(base,childProjects,AbstractProject.class);
}
@SuppressWarnings("unchecked")
@Nonnull
public List<Job<?, ?>> getChildJobs(@Nonnull AbstractProject<?, ?> owner) {
return Items.fromNameList(owner.getParent(), childProjects, (Class<Job<?, ?>>) (Class) Job.class);
}
public BuildStepMonitor getRequiredMonitorService() {
return BuildStepMonitor.NONE;
}
/**
* Checks if this trigger has the exact same set of children as the given list.
* @deprecated apparently unused
*/
@Deprecated
public boolean hasSame(AbstractProject owner, Collection<? extends AbstractProject> projects) {
List<AbstractProject> children = getChildProjects(owner);
return children.size()==projects.size() && children.containsAll(projects);
@@ -182,6 +194,48 @@ public boolean hasSame(Collection<? extends AbstractProject> projects) {
@Override
public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) {
List<Job<?, ?>> jobs = new ArrayList<>();
for (Job<?, ?> job : getChildJobs(build.getProject())) {
if (job instanceof AbstractProject) {
continue; // taken care of by DependencyGraph
}
jobs.add(job);
}
if (!jobs.isEmpty() && build.getResult().isBetterOrEqualTo(threshold)) {
PrintStream logger = listener.getLogger();
for (Job<?, ?> downstream : jobs) {
if (Jenkins.getInstance().getItemByFullName(downstream.getFullName()) != downstream) {
LOGGER.log(Level.WARNING, "Running as {0} cannot even see {1} for trigger from {2}", new Object[] {Jenkins.getAuthentication().getName(), downstream, build.getParent()});
continue;
}
if (!downstream.hasPermission(Item.BUILD)) {
listener.getLogger().println(Messages.BuildTrigger_you_have_no_permission_to_build_(ModelHyperlinkNote.encodeTo(downstream)));
continue;
}
if (!(downstream instanceof ParameterizedJobMixIn.ParameterizedJob)) {
logger.println(Messages.BuildTrigger_NotBuildable(ModelHyperlinkNote.encodeTo(downstream)));
continue;
}
ParameterizedJobMixIn.ParameterizedJob<?, ?> pj = (ParameterizedJobMixIn.ParameterizedJob) downstream;
if (pj.isDisabled()) {
logger.println(Messages.BuildTrigger_Disabled(ModelHyperlinkNote.encodeTo(downstream)));
continue;
}
if (!downstream.isBuildable()) { // some other reason; no API to retrieve cause
logger.println(Messages.BuildTrigger_NotBuildable(ModelHyperlinkNote.encodeTo(downstream)));
continue;
}
boolean scheduled = pj.scheduleBuild(pj.getQuietPeriod(), new UpstreamCause((Run) build));
if (Jenkins.getInstance().getItemByFullName(downstream.getFullName()) == downstream) {
String name = ModelHyperlinkNote.encodeTo(downstream);
if (scheduled) {
logger.println(Messages.BuildTrigger_Triggering(name));
} else {
logger.println(Messages.BuildTrigger_InQueue(name));
}
}
}
}
return true;
}
@@ -270,7 +324,7 @@ public int compare(Dependency lhs, Dependency rhs) {
}
public void buildDependencyGraph(AbstractProject owner, DependencyGraph graph) {
for (AbstractProject p : getChildProjects(owner))
for (AbstractProject p : getChildProjects(owner)) // only care about AbstractProject here
graph.addDependency(new Dependency(owner, p) {
@Override
public boolean shouldTriggerBuild(AbstractBuild build, TaskListener listener,
@@ -381,11 +435,11 @@ public FormValidation doCheck(@AncestorInPath AbstractProject project, @QueryPar
if (StringUtils.isNotBlank(projectName)) {
Item item = Jenkins.getInstance().getItem(projectName,project,Item.class);
if (item == null) {
AbstractProject nearest = AbstractProject.findNearest(projectName,project.getParent());
Job<?, ?> nearest = Items.findNearest(Job.class, projectName, project.getParent());
String alternative = nearest != null ? nearest.getRelativeNameFrom(project) : "?";
return FormValidation.error(Messages.BuildTrigger_NoSuchProject(projectName, alternative));
}
if(!(item instanceof AbstractProject))
if(!(item instanceof ParameterizedJobMixIn.ParameterizedJob))
return FormValidation.error(Messages.BuildTrigger_NotBuildable(projectName));
// check whether the supposed user is expected to be able to build
Authentication auth = Tasks.getAuthenticationOf(project);

0 comments on commit f1a2658

Please sign in to comment.