Package org.jfrog.build.extractor.maven

Source Code of org.jfrog.build.extractor.maven.BuildInfoRecorder

/*
* 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.build.extractor.maven;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.io.Closeables;
import org.apache.commons.lang.StringUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DefaultArtifact;
import org.apache.maven.artifact.metadata.ArtifactMetadata;
import org.apache.maven.execution.AbstractExecutionListener;
import org.apache.maven.execution.ExecutionEvent;
import org.apache.maven.execution.ExecutionListener;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.artifact.ProjectArtifactMetadata;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.logging.Logger;
import org.jfrog.build.api.Build;
import org.jfrog.build.api.BuildInfoConfigProperties;
import org.jfrog.build.api.builder.ArtifactBuilder;
import org.jfrog.build.api.builder.BuildInfoMavenBuilder;
import org.jfrog.build.api.builder.DependencyBuilder;
import org.jfrog.build.api.builder.ModuleBuilder;
import org.jfrog.build.api.util.FileChecksumCalculator;
import org.jfrog.build.client.*;
import org.jfrog.build.extractor.BuildInfoExtractor;
import org.jfrog.build.extractor.BuildInfoExtractorUtils;
import org.jfrog.build.extractor.maven.resolver.ResolutionHelper;
import org.xml.sax.InputSource;
import javax.xml.xpath.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.util.*;

import static org.jfrog.build.extractor.BuildInfoExtractorUtils.getModuleIdString;
import static org.jfrog.build.extractor.BuildInfoExtractorUtils.getTypeString;

/*
* Will be called for every project/module in the Maven project.
*/

/**
* @author Noam Y. Tenne
*/
@Component(role = BuildInfoRecorder.class)
public class BuildInfoRecorder extends AbstractExecutionListener implements BuildInfoExtractor<ExecutionEvent, Build> {

    @Requirement
    private Logger logger;

    @Requirement
    private BuildInfoModelPropertyResolver buildInfoModelPropertyResolver;

    @Requirement
    private BuildDeploymentHelper buildDeploymentHelper;

    @Requirement
    private ResolutionHelper resolutionHelper;

    private ExecutionListener wrappedListener;
    private BuildInfoMavenBuilder buildInfoBuilder;
    private ThreadLocal<ModuleBuilder> currentModule = new ThreadLocal<ModuleBuilder>();
    private ThreadLocal<Set<Artifact>> currentModuleArtifacts = new ThreadLocal<Set<Artifact>>();
    private ThreadLocal<Set<Artifact>> currentModuleDependencies = new ThreadLocal<Set<Artifact>>();
    private volatile boolean projectHasTestFailures;
    private Map<String, DeployDetails> deployableArtifactBuilderMap;
    private ArtifactoryClientConfiguration conf;
    private Map<String, String> matrixParams;
    private XPath xPath;
    private XPathExpression xPathExpression;
    private Set<Artifact> resolvedArtifacts = Collections.synchronizedSet(new HashSet<Artifact>());

    public void setListenerToWrap(ExecutionListener executionListener) {
        wrappedListener = executionListener;
    }

    public void setConfiguration(ArtifactoryClientConfiguration conf) {
        this.conf = conf;
    }

    /**
     * The repository listeners (either ArtifactoryEclipseRepositoryListener or ArtifactorySonatypeRepositoryListener) invoke this method
     * with each artifact being resolved by Maven.
     * @param artifact  The artifact being resolved by Maven.
     */
    public void artifactResolved(Artifact artifact) {
        if (artifact != null) {
            resolvedArtifacts.add(artifact);
        }
    }

    @Override
    public void projectDiscoveryStarted(ExecutionEvent event) {
        if (wrappedListener != null) {
            wrappedListener.projectDiscoveryStarted(event);
        }
    }

    @Override
    public void sessionStarted(ExecutionEvent event) {
        try {
            logger.info("Initializing Artifactory Build-Info Recording");
            buildInfoBuilder = buildInfoModelPropertyResolver.resolveProperties(event, conf);
            deployableArtifactBuilderMap = Maps.newHashMap();
            matrixParams = Maps.newHashMap();
            Map<String, String> matrixParamProps = conf.publisher.getMatrixParams();
            for (Map.Entry<String, String> matrixParamProp : matrixParamProps.entrySet()) {
                String key = matrixParamProp.getKey();
                key = StringUtils.removeStartIgnoreCase(key, ClientProperties.PROP_DEPLOY_PARAM_PROP_PREFIX);
                matrixParams.put(key, matrixParamProp.getValue());
            }

            if (wrappedListener != null) {
                wrappedListener.sessionStarted(event);
            }
        } catch (Throwable t) {
            String message = getClass().getName() + ".sessionStarted() listener has failed: ";
            logger.error(message, t);
            throw new RuntimeException(message, t);
        }
    }

    @Override
    public void sessionEnded(ExecutionEvent event) {
        try {
            Build build = extract(event);
            if (build != null) {
                File basedir = event.getSession().getTopLevelProject().getBasedir();
                conf.persistToPropertiesFile();
                buildDeploymentHelper.deploy(build, conf, deployableArtifactBuilderMap, projectHasTestFailures, basedir);
            }
            deployableArtifactBuilderMap.clear();
            if (wrappedListener != null) {
                wrappedListener.sessionEnded(event);
            }
        } catch (Throwable t) {
            String message = getClass().getName() + ".sessionEnded() listener has failed: ";
            logger.error(message, t);
            throw new RuntimeException(message, t);
        } finally {
            String propertyFilePath = System.getenv(BuildInfoConfigProperties.PROP_PROPS_FILE);
            if (StringUtils.isNotBlank(propertyFilePath)) {
                File file = new File(propertyFilePath);
                if (file.exists()) {
                    file.delete();
                }
            }
        }
    }

    @Override
    public void projectSkipped(ExecutionEvent event) {
        if (wrappedListener != null) {
            wrappedListener.projectSkipped(event);
        }
    }

    @Override
    public void projectStarted(ExecutionEvent event) {
        MavenProject project = event.getProject();
        initModule(project);

        if (wrappedListener != null) {
            wrappedListener.projectStarted(event);
        }
    }

    @Override
    public void projectSucceeded(ExecutionEvent event) {
        finalizeModule(event.getProject());
        if (wrappedListener != null) {
            wrappedListener.projectSucceeded(event);
        }
    }

    @Override
    public void projectFailed(ExecutionEvent event) {
        if (wrappedListener != null) {
            wrappedListener.projectFailed(event);
        }
    }

    @Override
    public void forkStarted(ExecutionEvent event) {
        if (wrappedListener != null) {
            wrappedListener.forkStarted(event);
        }
    }

    @Override
    public void forkSucceeded(ExecutionEvent event) {
        if (wrappedListener != null) {
            wrappedListener.forkSucceeded(event);
        }
    }

    @Override
    public void forkFailed(ExecutionEvent event) {
        if (wrappedListener != null) {
            wrappedListener.forkFailed(event);
        }
    }

    @Override
    public void forkedProjectStarted(ExecutionEvent event) {
        if (wrappedListener != null) {
            wrappedListener.forkedProjectStarted(event);
        }
    }

    @Override
    public void forkedProjectSucceeded(ExecutionEvent event) {
        if (wrappedListener != null) {
            wrappedListener.forkedProjectSucceeded(event);
        }
    }

    @Override
    public void forkedProjectFailed(ExecutionEvent event) {
        if (wrappedListener != null) {
            wrappedListener.forkedProjectFailed(event);
        }
    }

    @Override
    public void mojoSkipped(ExecutionEvent event) {
        if (wrappedListener != null) {
            wrappedListener.mojoSkipped(event);
        }
    }

    @Override
    public void mojoStarted(ExecutionEvent event) {
        if (wrappedListener != null) {
            wrappedListener.mojoStarted(event);
        }
    }

    @Override
    public void mojoSucceeded(ExecutionEvent event) {
        MavenProject project = event.getProject();
        if (project == null) {
            logger.warn("Skipping Artifactory Build-Info dependency extraction: Null project.");
            return;
        }
        if (!projectHasTestFailures && "maven-surefire-plugin".equals((event).getMojoExecution().getPlugin().getArtifactId())) {
            List<File> resultsFile = getSurefireResultsFile(project);
            if (isTestsFailed(resultsFile)) {
                projectHasTestFailures = true;
            }
        }
        extractModuleDependencies(project);
        if (wrappedListener != null) {
            wrappedListener.mojoSucceeded(event);
        }
    }

    private List<File> getSurefireResultsFile(MavenProject project) {
        List<File> surefireReports = Lists.newArrayList();
        File surefireDirectory = new File(new File(project.getFile().getParentFile(), "target"), "surefire-reports");
        String[] xmls;
        try {
            xmls = surefireDirectory.list(new FilenameFilter() {
                public boolean accept(File dir, String name) {
                    return name.endsWith("xml");
                }
            });
        } catch (Exception e) {
            logger.error("Error occurred: " + e.getMessage() + " while retrieving surefire descriptors at: " +
                    surefireDirectory.getAbsolutePath(), e);
            return Lists.newArrayList();
        }
        if (xmls != null) {
            for (String xml : xmls) {
                surefireReports.add(new File(surefireDirectory, xml));
            }
        }
        return surefireReports;
    }

    private boolean isTestsFailed(List<File> surefireReports) {

        for (File report : surefireReports) {
            FileInputStream stream = null;
            try {
                stream = new FileInputStream(report);
                setXpathPattern();
                Object evaluate = xPathExpression.evaluate(new InputSource(stream),
                        XPathConstants.STRING);
                if (evaluate != null && StringUtils.isNotBlank(evaluate.toString()) && evaluate.toString().equals("true")) {
                    return true;
                }
            } catch (FileNotFoundException e) {
                logger.error("File '" + report.getAbsolutePath() + "' does not exist.");
            } catch (XPathExpressionException e) {
                logger.error("Expression '/testsuite/@failures>0 or /testsuite/@errors>0' is invalid.");
            } finally {
                Closeables.closeQuietly(stream);
            }
        }
        return false;
    }

    @Override
    public void mojoFailed(ExecutionEvent event) {
        MavenProject project = event.getProject();
        if (project == null) {
            logger.warn("Skipping Artifactory Build-Info dependency extraction: Null project.");
            return;
        }
        extractModuleDependencies(project);
        if (wrappedListener != null) {
            wrappedListener.mojoFailed(event);
        }
    }

    private void initModule(MavenProject project) {
        if (project == null) {
            logger.warn("Skipping Artifactory Build-Info module initialization: Null project.");
            return;
        }
        ModuleBuilder module = new ModuleBuilder();
        module.id(getModuleIdString(project.getGroupId(), project.getArtifactId(), project.getVersion()));
        module.properties(project.getProperties());

        currentModule.set(module);

        currentModuleArtifacts.set(Sets.<Artifact>newHashSet());
        currentModuleDependencies.set(Sets.<Artifact>newHashSet());
    }

    private void extractArtifactsAndDependencies(MavenProject project) {
        if (project == null) {
            logger.warn("Skipping Artifactory Build-Info artifact and dependency extraction: Null project.");
            return;
        }
        Set<Artifact> artifacts = currentModuleArtifacts.get();
        if (artifacts == null) {
            logger.warn("Skipping Artifactory Build-Info project artifact extraction: Null current module artifacts.");
        } else {
            extractModuleArtifact(project, artifacts);
            extractModuleAttachedArtifacts(project, artifacts);
        }

        extractModuleDependencies(project);
    }

    private void finalizeModule(MavenProject project) {
        extractArtifactsAndDependencies(project);
        finalizeAndAddModule(project);
    }

    //In case of Pom project, the Artifact will be the Pom file.
    private void extractModuleArtifact(MavenProject project, Set<Artifact> artifacts) {
        Artifact artifact = project.getArtifact();
        if (artifact == null) {
            logger.warn("Skipping Artifactory Build-Info project artifact extraction: Null artifact.");
            return;
        }
        artifacts.add(artifact);
    }


    /*
    * Attached Artifacts- are the artifacts/assemblies like tests, sources and so on....
    *   Not include the Pom file
    */
    private void extractModuleAttachedArtifacts(MavenProject project, Set<Artifact> artifacts) {
        List<Artifact> attachedArtifacts = project.getAttachedArtifacts();
        if (attachedArtifacts != null) {
            for (Artifact attachedArtifact : attachedArtifacts) {
                artifacts.add(attachedArtifact);
            }
        }
    }

    private void extractModuleDependencies(MavenProject project) {
        Set<Artifact> moduleDependencies = currentModuleDependencies.get();
        if (moduleDependencies == null) {
            logger.warn("Skipping Artifactory Build-Info project dependency extraction: Null current module dependencies.");
            return;
        }

        mergeProjectDependencies(project.getArtifacts());
    }

    /**
     * Merge the dependencies taken from the MavenProject object with those collected inside the resolvedArtifacts collection.
     * @param projectDependencies   The artifacts taken from the MavenProject object.
     */
    private void mergeProjectDependencies(Set<Artifact> projectDependencies) {
        // Go over all the artifacts taken from the MavenProject object, and replace their equals method, so that we are
        // able to merge them together with the artifacts inside the resolvedArtifacts set:
        Set<Artifact> dependecies = Sets.newHashSet();
        for(Artifact artifact : projectDependencies) {
            DefaultArtifact art = new DefaultArtifact(artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion(),
                    artifact.getScope(), artifact.getType(), "", artifact.getArtifactHandler()) {

                public boolean equals(Object o) {
                    if (o == this) {
                        return true;
                    }
                    if (!(o instanceof org.apache.maven.artifact.Artifact)) {
                        return false;
                    }
                    return hashCode() == o.hashCode();
                }
            };
            art.setFile(artifact.getFile());
            dependecies.add(art);
        }

        // Now we merge the artifacts from the two collections. In case an artifact is included in both collections, we'd like to keep
        // the one that was taken from the MavenProject, because of the scope it has.
        // The merge is done only if the client is configured to do so.
        Set<Artifact> moduleDependencies = currentModuleDependencies.get();
        Set<Artifact> tempSet = Sets.newHashSet(moduleDependencies);
        moduleDependencies.clear();
        moduleDependencies.addAll(dependecies);
        moduleDependencies.addAll(tempSet);
        if (conf.publisher.isRecordAllDependencies()) {
            moduleDependencies.addAll(resolvedArtifacts);
        }
    }

    private void finalizeAndAddModule(MavenProject project) {
        addFilesToCurrentModule(project);
        currentModule.remove();
        currentModuleArtifacts.remove();
        currentModuleDependencies.remove();
        resolvedArtifacts.clear();
    }

    private void addFilesToCurrentModule(MavenProject project) {
        ModuleBuilder module = currentModule.get();
        if (module == null) {
            logger.warn("Skipping Artifactory Build-Info module finalization: Null current module.");
            return;
        }
        addArtifactsToCurrentModule(project, module);
        addDependenciesToCurrentModule(module);

        buildInfoBuilder.addModule(module.build());
    }

    private void addArtifactsToCurrentModule(MavenProject project, ModuleBuilder module) {
        Set<Artifact> moduleArtifacts = currentModuleArtifacts.get();
        if (moduleArtifacts == null) {
            logger.warn("Skipping Artifactory Build-Info module artifact addition: Null current module artifact list.");
            return;
        }

        ArtifactoryClientConfiguration.PublisherHandler publisher = conf.publisher;
        IncludeExcludePatterns patterns = new IncludeExcludePatterns(
                publisher.getIncludePatterns(), publisher.getExcludePatterns());
        boolean excludeArtifactsFromBuild = publisher.isFilterExcludedArtifactsFromBuild();
        for (Artifact moduleArtifact : moduleArtifacts) {
            String artifactId = moduleArtifact.getArtifactId();
            String artifactVersion = moduleArtifact.getVersion();
            String artifactClassifier = moduleArtifact.getClassifier();
            String artifactExtension = moduleArtifact.getArtifactHandler().getExtension();
            String type = getTypeString(moduleArtifact.getType(), artifactClassifier, artifactExtension);

            String artifactName = getArtifactName(artifactId, artifactVersion, artifactClassifier, artifactExtension);

            ArtifactBuilder artifactBuilder = new ArtifactBuilder(artifactName).type(type);
            File artifactFile = moduleArtifact.getFile();
            // for pom projects take the file from the project if the artifact file is null
            if (isPomProject(moduleArtifact) && moduleArtifact.equals(project.getArtifact())) {
                artifactFile = project.getFile();   // project.getFile() returns the project pom file
            }
            org.jfrog.build.api.Artifact artifact = artifactBuilder.build();
            String groupId = moduleArtifact.getGroupId();
            String deploymentPath = getDeploymentPath(groupId, artifactId, artifactVersion, artifactClassifier, artifactExtension);
            // If excludeArtifactsFromBuild and the PatternMatcher found conflict, add the excluded artifact to the excluded artifact set.
            if (excludeArtifactsFromBuild && PatternMatcher.pathConflicts(deploymentPath, patterns)) {
                module.addExcludedArtifact(artifact);
            } else {
                module.addArtifact(artifact);
            }
            if (isPublishArtifacts(artifactFile)) {
                addDeployableArtifact(artifact, artifactFile, moduleArtifact.getGroupId(),
                        artifactId, artifactVersion, artifactClassifier, artifactExtension);
            }

            /*
            * In case of non packaging Pom project module, we need to create the pom file from the ProjectArtifactMetadata on the Artifact
            */
            if (!isPomProject(moduleArtifact)) {
                for (ArtifactMetadata metadata : moduleArtifact.getMetadataList()) {
                    if (metadata instanceof ProjectArtifactMetadata) {  // the pom metadata
                        File pomFile = ((ProjectArtifactMetadata) metadata).getFile();
                        artifactBuilder.type("pom");
                        String pomFileName = StringUtils.removeEnd(artifactName, artifactExtension) + "pom";
                        artifactBuilder.name(pomFileName);
                        org.jfrog.build.api.Artifact pomArtifact = artifactBuilder.build();
                        deploymentPath = getDeploymentPath(groupId, artifactId, artifactVersion, artifactClassifier, "pom");
                        if (excludeArtifactsFromBuild && PatternMatcher.pathConflicts(deploymentPath, patterns)) {
                            module.addExcludedArtifact(pomArtifact);
                        } else {
                            module.addArtifact(pomArtifact);
                        }
                        if (isPublishArtifacts(pomFile)) {
                            addDeployableArtifact(pomArtifact, pomFile, moduleArtifact.getGroupId(),
                                    artifactId, artifactVersion,
                                    artifactClassifier, "pom");
                        }
                        break;
                    }
                }
            }
        }
    }

    private boolean isPublishArtifacts(File fileToDeploy) {
        if (fileToDeploy == null || !fileToDeploy.isFile()) {
            return false;
        }
        if (!conf.publisher.isPublishArtifacts()) {
            return false;
        }
        return conf.publisher.isEvenUnstable() || !projectHasTestFailures;
    }

    private String getArtifactName(String artifactId, String version, String classifier, String fileExtension) {
        StringBuilder nameBuilder = new StringBuilder(artifactId).append("-").append(version);
        if (StringUtils.isNotBlank(classifier)) {
            nameBuilder.append("-").append(classifier);
        }

        return nameBuilder.append(".").append(fileExtension).toString();
    }

    private void addDeployableArtifact(org.jfrog.build.api.Artifact artifact, File artifactFile,
                                       String groupId, String artifactId, String version, String classifier, String fileExtension) {
        String deploymentPath = getDeploymentPath(groupId, artifactId, version, classifier, fileExtension);
        // deploy to snapshots or releases repository based on the deploy version
        String targetRepository = getTargetRepository(deploymentPath);

        DeployDetails deployable = new DeployDetails.Builder().artifactPath(deploymentPath).file(artifactFile).
                targetRepository(targetRepository).addProperties(conf.publisher.getMatrixParams()).build();
        String myArtifactId = BuildInfoExtractorUtils.getArtifactId(currentModule.get().build().getId(),
                artifact.getName());
        deployableArtifactBuilderMap.put(myArtifactId, deployable);
    }

    /**
     * @param deployPath the full path string to extract the repo from
     * @return Return the target deployment repository. Either the releases repository (default) or snapshots if defined
     * and the deployed file is a snapshot.
     */
    public String getTargetRepository(String deployPath) {
        String snapshotsRepository = conf.publisher.getSnapshotRepoKey();
        if (snapshotsRepository != null && deployPath.contains("-SNAPSHOT")) {
            return snapshotsRepository;
        }
        return conf.publisher.getRepoKey();
    }

    private String getDeploymentPath(String groupId, String artifactId, String version, String classifier,
                                     String fileExtension) {
        return new StringBuilder(groupId.replace(".", "/")).append("/").append(artifactId).append("/").append(version).
                append("/").append(getArtifactName(artifactId, version, classifier, fileExtension)).toString();
    }

    private void addDependenciesToCurrentModule(ModuleBuilder module) {
        Set<Artifact> moduleDependencies = currentModuleDependencies.get();
        if (moduleDependencies == null) {
            logger.warn("Skipping Artifactory Build-Info module dependency addition: Null current module dependency " +
                    "list.");
            return;
        }
        for (Artifact dependency : moduleDependencies) {
            File depFile = dependency.getFile();
            DependencyBuilder dependencyBuilder = new DependencyBuilder()
                    .id(getModuleIdString(dependency.getGroupId(), dependency.getArtifactId(),
                            dependency.getVersion()))
                    .type(getTypeString(dependency.getType(),
                            dependency.getClassifier(), getExtension(depFile)));
            String scopes = dependency.getScope();
            if (StringUtils.isNotBlank(scopes)) {
                dependencyBuilder.scopes(Lists.newArrayList(scopes));
            }
            setDependencyChecksums(depFile, dependencyBuilder);
            module.addDependency(dependencyBuilder.build());
        }
    }

    private String getExtension(File depFile) {
        String extension = "";
        String fileName = depFile.getName();
        if (depFile != null && fileName != null) {
            int lastDot = fileName.lastIndexOf('.');
            if (lastDot > 0 && lastDot + 1 < fileName.length()) {
                extension = fileName.substring(lastDot + 1);
            }
        }
        return extension;
    }

    private boolean isPomProject(Artifact moduleArtifact) {
        return "pom".equals(moduleArtifact.getType());
    }

    private void setDependencyChecksums(File dependencyFile, DependencyBuilder dependencyBuilder) {
        if ((dependencyFile != null) && (dependencyFile.isFile())) {
            try {
                Map<String, String> checksumsMap =
                        FileChecksumCalculator.calculateChecksums(dependencyFile, "md5", "sha1");
                dependencyBuilder.md5(checksumsMap.get("md5"));
                dependencyBuilder.sha1(checksumsMap.get("sha1"));
            } catch (Exception e) {
                logger.error("Could not set checksum values on '" + dependencyBuilder.build().getId() + "': " +
                        e.getMessage(), e);
            }
        }
    }

    @Override
    public Build extract(ExecutionEvent event) {
        MavenSession session = event.getSession();
        if (!session.getResult().hasExceptions()) {
            if (conf.isIncludeEnvVars()) {
                Properties envProperties = new Properties();
                envProperties.putAll(conf.getAllProperties());
                envProperties = BuildInfoExtractorUtils.getEnvProperties(envProperties, conf.getLog());
                for (Map.Entry<Object, Object> envProp : envProperties.entrySet()) {
                    buildInfoBuilder.addProperty(envProp.getKey(), envProp.getValue());
                }
            }
            Date finish = new Date();
            long time = finish.getTime() - session.getRequest().getStartTime().getTime();

            return buildInfoBuilder.durationMillis(time).build();
        }

        return null;
    }

    /**
     * Set pattern for the "Surefire" plugin report, this pattern check if we
     * have failures or error is a specific test
     */
    private void setXpathPattern() throws XPathExpressionException {
        if (xPath == null) {
            xPath = XPathFactory.newInstance().newXPath();
            xPathExpression = xPath.compile("/testsuite/@failures>0 or /testsuite/@errors>0");
        }
    }
}
TOP

Related Classes of org.jfrog.build.extractor.maven.BuildInfoRecorder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.