001 /*
002 * SonarQube, open source software quality management tool.
003 * Copyright (C) 2008-2014 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * SonarQube is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * SonarQube is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public License
017 * along with this program; if not, write to the Free Software Foundation,
018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
019 */
020 package org.sonar.batch.scan;
021
022 import org.apache.commons.lang.ArrayUtils;
023 import org.apache.commons.lang.StringUtils;
024 import org.slf4j.Logger;
025 import org.slf4j.LoggerFactory;
026 import org.sonar.api.CoreProperties;
027 import org.sonar.api.batch.bootstrap.ProjectBuilder;
028 import org.sonar.api.batch.bootstrap.ProjectDefinition;
029 import org.sonar.api.batch.bootstrap.ProjectReactor;
030 import org.sonar.api.config.Settings;
031 import org.sonar.api.task.TaskComponent;
032
033 import javax.annotation.Nullable;
034
035 /**
036 * Exclude the sub-projects as defined by the properties sonar.skippedModules and sonar.includedModules
037 *
038 * @since 2.12
039 */
040 public class ProjectExclusions implements TaskComponent {
041
042 private static final Logger LOG = LoggerFactory.getLogger(ProjectExclusions.class);
043
044 private Settings settings;
045 private ProjectReactor reactor;
046
047 public ProjectExclusions(Settings settings, ProjectReactor reactor,
048 // exclusions are applied when the project is completely defined by extensions
049 @Nullable ProjectBuilder[] projectBuilders) {
050 this.settings = settings;
051 this.reactor = reactor;
052 }
053
054 public ProjectExclusions(Settings settings, ProjectReactor reactor) {
055 this(settings, reactor, new ProjectBuilder[0]);
056 }
057
058 public void apply() {
059 if (!reactor.getProjects().isEmpty() && StringUtils.isNotBlank(reactor.getProjects().get(0).getKey())) {
060 LOG.info("Apply project exclusions");
061
062 if (settings.hasKey(CoreProperties.CORE_INCLUDED_MODULES_PROPERTY)) {
063 LOG.warn("'sonar.includedModules' property is deprecated since version 4.3 and should not be used anymore.");
064 }
065 if (settings.hasKey(CoreProperties.CORE_SKIPPED_MODULES_PROPERTY)) {
066 LOG.warn("'sonar.skippedModules' property is deprecated since version 4.3 and should not be used anymore.");
067 }
068
069 for (ProjectDefinition project : reactor.getProjects()) {
070 if (isExcluded(key(project), project == reactor.getRoot())) {
071 exclude(project);
072 }
073 }
074 }
075 }
076
077 private boolean isExcluded(String projectKey, boolean isRoot) {
078 String[] includedKeys = settings.getStringArray(CoreProperties.CORE_INCLUDED_MODULES_PROPERTY);
079 boolean excluded = false;
080 if (!isRoot && includedKeys.length > 0) {
081 excluded = !ArrayUtils.contains(includedKeys, projectKey);
082 }
083 String skippedModulesProperty = CoreProperties.CORE_SKIPPED_MODULES_PROPERTY;
084 if (!excluded) {
085 String[] excludedKeys = settings.getStringArray(skippedModulesProperty);
086 excluded = ArrayUtils.contains(excludedKeys, projectKey);
087 }
088 if (excluded && isRoot) {
089 throw new IllegalArgumentException("The root project can't be excluded. Please check the parameters " + skippedModulesProperty + " and sonar.includedModules.");
090 }
091 return excluded;
092 }
093
094 private void exclude(ProjectDefinition project) {
095 LOG.info(String.format("Exclude project: %s [%s]", project.getName(), project.getKey()));
096 project.remove();
097 }
098
099 static String key(ProjectDefinition project) {
100 String key = project.getKey();
101 if (key.contains(":")) {
102 return StringUtils.substringAfter(key, ":");
103 }
104 return key;
105 }
106 }