/* * Copyright (C) 2010 JFrog Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jfrog.hudson.action; import com.google.common.collect.Lists; import hudson.matrix.MatrixConfiguration; import hudson.maven.MavenBuild; import hudson.maven.reporters.MavenArtifactRecord; import hudson.model.*; import hudson.tasks.BuildWrapper; import hudson.tasks.Builder; import hudson.tasks.Publisher; import hudson.util.DescribableList; import jenkins.model.Jenkins; import org.apache.commons.lang.StringUtils; import org.jfrog.build.client.ArtifactoryHttpClient; import org.jfrog.hudson.util.publisher.PublisherFindImpl; import org.jfrog.hudson.util.publisher.PublisherFlexible; import java.util.Collections; import java.util.List; /** * @author Yossi Shaul */ public abstract class ActionableHelper { public static MavenArtifactRecord getLatestMavenArtifactRecord(MavenBuild mavenBuild) { return getLatestAction(mavenBuild, MavenArtifactRecord.class); } /** * Returns the latest action of the type. One module may produce multiple action entries of the same type, in some * cases the last one contains all the info we need (previous ones might only contain partial information, eg, only * main artifact) * * @param build The build * @param actionClass The type of the action * @return Latest action of the given type or null if not found */ public static <T extends Action> T getLatestAction(Run build, Class<T> actionClass) { List<T> records = build.getActions(actionClass); if (records == null || records.isEmpty()) { return null; } else { return records.get(records.size() - 1); } } /** * Search for a publisher of the given type in a project and return it, or null if it is not found. * @return The publisher */ public static <T extends Publisher> T getPublisher(AbstractProject<?, ?> project, Class<T> type) { // Search for a publisher of the given type in the project and return it if found: T publisher = new PublisherFindImpl<T>().find(project, type); if (publisher != null) { return publisher; } // If not found, the publisher might be wrapped by a "Flexible Publish" publisher. The below searches for it inside the // Flexible Publisher: publisher = new PublisherFlexible<T>().find(project, type); return publisher; } /** * @return The wrapped item (eg, project) wrapper of the given type. Null if not found. */ public static <T extends BuildWrapper> T getBuildWrapper(BuildableItem wrapped, Class<T> type) { DescribableList<BuildWrapper, Descriptor<BuildWrapper>> wrappers = ((BuildableItemWithBuildWrappers) wrapped).getBuildWrappersList(); for (BuildWrapper wrapper : wrappers) { if (type.isInstance(wrapper)) { return type.cast(wrapper); } } return null; } /** * Get a list of {@link Builder}s that are related to the project. * * @param project The project from which to get the builder. * @param type The type of the builder (the actual class) * @param <T> The type that the class represents * @return A list of builders that answer the class definition that are attached to the project. */ public static <T extends Builder> List<T> getBuilder(Project<?, ?> project, Class<T> type) { List<T> result = Lists.newArrayList(); DescribableList<Builder, Descriptor<Builder>> builders = project.getBuildersList(); for (Builder builder : builders) { if (type.isInstance(builder)) { result.add(type.cast(builder)); } } return result; } public static Cause.UpstreamCause getUpstreamCause(Run build) { CauseAction action = ActionableHelper.getLatestAction(build, CauseAction.class); if (action != null) { for (Cause cause : action.getCauses()) { if (cause instanceof Cause.UpstreamCause) { return (Cause.UpstreamCause) cause; } } } return null; } /** * @param build The build * @return The user id caused triggered the build. "anonymous" if not started by a user */ public static String getUserCausePrincipal(Run build) { return getUserCausePrincipal(build, "anonymous"); } /** * @param build The build * @param defaultPrincipal Principal to return if the user who caused the id is not found * @return The user id caused triggered the build of default principal if not found */ public static String getUserCausePrincipal(Run build, String defaultPrincipal) { Cause.UserIdCause userCause = getUserCause(build); String principal = defaultPrincipal; if (userCause != null && userCause.getUserId() != null) { principal = userCause.getUserId(); } return principal; } private static Cause.UserIdCause getUserCause(Run build) { CauseAction action = ActionableHelper.getLatestAction(build, CauseAction.class); if (action != null) { for (Cause cause : action.getCauses()) { if (cause instanceof Cause.UserIdCause) { return (Cause.UserIdCause) cause; } } } return null; } public static String getBuildUrl(Run build) { String root = Hudson.getInstance().getRootUrl(); if (StringUtils.isBlank(root)) { return ""; } return root + build.getUrl(); } /** * Return list with {@link ArtifactoryProjectAction} if not already exists in project actions. * * @param artifactoryServerName The name of Artifactory server * @param project The hudson project * @return Empty list or list with one {@link ArtifactoryProjectAction} */ public static List<ArtifactoryProjectAction> getArtifactoryProjectAction( String artifactoryServerName, AbstractProject project) { if (shouldReturnEmptyList(artifactoryServerName, project)) return Collections.emptyList(); return Lists.newArrayList(new ArtifactoryProjectAction(artifactoryServerName, project)); } private static boolean shouldReturnEmptyList(String artifactoryServerName, AbstractProject project) { if (artifactoryServerName == null) { return true; } if (project.getAction(ArtifactoryProjectAction.class) != null) { // don't add if already exist (if multiple Artifactory builders are configured in free style) return true; } if (project instanceof MatrixConfiguration) return true; return false; } /** * Return list with {@link ArtifactoryProjectAction} if not already exists in project actions. * * @param artifactoryServerName The name of Artifactory server * @param project The hudson project * @return Empty list or list with one {@link ArtifactoryProjectAction} */ public static List<ArtifactoryProjectAction> getArtifactoryProjectAction( String artifactoryServerName, AbstractProject project, String buildName) { if (shouldReturnEmptyList(artifactoryServerName, project)) { return Collections.emptyList(); } return Lists.newArrayList(new ArtifactoryProjectAction(artifactoryServerName, buildName)); } /** * Returns the version of Jenkins Artifactory Plugin or empty string if not found * @return the version of Jenkins Artifactory Plugin or empty string if not found */ public static String getArtifactoryPluginVersion(){ String pluginsSortName = "artifactory"; //Validates Jenkins existence because in some jobs the Jenkins instance is unreachable if(Jenkins.getInstance() != null && Jenkins.getInstance().getPlugin(pluginsSortName) != null && Jenkins.getInstance().getPlugin(pluginsSortName).getWrapper() != null) { return Jenkins.getInstance().getPlugin(pluginsSortName).getWrapper().getVersion(); } return ""; } /** * Returns the default number of retries * @return the default number of retries */ public static int getDefaultConnectionRetries() { return ArtifactoryHttpClient.DEFAULT_CONNECTION_RETRY; } }