/*
This file is part of Delivery Pipeline Plugin.
Delivery Pipeline Plugin is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Delivery Pipeline Plugin is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Delivery Pipeline Plugin.
If not, see <http://www.gnu.org/licenses/>.
*/
package se.diabol.jenkins.pipeline.util;
import static com.google.common.collect.Maps.newLinkedHashMap;
import hudson.EnvVars;
import hudson.Util;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Cause;
import hudson.model.ItemGroup;
import hudson.model.Items;
import hudson.model.Job;
import hudson.util.ListBoxModel;
import se.diabol.jenkins.pipeline.RelationshipResolver;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
public final class ProjectUtil {
private static final Logger LOG = Logger.getLogger(ProjectUtil.class.getName());
private ProjectUtil() {
}
public static ListBoxModel fillAllProjects(ItemGroup<?> context, Class<? extends Job> type) {
ListBoxModel options = new ListBoxModel();
for (Job p : JenkinsUtil.getInstance().getAllItems(type)) {
options.add(p.getFullDisplayName(), p.getRelativeNameFrom(context));
}
return options;
}
/**
* @see ProjectUtil#getAllDownstreamProjects(hudson.model.AbstractProject, java.util.Map)
*
*/
public static Map<String, AbstractProject<?, ?>> getAllDownstreamProjects(AbstractProject first,
AbstractProject last) {
Map<String, AbstractProject<?, ?>> projects = newLinkedHashMap();
return getAllDownstreamProjects(first, last, projects);
}
/**
* Get all downstream projects for a given project. This will recursively call all downstream projects
* for a given first project.
* A project that has a downstream project and will eventually loop back to itself will log a warning,
* and will NOT add. Adding a project that already exists will produce a stack overflow.
*
* @param first The first project
* @param last The last project to visualize
* @param projects Current map of all sub projects.
* @return A map of all downstream projects.
*/
public static Map<String, AbstractProject<?, ?>> getAllDownstreamProjects(AbstractProject first,
AbstractProject last, Map<String,
AbstractProject<?, ?>> projects) {
if (first == null) {
return projects;
}
if (projects.containsValue(first)) {
return projects;
}
if (last != null && first.getFullName().equals(last.getFullName())) {
projects.put(last.getFullName(), last);
return projects;
}
projects.put(first.getFullName(), first);
for (AbstractProject p : getDownstreamProjects(first)) {
projects.putAll(getAllDownstreamProjects(p, last, projects));
}
return projects;
}
public static List<AbstractProject> getDownstreamProjects(AbstractProject<?, ?> project) {
List<AbstractProject> result = new ArrayList<AbstractProject>();
List<RelationshipResolver> resolvers = RelationshipResolver.all();
for (RelationshipResolver resolver : resolvers) {
result.addAll(resolver.getDownstreamProjects(project));
}
return result;
}
public static AbstractProject<?, ?> getProject(String name, ItemGroup context) {
return JenkinsUtil.getInstance().getItem(name, context, AbstractProject.class);
}
public static Map<String, AbstractProject> getProjects(String regExp) {
if (regExp != null && regExp.trim().equals("")) {
return Collections.emptyMap();
}
try {
Pattern pattern = Pattern.compile(regExp);
Map<String, AbstractProject> result = new HashMap<String, AbstractProject>();
for (AbstractProject<?, ?> project : JenkinsUtil.getInstance().getAllItems(AbstractProject.class)) {
Matcher matcher = pattern.matcher(project.getFullName());
if (matcher.find()) {
if (matcher.groupCount() >= 1) {
String name = matcher.group(1);
result.put(name, project);
} else {
LOG.log(Level.WARNING, "Could not find match group");
}
}
}
return result;
} catch (PatternSyntaxException e) {
LOG.log(Level.WARNING, "Could not find projects on regular expression", e);
return Collections.emptyMap();
}
}
public static boolean isQueued(AbstractProject project, AbstractBuild firstBuild) {
if (!project.isInQueue()) {
return false;
} else if (firstBuild == null) {
return true;
}
List<Cause.UpstreamCause> causes = Util.filter(project.getQueueItem().getCauses(),
Cause.UpstreamCause.class);
@SuppressWarnings("unchecked")
List<AbstractProject<?,?>> upstreamProjects = project.getUpstreamProjects();
for (AbstractProject<?, ?> upstreamProject : upstreamProjects) {
AbstractBuild upstreamBuild = BuildUtil.match(upstreamProject.getBuilds(), firstBuild);
if (upstreamBuild != null) {
for (Cause.UpstreamCause upstreamCause : causes) {
if (upstreamBuild.getNumber() == upstreamCause.getUpstreamBuild()
&& upstreamProject.getRelativeNameFrom(JenkinsUtil.getInstance()).equals(
upstreamCause.getUpstreamProject())) {
return true;
}
}
}
}
return false;
}
public static List<AbstractProject> getProjectList(String projects, ItemGroup context, EnvVars env) {
List<AbstractProject> projectList = new ArrayList<AbstractProject>();
// expand variables if applicable
StringBuilder projectNames = new StringBuilder();
StringTokenizer tokens = new StringTokenizer(projects, ",");
while (tokens.hasMoreTokens()) {
if (projectNames.length() > 0) {
projectNames.append(',');
}
projectNames.append(env != null ? env.expand(tokens.nextToken().trim()) : tokens.nextToken().trim());
}
projectList.addAll(Items.fromNameList(context, projectNames.toString(), AbstractProject.class));
return projectList;
}
public static List<AbstractProject> getStartUpstreams(AbstractProject project) {
List<AbstractProject> upstreams = project.getUpstreamProjects();
if (upstreams.isEmpty()) {
return new ArrayList<AbstractProject>(Collections.singleton(project));
} else {
return getStartUpstreams(project, new ArrayList<AbstractProject>());
}
}
private static List<AbstractProject> getStartUpstreams(AbstractProject project, List<AbstractProject> edges) {
List<AbstractProject> upstreams = project.getUpstreamProjects();
if (upstreams.isEmpty()) {
edges.add(project);
return edges;
} else {
List<AbstractProject> result = new ArrayList<AbstractProject>(edges);
for (AbstractProject upstream : upstreams) {
result = (getStartUpstreams(upstream, edges));
}
return result;
}
}
}