org.jfrog.hudson.plugins.artifactory.util.ExtractorUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.jfrog.hudson.plugins.artifactory.util.ExtractorUtils.java

Source

/*
 * Copyright (C) 2011 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.plugins.artifactory.util;

import com.google.common.collect.Lists;
import com.google.common.collect.MapDifference;
import com.google.common.collect.Maps;
import com.google.common.io.Closeables;
import hudson.EnvVars;
import hudson.FilePath;
import hudson.Util;
import hudson.model.*;
import hudson.slaves.SlaveComputer;
import hudson.tasks.LogRotator;
import org.apache.commons.lang.StringUtils;
import org.jfrog.build.api.BuildInfoConfigProperties;
import org.jfrog.build.api.BuildInfoFields;
import org.jfrog.build.api.util.NullLog;
import org.jfrog.build.extractor.clientConfiguration.ArtifactoryClientConfiguration;
import org.jfrog.build.extractor.clientConfiguration.ClientProperties;
import org.jfrog.build.extractor.clientConfiguration.IncludeExcludePatterns;
import org.jfrog.hudson.plugins.artifactory.action.ActionableHelper;
import org.jfrog.hudson.plugins.artifactory.config.ArtifactoryServer;
import org.jfrog.hudson.plugins.artifactory.config.Credentials;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * @author Tomer Cohen
 */
public class ExtractorUtils {

    /**
     * Flag to indicate whether an external extractor was used, and the work doesn't need to be done from inside
     * Hudson.
     */
    public static final String EXTRACTOR_USED = "extractor.used";

    private ExtractorUtils() {
        // utility class
        throw new IllegalAccessError();
    }

    /**
     * Get the VCS revision from the Hudson build environment. The search will one of "SVN_REVISION", "GIT_COMMIT",
     * "P4_CHANGELIST" in the environment.
     *
     * @param env The Hudson build environment.
     * @return The vcs revision for supported VCS
     */
    public static String getVcsRevision(Map<String, String> env) {
        String revision = env.get("SVN_REVISION");
        if (StringUtils.isBlank(revision)) {
            revision = env.get("GIT_COMMIT");
        }
        if (StringUtils.isBlank(revision)) {
            revision = env.get("P4_CHANGELIST");
        }
        return revision;
    }

    /**
     * Add build info properties that will be read by an external extractor. All properties are then saved into a {@code
     * buildinfo.properties} into a temporary location. The location is then put into an environment variable {@link
     * org.jfrog.build.api.BuildInfoConfigProperties#PROP_PROPS_FILE} for the extractor to read.
     *
     * @param env              A map of the environment variables that are to be persisted into the buildinfo.properties
     *                         file. NOTE: nothing should be added to the env in this method
     * @param build            The build from which to get build/project related information from (e.g build name and
     *                         build number).
     * @param listener
     * @param publisherContext A context for publisher settings
     */
    public static ArtifactoryClientConfiguration addBuilderInfoArguments(Map<String, String> env,
            AbstractBuild build, BuildListener listener, PublisherContext publisherContext,
            ResolverContext resolverContext) throws IOException, InterruptedException {

        EnvVars envVars = new EnvVars();
        for (EnvironmentContributingAction a : Util.filter(build.getActions(),
                EnvironmentContributingAction.class)) {
            a.buildEnvVars(build, envVars);
        }
        env.putAll(envVars);

        listener.getLogger().println("*** Start env vars ***");
        for (Map.Entry<String, String> entry : env.entrySet()) {
            listener.getLogger().println(entry.getKey() + " = " + entry.getValue());
        }
        listener.getLogger().println("*** End env vars ***");

        ArtifactoryClientConfiguration configuration = new ArtifactoryClientConfiguration(new NullLog());

        if (publisherContext != null) {
            setPublisherInfo(env, build, resolverContext, publisherContext, configuration);
        }

        if (resolverContext != null) {
            setResolverInfo(configuration, resolverContext);
        }

        if ((Hudson.getInstance().getPlugin("jira") != null) && (publisherContext != null)
                && publisherContext.isEnableIssueTrackerIntegration()) {
            new IssuesTrackerHelper(build, listener, publisherContext.isAggregateBuildIssues(),
                    publisherContext.getAggregationBuildStatus()).setIssueTrackerInfo(configuration);
        }

        IncludesExcludes envVarsPatterns = new IncludesExcludes("", "");
        if (publisherContext != null && publisherContext.getEnvVarsPatterns() != null) {
            envVarsPatterns = publisherContext.getEnvVarsPatterns();
        }
        addEnvVars(env, build, configuration, envVarsPatterns);
        persistConfiguration(build, configuration, env, listener);
        return configuration;
    }

    private static void setResolverInfo(ArtifactoryClientConfiguration configuration, ResolverContext context) {
        configuration.setTimeout(context.getServer().getTimeout());
        configuration.resolver.setContextUrl(context.getServer().getUrl());
        configuration.resolver.setRepoKey(context.getServerDetails().downloadRepositoryKey);
        configuration.resolver.setUsername(context.getCredentials().getUsername());
        configuration.resolver.setPassword(context.getCredentials().getPassword());
    }

    /**
     * Set all the parameters relevant for publishing artifacts and build info
     */
    private static void setPublisherInfo(Map<String, String> env, AbstractBuild build,
            ResolverContext resolverContext, PublisherContext publisherContext,
            ArtifactoryClientConfiguration configuration) {
        configuration.setActivateRecorder(Boolean.TRUE);

        String buildName = sanitizeBuildName(build.getProject().getFullName());
        configuration.info.setBuildName(buildName);
        configuration.publisher.addMatrixParam("build.name", buildName);
        String buildNumber = build.getNumber() + "";
        configuration.info.setBuildNumber(buildNumber);
        configuration.publisher.addMatrixParam("build.number", buildNumber);

        Date buildStartDate = build.getTimestamp().getTime();
        configuration.info.setBuildStarted(buildStartDate.getTime());
        configuration.info.setBuildTimestamp(String.valueOf(buildStartDate.getTime()));
        configuration.publisher.addMatrixParam("build.timestamp", String.valueOf(buildStartDate.getTime()));

        String vcsRevision = getVcsRevision(env);
        if (StringUtils.isNotBlank(vcsRevision)) {
            configuration.info.setVcsRevision(vcsRevision);
            configuration.publisher.addMatrixParam(BuildInfoFields.VCS_REVISION, vcsRevision);
        }

        if (StringUtils.isNotBlank(publisherContext.getArtifactsPattern())) {
            configuration.publisher.setIvyArtifactPattern(publisherContext.getArtifactsPattern());
        }
        if (StringUtils.isNotBlank(publisherContext.getIvyPattern())) {
            configuration.publisher.setIvyPattern(publisherContext.getIvyPattern());
        }
        configuration.publisher.setM2Compatible(publisherContext.isMaven2Compatible());
        String buildUrl = ActionableHelper.getBuildUrl(build);
        if (StringUtils.isNotBlank(buildUrl)) {
            configuration.info.setBuildUrl(buildUrl);
        }

        String userName = null;
        Cause.UpstreamCause parent = ActionableHelper.getUpstreamCause(build);
        if (parent != null) {
            String parentProject = sanitizeBuildName(parent.getUpstreamProject());
            configuration.info.setParentBuildName(parentProject);
            configuration.publisher.addMatrixParam(BuildInfoFields.BUILD_PARENT_NAME, parentProject);
            String parentBuildNumber = parent.getUpstreamBuild() + "";
            configuration.info.setParentBuildNumber(parentBuildNumber);
            configuration.publisher.addMatrixParam(BuildInfoFields.BUILD_PARENT_NUMBER, parentBuildNumber);
            userName = "auto";
        }

        userName = ActionableHelper.getUserCausePrincipal(build, userName);

        configuration.info.setPrincipal(userName);
        configuration.info.setAgentName("Hudson");
        configuration.info.setAgentVersion(build.getHudsonVersion());
        ArtifactoryServer publishingServer = publisherContext.getArtifactoryServer();
        Credentials preferredDeployer = CredentialResolver
                .getPreferredDeployer(publisherContext.getDeployerOverrider(), publishingServer);
        if (StringUtils.isNotBlank(preferredDeployer.getUsername())) {
            configuration.publisher.setUsername(preferredDeployer.getUsername());
            configuration.publisher.setPassword(preferredDeployer.getPassword());
        }

        configuration.setTimeout(publishingServer.getTimeout());
        configuration.publisher.setContextUrl(publishingServer.getUrl());
        configuration.publisher.setRepoKey(publisherContext.getServerDetails().repositoryKey);
        configuration.publisher.setSnapshotRepoKey(publisherContext.getServerDetails().snapshotsRepositoryKey);

        configuration.info.licenseControl.setRunChecks(publisherContext.isRunChecks());
        configuration.info.licenseControl
                .setIncludePublishedArtifacts(publisherContext.isIncludePublishArtifacts());
        configuration.info.licenseControl.setAutoDiscover(publisherContext.isLicenseAutoDiscovery());
        configuration.publisher.setCopyAggregatedArtifacts(publisherContext.isCopyAggregatedArtifacts());
        configuration.publisher.setPublishAggregatedArtifacts(publisherContext.isPublishAggregatedArtifacts());
        if (StringUtils.isNotBlank(publisherContext.getAggregateArtifactsPath())) {
            configuration.publisher.setAggregateArtifacts(publisherContext.getAggregateArtifactsPath());
        }
        if (publisherContext.isRunChecks()) {
            if (StringUtils.isNotBlank(publisherContext.getViolationRecipients())) {
                configuration.info.licenseControl.setViolationRecipients(publisherContext.getViolationRecipients());
            }
            if (StringUtils.isNotBlank(publisherContext.getScopes())) {
                configuration.info.licenseControl.setScopes(publisherContext.getScopes());
            }
        }
        if (publisherContext.isDiscardOldBuilds()) {
            LogRotator rotator = build.getProject().getLogRotator();
            if (rotator != null) {
                if (rotator.getNumToKeep() > -1) {
                    configuration.info.setBuildRetentionDays(rotator.getNumToKeep());
                }
                if (rotator.getDaysToKeep() > -1) {
                    configuration.info.setBuildRetentionMinimumDate(String.valueOf(rotator.getDaysToKeep()));
                }
                configuration.info.setDeleteBuildArtifacts(publisherContext.isDiscardBuildArtifacts());
            }
            configuration.info.setBuildNumbersNotToDelete(getBuildNumbersNotToBeDeletedAsString(build));
        }
        configuration.publisher.setPublishArtifacts(publisherContext.isDeployArtifacts());
        configuration.publisher.setEvenUnstable(publisherContext.isEvenIfUnstable());
        configuration.publisher.setIvy(publisherContext.isDeployIvy());
        configuration.publisher.setMaven(publisherContext.isDeployMaven());
        IncludesExcludes deploymentPatterns = publisherContext.getIncludesExcludes();
        if (deploymentPatterns != null) {
            String includePatterns = deploymentPatterns.getIncludePatterns();
            if (StringUtils.isNotBlank(includePatterns)) {
                configuration.publisher.setIncludePatterns(includePatterns);
            }
            String excludePatterns = deploymentPatterns.getExcludePatterns();
            if (StringUtils.isNotBlank(excludePatterns)) {
                configuration.publisher.setExcludePatterns(excludePatterns);
            }
        }
        configuration.publisher
                .setFilterExcludedArtifactsFromBuild(publisherContext.isFilterExcludedArtifactsFromBuild());
        configuration.publisher.setPublishBuildInfo(!publisherContext.isSkipBuildInfoDeploy());
        configuration.setIncludeEnvVars(publisherContext.isIncludeEnvVars());
        IncludesExcludes envVarsPatterns = publisherContext.getEnvVarsPatterns();
        if (envVarsPatterns != null) {
            configuration.setEnvVarsIncludePatterns(envVarsPatterns.getIncludePatterns());
            configuration.setEnvVarsExcludePatterns(envVarsPatterns.getExcludePatterns());
        }
        addMatrixParams(publisherContext, configuration.publisher, env);
    }

    /**
     * Replaces occurrences of '/' with ' :: ' if exist
     */
    public static String sanitizeBuildName(String buildName) {
        return StringUtils.replace(buildName, "/", " :: ");
    }

    /**
     * Get the list of build numbers that are to be kept forever.
     */
    public static List<String> getBuildNumbersNotToBeDeleted(AbstractBuild build) {
        List<String> notToDelete = Lists.newArrayList();
        List<? extends Run<?, ?>> builds = build.getProject().getBuilds();
        for (Run<?, ?> run : builds) {
            if (run.isKeepLog()) {
                notToDelete.add(String.valueOf(run.getNumber()));
            }
        }
        return notToDelete;
    }

    private static String getBuildNumbersNotToBeDeletedAsString(AbstractBuild build) {
        StringBuilder builder = new StringBuilder();
        List<String> notToBeDeleted = getBuildNumbersNotToBeDeleted(build);
        for (String notToDelete : notToBeDeleted) {
            builder.append(notToDelete).append(",");
        }
        return builder.toString();
    }

    public static void persistConfiguration(AbstractBuild build, ArtifactoryClientConfiguration configuration,
            Map<String, String> env, BuildListener listener) throws IOException, InterruptedException {
        FilePath propertiesFile = build.getWorkspace().createTextTempFile("buildInfo", ".properties", "", false);
        configuration.setPropertiesFile(propertiesFile.getRemote());

        listener.getLogger().println("*** Adding env var: BUILDINFO_PROPFILE=" + propertiesFile.getRemote());
        listener.getLogger().println("*** Adding env var: " + BuildInfoConfigProperties.PROP_PROPS_FILE + "="
                + propertiesFile.getRemote());

        env.put("BUILDINFO_PROPFILE", propertiesFile.getRemote());
        env.put(BuildInfoConfigProperties.PROP_PROPS_FILE, propertiesFile.getRemote());

        listener.getLogger().println("*** Persisting properties file.");

        if (!(Computer.currentComputer() instanceof SlaveComputer)) {
            configuration.persistToPropertiesFile();
        } else {
            try {
                Properties properties = new Properties();
                properties.putAll(configuration.getAllRootConfig());
                properties.putAll(configuration.getAllProperties());
                File tempFile = File.createTempFile("buildInfo", ".properties");
                FileOutputStream stream = new FileOutputStream(tempFile);
                try {
                    properties.store(stream, "");
                } finally {
                    Closeables.closeQuietly(stream);
                }
                propertiesFile.copyFrom(tempFile.toURI().toURL());
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    private static void addMatrixParams(PublisherContext context,
            ArtifactoryClientConfiguration.PublisherHandler publisher, Map<String, String> env) {
        String matrixParams = context.getMatrixParams();
        if (StringUtils.isBlank(matrixParams)) {
            return;
        }
        String[] keyValuePairs = StringUtils.split(matrixParams, "; ");
        if (keyValuePairs == null) {
            return;
        }
        for (String keyValuePair : keyValuePairs) {
            String[] split = StringUtils.split(keyValuePair, "=");
            if (split.length == 2) {
                String value = Util.replaceMacro(split[1], env);
                publisher.addMatrixParam(split[0], value);
            }
        }
    }

    private static void addEnvVars(Map<String, String> env, AbstractBuild<?, ?> build,
            ArtifactoryClientConfiguration configuration, IncludesExcludes envVarsPatterns) {
        IncludeExcludePatterns patterns = new IncludeExcludePatterns(envVarsPatterns.getIncludePatterns(),
                envVarsPatterns.getExcludePatterns());

        // Add only the Hudson specific environment variables
        MapDifference<String, String> envDifference = Maps.difference(env, System.getenv());
        Map<String, String> filteredEnvDifference = envDifference.entriesOnlyOnLeft();
        configuration.info.addBuildVariables(filteredEnvDifference, patterns);

        // Add Hudson build variables
        Map<String, String> buildVariables = build.getBuildVariables();
        MapDifference<String, String> buildVarDifference = Maps.difference(buildVariables, System.getenv());
        Map<String, String> filteredBuildVarDifferences = buildVarDifference.entriesOnlyOnLeft();
        configuration.info.addBuildVariables(filteredBuildVarDifferences, patterns);

        // Write all the deploy (matrix params) properties.
        configuration.fillFromProperties(buildVariables, patterns);
        for (Map.Entry<String, String> entry : buildVariables.entrySet()) {
            if (entry.getKey().startsWith(ClientProperties.PROP_DEPLOY_PARAM_PROP_PREFIX)) {
                configuration.publisher.addMatrixParam(entry.getKey(), entry.getValue());
            }
        }
    }
}