Package org.jacoco.maven

Source Code of org.jacoco.maven.CheckMojo

/*******************************************************************************
* Copyright (c) 2009, 2014 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*    Evgeny Mandrikov - initial API and implementation
*    Kyle Lieber - implementation of CheckMojo
*    Marc Hoffmann - redesign using report APIs
*   
*******************************************************************************/
package org.jacoco.maven;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.maven.plugin.MojoExecutionException;
import org.jacoco.core.analysis.IBundleCoverage;
import org.jacoco.core.analysis.ICoverageNode;
import org.jacoco.core.data.ExecutionDataStore;
import org.jacoco.core.tools.ExecFileLoader;
import org.jacoco.report.IReportVisitor;
import org.jacoco.report.check.IViolationsOutput;
import org.jacoco.report.check.Limit;
import org.jacoco.report.check.Rule;
import org.jacoco.report.check.RulesChecker;

/**
* Checks that the code coverage metrics are being met.
*
* @goal check
* @phase verify
* @requiresProject true
* @threadSafe
* @since 0.6.1
*/
public class CheckMojo extends AbstractJacocoMojo implements IViolationsOutput {

  private static final String MSG_SKIPPING = "Skipping JaCoCo execution due to missing execution data file:";
  private static final String CHECK_SUCCESS = "All coverage checks have been met.";
  private static final String CHECK_FAILED = "Coverage checks have not been met. See log for details.";

  /**
   * <p>
   * Check configuration used to specify rules on element types (BUNDLE,
   * PACKAGE, CLASS, SOURCEFILE or METHOD) with a list of limits. Each limit
   * applies to a certain counter (INSTRUCTION, LINE, BRANCH, COMPLEXITY,
   * METHOD, CLASS) and defines a minimum or maximum for the corresponding
   * value (TOTALCOUNT, COVEREDCOUNT, MISSEDCOUNT, COVEREDRATIO, MISSEDRATIO).
   * If a limit refers to a ratio the range is from 0.0 to 1.0 where the
   * number of decimal places will also determine the precision in error
   * messages.
   *
   * Note that you <b>must</b> use <tt>implementation</tt> hints for
   * <tt>rule</tt> and <tt>limit</tt> when using Maven 2, with Maven 3 you do
   * not need to specify the attributes.
   * </p>
   *
   * <p>
   * This example requires an overall instruction coverage of 80% and no class
   * must be missed:
   * </p>
   *
   * <pre>
   * {@code
   * <rules>
   *   <rule implementation="org.jacoco.maven.RuleConfiguration">
   *     <element>BUNDLE</element>
   *     <limits>
   *       <limit implementation="org.jacoco.report.check.Limit">
   *         <counter>INSTRUCTION</counter>
   *         <value>COVEREDRATIO</value>
   *         <minimum>0.80</minimum>
   *       </limit>
   *       <limit implementation="org.jacoco.report.check.Limit">
   *         <counter>CLASS</counter>
   *         <value>MISSEDCOUNT</value>
   *         <maximum>0</maximum>
   *       </limit>
   *     </limits>
   *   </rule>
   * </rules>}
   * </pre>
   *
   * <p>
   * This example requires a line coverage minimum of 50% for every class
   * except test classes:
   * </p>
   *
   * <pre>
   * {@code
   * <rules>
   *   <rule>
   *     <element>CLASS</element>
   *     <excludes>
   *       <exclude>*Test</exclude>
   *     </excludes>
   *     <limits>
   *       <limit>
   *         <counter>LINE</counter>
   *         <value>COVEREDRATIO</value>
   *         <minimum>0.50</minimum>
   *       </limit>
   *     </limits>
   *   </rule>
   * </rules>}
   * </pre>
   *
   * @parameter
   * @required
   */
  private List<RuleConfiguration> rules;

  /**
   * Halt the build if any of the checks fail.
   *
   * @parameter property="jacoco.haltOnFailure" default-value="true"
   * @required
   */
  private boolean haltOnFailure;

  /**
   * File with execution data.
   *
   * @parameter default-value="${project.build.directory}/jacoco.exec"
   */
  private File dataFile;

  private boolean violations;

  private boolean canCheckCoverage() {
    if (!dataFile.exists()) {
      getLog().info(MSG_SKIPPING + dataFile);
      return false;
    }
    final File classesDirectory = new File(getProject().getBuild()
        .getOutputDirectory());
    if (!classesDirectory.exists()) {
      getLog().info(
          "Skipping JaCoCo execution due to missing classes directory:"
              + classesDirectory);
      return false;
    }
    return true;
  }

  @Override
  public void executeMojo() throws MojoExecutionException,
      MojoExecutionException {
    if (!canCheckCoverage()) {
      return;
    }
    executeCheck();
  }

  private void executeCheck() throws MojoExecutionException {
    final IBundleCoverage bundle = loadBundle();
    violations = false;

    final RulesChecker checker = new RulesChecker();
    final List<Rule> checkerrules = new ArrayList<Rule>();
    for (final RuleConfiguration r : rules) {
      checkerrules.add(r.rule);
    }
    checker.setRules(checkerrules);

    final IReportVisitor visitor = checker.createVisitor(this);
    try {
      visitor.visitBundle(bundle, null);
    } catch (final IOException e) {
      throw new MojoExecutionException(
          "Error while checking code coverage: " + e.getMessage(), e);
    }
    if (violations) {
      if (this.haltOnFailure) {
        throw new MojoExecutionException(CHECK_FAILED);
      } else {
        this.getLog().warn(CHECK_FAILED);
      }
    } else {
      this.getLog().info(CHECK_SUCCESS);
    }
  }

  private IBundleCoverage loadBundle() throws MojoExecutionException {
    final FileFilter fileFilter = new FileFilter(this.getIncludes(),
        this.getExcludes());
    final BundleCreator creator = new BundleCreator(getProject(),
        fileFilter, getLog());
    try {
      final ExecutionDataStore executionData = loadExecutionData();
      return creator.createBundle(executionData);
    } catch (final IOException e) {
      throw new MojoExecutionException(
          "Error while reading code coverage: " + e.getMessage(), e);
    }
  }

  private ExecutionDataStore loadExecutionData() throws IOException {
    final ExecFileLoader loader = new ExecFileLoader();
    loader.load(dataFile);
    return loader.getExecutionDataStore();
  }

  public void onViolation(final ICoverageNode node, final Rule rule,
      final Limit limit, final String message) {
    this.getLog().warn(message);
    violations = true;
  }

}
TOP

Related Classes of org.jacoco.maven.CheckMojo

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.