All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jfrog.hudson.maven2.ArtifactsDeployer Maven / Gradle / Ivy

The newest version!
/*
 * 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.maven2;

import hudson.EnvVars;
import hudson.Util;
import hudson.maven.MavenBuild;
import hudson.maven.MavenModule;
import hudson.maven.MavenModuleSetBuild;
import hudson.maven.reporters.MavenArtifact;
import hudson.maven.reporters.MavenArtifactRecord;
import hudson.model.*;
import hudson.util.VersionNumber;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.jfrog.build.api.BuildInfoFields;
import org.jfrog.build.api.util.FileChecksumCalculator;
import org.jfrog.build.client.ArtifactoryBuildInfoClient;
import org.jfrog.build.client.DeployDetails;
import org.jfrog.build.client.IncludeExcludePatterns;
import org.jfrog.build.client.PatternMatcher;
import org.jfrog.hudson.ArtifactoryRedeployPublisher;
import org.jfrog.hudson.ArtifactoryServer;
import org.jfrog.hudson.action.ActionableHelper;
import org.jfrog.hudson.release.ReleaseAction;
import org.jfrog.hudson.util.BuildUniqueIdentifierHelper;
import org.jfrog.hudson.util.ExtractorUtils;
import org.jfrog.hudson.util.IncludesExcludes;
import org.jfrog.hudson.util.MavenVersionHelper;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.logging.Logger;

/**
 * Deploys artifacts to Artifactory. This class is used only when the Maven 3 extractor is not active.
 *
 * @author Yossi Shaul
 */
public class ArtifactsDeployer {
    private static Logger debuggingLogger = Logger.getLogger(ArtifactsDeployer.class.getName());
    private static final String HIGHEST_VERSION_BEFORE_ARCHIVE_FIX = "1.404";
    private static final String SHA1 = "SHA1";

    private final ArtifactoryServer artifactoryServer;
    private final String targetReleasesRepository;
    private final String targetSnapshotsRepository;
    private final ArtifactoryBuildInfoClient client;
    private final MavenModuleSetBuild mavenModuleSetBuild;
    private final BuildListener listener;
    private final IncludeExcludePatterns patterns;
    private final boolean downstreamIdentifier;
    private final boolean isArchiveJenkinsVersion;
    private final EnvVars env;
    private final String[] matrixParams;
    private final AbstractBuild rootBuild;

    public ArtifactsDeployer(ArtifactoryRedeployPublisher artifactoryPublisher, ArtifactoryBuildInfoClient client,
                             MavenModuleSetBuild mavenModuleSetBuild, BuildListener listener) throws IOException, InterruptedException {
        this.client = client;
        this.mavenModuleSetBuild = mavenModuleSetBuild;
        this.listener = listener;
        this.env = mavenModuleSetBuild.getEnvironment(listener);
        this.artifactoryServer = artifactoryPublisher.getArtifactoryServer();
        // release action might change the target releases repository
        ReleaseAction releaseAction = ActionableHelper.getLatestAction(mavenModuleSetBuild, ReleaseAction.class);
        if (releaseAction != null) {
            String stagingRepoKey = releaseAction.getStagingRepositoryKey();
            if (StringUtils.isBlank(stagingRepoKey)) {
                stagingRepoKey = artifactoryPublisher.getRepositoryKey();
            }
            this.targetReleasesRepository = stagingRepoKey;
        } else {
            this.targetReleasesRepository = artifactoryPublisher.getRepositoryKey();
        }
        this.targetSnapshotsRepository = artifactoryPublisher.getSnapshotsRepositoryKey();
        this.downstreamIdentifier = artifactoryPublisher.isPassIdentifiedDownstream();
        IncludesExcludes patterns = artifactoryPublisher.getArtifactDeploymentPatterns();
        if (patterns != null) {
            this.patterns = new IncludeExcludePatterns(patterns.getIncludePatterns(), patterns.getExcludePatterns());
        } else {
            this.patterns = IncludeExcludePatterns.EMPTY;
        }
        this.matrixParams = StringUtils.split(artifactoryPublisher.getMatrixParams(), "; ");
        debuggingLogger.fine("Getting root build");
        this.rootBuild = BuildUniqueIdentifierHelper.getRootBuild(mavenModuleSetBuild);
        this.isArchiveJenkinsVersion = Hudson.getVersion().isNewerThan(new VersionNumber(
                HIGHEST_VERSION_BEFORE_ARCHIVE_FIX));
    }

    public void deploy() throws IOException, InterruptedException, NoSuchAlgorithmException {
        listener.getLogger().println("Deploying artifacts to " + artifactoryServer.getUrl());
        Map mavenBuildMap = mavenModuleSetBuild.getModuleLastBuilds();

        for (Map.Entry mavenBuildEntry : mavenBuildMap.entrySet()) {
            MavenBuild mavenBuild = mavenBuildEntry.getValue();
            Result result = mavenBuild.getResult();
            if (Result.NOT_BUILT.equals(result)) {
                // HAP-52 - the module build might be skipped if using incremental build
                listener.getLogger().println(
                        "Module: '" + mavenBuildEntry.getKey().getName() + "' wasn't built. Skipping.");
                continue;
            }
            listener.getLogger().println("Deploying artifacts of module: " + mavenBuildEntry.getKey().getName());
            MavenArtifactRecord mar = ActionableHelper.getLatestMavenArtifactRecord(mavenBuild);
            MavenArtifact mavenArtifact = mar.mainArtifact;

            // deploy main artifact
            debuggingLogger.fine("Deploying main artifact: " + artifactToString(mavenArtifact, mavenBuild));
            deployArtifact(mavenBuild, mavenArtifact);
            if (!mar.isPOM() && mar.pomArtifact != null && mar.pomArtifact != mar.mainArtifact) {
                // deploy the pom if the main artifact is not the pom
                debuggingLogger.fine("Deploying pom artifact: " + artifactToString(mavenArtifact, mavenBuild));
                deployArtifact(mavenBuild, mar.pomArtifact);
            }

            // deploy attached artifacts
            for (MavenArtifact attachedArtifact : mar.attachedArtifacts) {
                debuggingLogger.fine("Deploying attached artifact: " + artifactToString(mavenArtifact, mavenBuild));
                deployArtifact(mavenBuild, attachedArtifact);
            }
        }
    }

    private String artifactToString(MavenArtifact mavenArtifact, MavenBuild mavenBuild) throws IOException {
        return new StringBuilder().append(ToStringBuilder.reflectionToString(mavenArtifact))
                .append("[File: ").append(getArtifactFile(mavenBuild, mavenArtifact)).append("]")
                .toString();
    }

    private void deployArtifact(MavenBuild mavenBuild, MavenArtifact mavenArtifact)
            throws IOException, InterruptedException, NoSuchAlgorithmException {
        String artifactPath = buildArtifactPath(mavenArtifact);

        if (PatternMatcher.pathConflicts(artifactPath, patterns)) {
            listener.getLogger().println("Skipping the deployment of '" + artifactPath +
                    "' due to the defined include-exclude patterns.");
            return;
        }

        File artifactFile = getArtifactFile(mavenBuild, mavenArtifact);
        // calculate the sha1 checksum that is not given by Jenkins and add it to the deploy details
        Map checksums = FileChecksumCalculator.calculateChecksums(artifactFile, SHA1);
        DeployDetails.Builder builder = new DeployDetails.Builder()
                .file(artifactFile)
                .artifactPath(artifactPath)
                .targetRepository(getTargetRepository(mavenArtifact.version))
                .md5(mavenArtifact.md5sum).sha1(checksums.get(SHA1))
                .addProperty("build.name", ExtractorUtils.sanitizeBuildName(mavenModuleSetBuild.getParent().getFullName()))
                .addProperty("build.number", mavenModuleSetBuild.getNumber() + "")
                .addProperty("build.timestamp", mavenBuild.getTimestamp().getTime().getTime() + "");

        String identifier = BuildUniqueIdentifierHelper.getUpstreamIdentifier(rootBuild);
        if (StringUtils.isNotBlank(identifier)) {
            builder.addProperty(BuildInfoFields.BUILD_ROOT, identifier);
        }

        Cause.UpstreamCause parent = ActionableHelper.getUpstreamCause(mavenModuleSetBuild);
        if (parent != null) {
            builder.addProperty("build.parentName", ExtractorUtils.sanitizeBuildName(parent.getUpstreamProject()))
                    .addProperty("build.parentNumber", parent.getUpstreamBuild() + "");
        }
        String revision = ExtractorUtils.getVcsRevision(env);
        if (StringUtils.isNotBlank(revision)) {
            builder.addProperty(BuildInfoFields.VCS_REVISION, revision);
        }
        addMatrixParams(builder);
        DeployDetails deployDetails = builder.build();
        logDeploymentPath(deployDetails, artifactPath);
        client.deployArtifact(deployDetails);
    }

    private void addMatrixParams(DeployDetails.Builder builder) {
        if (matrixParams == null) {
            return;
        }
        for (String matrixParam : matrixParams) {
            String[] split = StringUtils.split(matrixParam, '=');
            if (split.length == 2) {
                String value = Util.replaceMacro(split[1], env);
                builder.addProperty(split[0], value);
            }
        }
    }

    private void logDeploymentPath(DeployDetails deployDetails, String artifactPath) {
        String deploymentPath =
                artifactoryServer.getUrl() + "/" + deployDetails.getTargetRepository() + "/" + artifactPath;
        listener.getLogger().println("Deploying artifact: " + deploymentPath);
    }

    /**
     * @return Return the target deployment repository. Either the releases repository (default) or snapshots if defined
     *         and the deployed version is a snapshot.
     */
    public String getTargetRepository(String version) {
        if (targetSnapshotsRepository != null && version.endsWith("SNAPSHOT")) {
            return targetSnapshotsRepository;
        }
        return targetReleasesRepository;
    }

    private String buildArtifactPath(MavenArtifact mavenArtifact) {
        String directoryPath =
                mavenArtifact.groupId.replace('.', '/') + "/" + mavenArtifact.artifactId + "/" + mavenArtifact.version;
        return directoryPath + "/" + mavenArtifact.canonicalName;
    }

    /**
     * Obtains the {@link java.io.File} representing the archived artifact.
     */
    private File getArtifactFile(MavenBuild build, MavenArtifact mavenArtifact) throws IOException {
        String fileName = mavenArtifact.fileName;
        if (isArchiveJenkinsVersion) {
            fileName = mavenArtifact.canonicalName;
        }
        File file = new File(new File(new File(new File(build.getArtifactsDir(), mavenArtifact.groupId),
                mavenArtifact.artifactId), mavenArtifact.version), fileName);
        if (!file.exists()) {
            throw new FileNotFoundException("Archived artifact is missing: " + file + " " + getAdditionalMessage());
        }
        return file;
    }

    /**
     * @return An additional error message to be attached to the exception
     */
    private String getAdditionalMessage() throws IOException {
        try {
            if (MavenVersionHelper.isLowerThanMaven3(mavenModuleSetBuild, env, listener)) {
                return "\nDisabling the automatic archiving and using the external Maven extractor is compatible with Maven 3.0.2 and up";
            }
            return "";
        } catch (InterruptedException e) {
            throw new RuntimeException("Unable to determine Maven version", e);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy