*/
package org.sonar.batch.bootstrap;
-import org.sonar.batch.issue.tracking.TrackedIssue;
-
-import org.sonar.batch.issue.tracking.ServerIssueFromWs;
-import org.sonar.core.issue.tracking.Tracker;
import com.google.common.collect.Lists;
-
import java.util.Collection;
import java.util.List;
-
import org.sonar.batch.cpd.CpdComponents;
+import org.sonar.batch.issue.tracking.ServerIssueFromWs;
+import org.sonar.batch.issue.tracking.TrackedIssue;
import org.sonar.batch.scan.report.ConsoleReport;
import org.sonar.batch.scan.report.HtmlReport;
import org.sonar.batch.scan.report.IssuesReportBuilder;
import org.sonar.batch.scm.ScmSensor;
import org.sonar.batch.source.CodeColorizerSensor;
import org.sonar.batch.source.LinesSensor;
+import org.sonar.batch.task.ListTask;
+import org.sonar.batch.task.ScanTask;
+import org.sonar.batch.task.Tasks;
+import org.sonar.batch.task.ViewsTask;
import org.sonar.core.component.DefaultResourceTypes;
import org.sonar.core.config.CorePropertyDefinitions;
+import org.sonar.core.issue.tracking.Tracker;
public class BatchComponents {
private BatchComponents() {
HtmlReport.class,
IssuesReportBuilder.class,
SourceProvider.class,
- RuleNameProvider.class
- );
+ RuleNameProvider.class,
+
+ // Tasks
+ Tasks.class,
+ ListTask.DEFINITION,
+ ListTask.class,
+ ScanTask.DEFINITION,
+ ScanTask.class,
+ ViewsTask.DEFINITION,
+ ViewsTask.class);
components.addAll(CorePropertyDefinitions.all());
// CPD
components.addAll(CpdComponents.all());
*/
package org.sonar.batch.bootstrap;
-import com.github.kevinsawicki.http.HttpRequest;
-import java.net.MalformedURLException;
-import java.net.URL;
import java.util.List;
import java.util.Map;
-import javax.annotation.CheckForNull;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.CoreProperties;
import org.sonar.api.SonarPlugin;
-import org.sonar.api.platform.Server;
-import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.UriReader;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.batch.analysis.AnalysisProperties;
-import org.sonar.batch.analysis.DefaultAnalysisMode;
import org.sonar.batch.cache.GlobalPersistentCacheProvider;
import org.sonar.batch.cache.ProjectSyncContainer;
import org.sonar.batch.cache.StrategyWSLoaderProvider;
import org.sonar.batch.repository.DefaultGlobalRepositoriesLoader;
import org.sonar.batch.repository.GlobalRepositoriesLoader;
import org.sonar.batch.repository.GlobalRepositoriesProvider;
-import org.sonar.batch.scan.ProjectScanContainer;
+import org.sonar.batch.task.TaskContainer;
import org.sonar.core.platform.ComponentContainer;
import org.sonar.core.platform.PluginClassloaderFactory;
import org.sonar.core.platform.PluginInfo;
import org.sonar.core.util.DefaultHttpDownloader;
import org.sonar.core.util.UuidFactoryImpl;
-import static java.lang.String.format;
-
public class GlobalContainer extends ComponentContainer {
- private static final org.sonar.api.utils.log.Logger LOG = Loggers.get(GlobalContainer.class);
-
private final Map<String, String> bootstrapProperties;
private boolean preferCache;
}
}
- public void executeAnalysis(Map<String, String> analysisProperties, Object... components) {
- GlobalProperties globalProperties = this.getComponentByType(GlobalProperties.class);
- // SONAR-6888
- String task = analysisProperties.get(CoreProperties.TASK);
- if ("views".equals(task)) {
- triggerViews(this.getComponentByType(ServerClient.class), this.getComponentByType(Server.class));
- return;
- }
- if (StringUtils.isNotBlank(task) && !CoreProperties.SCAN_TASK.equals(task)) {
- throw MessageException.of("Tasks are no more supported on batch side since SonarQube 5.2");
- }
-
- AnalysisProperties props = new AnalysisProperties(analysisProperties, globalProperties.property(CoreProperties.ENCRYPTION_SECRET_KEY_PATH));
- if (isIssuesMode(props)) {
- String projectKey = getProjectKeyWithBranch(props);
- new ProjectSyncContainer(this, projectKey, false).execute();
- }
- new ProjectScanContainer(this, props, components).execute();
- }
-
- private static void triggerViews(ServerClient serverClient, Server server) {
- LOG.info("Trigger Views update");
- URL url;
- try {
- url = new URL(serverClient.getURL() + "/api/views/run");
- } catch (MalformedURLException e) {
- throw new IllegalArgumentException("Invalid URL", e);
- }
- HttpRequest request = HttpRequest.post(url);
- request.trustAllCerts();
- request.trustAllHosts();
- request.header("User-Agent", format("SonarQube %s", server.getVersion()));
- request.basic(serverClient.getLogin(), serverClient.getPassword());
- if (!request.ok()) {
- int responseCode = request.code();
- if (responseCode == 401) {
- throw new IllegalStateException(format(serverClient.getMessageWhenNotAuthorized(), CoreProperties.LOGIN, CoreProperties.PASSWORD));
- }
- if (responseCode == 409) {
- throw new IllegalStateException("A full refresh of Views is already queued or running");
- }
- if (responseCode == 403) {
- // SONAR-4397 Details are in response content
- throw new IllegalStateException(request.body());
- }
- throw new IllegalStateException(format("Fail to execute request [code=%s, url=%s]: %s", responseCode, url, request.body()));
- }
- }
-
- @CheckForNull
- private static String getProjectKeyWithBranch(AnalysisProperties props) {
- String projectKey = props.property(CoreProperties.PROJECT_KEY_PROPERTY);
- if (projectKey != null && props.property(CoreProperties.PROJECT_BRANCH_PROPERTY) != null) {
- projectKey = projectKey + ":" + props.property(CoreProperties.PROJECT_BRANCH_PROPERTY);
- }
- return projectKey;
+ public void executeTask(Map<String, String> taskProperties, Object... components) {
+ new TaskContainer(this, taskProperties, components).execute();
}
public void syncProject(String projectKey, boolean force) {
new ProjectSyncContainer(this, projectKey, force).execute();
}
- private boolean isIssuesMode(AnalysisProperties props) {
- DefaultAnalysisMode mode = new DefaultAnalysisMode(this.getComponentByType(GlobalProperties.class), props);
- return mode.isIssues();
- }
-
}
*/
public Batch executeTask(Map<String, String> analysisProperties, Object... components) {
checkStarted();
- bootstrapContainer.executeAnalysis(analysisProperties, components);
+ bootstrapContainer.executeTask(analysisProperties, components);
return this;
}
*/
public Batch executeTask(Map<String, String> analysisProperties, IssueListener issueListener) {
checkStarted();
- bootstrapContainer.executeAnalysis(analysisProperties, components, issueListener);
+ bootstrapContainer.executeTask(analysisProperties, components, issueListener);
return this;
}
*/
package org.sonar.batch.scan;
-import org.sonar.batch.issue.DefaultProjectIssues;
-
import com.google.common.annotations.VisibleForTesting;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.InstantiationStrategy;
import org.sonar.batch.index.Caches;
import org.sonar.batch.index.DefaultIndex;
import org.sonar.batch.issue.DefaultIssueCallback;
+import org.sonar.batch.issue.DefaultProjectIssues;
import org.sonar.batch.issue.IssueCache;
import org.sonar.batch.issue.tracking.DefaultServerLineHashesLoader;
import org.sonar.batch.issue.tracking.IssueTransition;
private static final Logger LOG = Loggers.get(ProjectScanContainer.class);
- private final Object[] components;
private final AnalysisProperties props;
- public ProjectScanContainer(ComponentContainer globalContainer, AnalysisProperties props, Object... components) {
+ public ProjectScanContainer(ComponentContainer globalContainer, AnalysisProperties props) {
super(globalContainer);
this.props = props;
- this.components = components;
}
@Override
protected void doBeforeStart() {
- for (Object component : components) {
- add(component);
- }
addBatchComponents();
getComponentByType(ProjectLock.class).tryLock();
addBatchExtensions();
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.task;
+
+import org.sonar.api.task.Task;
+import org.sonar.api.task.TaskDefinition;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+
+public class ListTask implements Task {
+
+ private static final Logger LOG = Loggers.get(ListTask.class);
+
+ public static final String KEY = "list";
+
+ public static final TaskDefinition DEFINITION = TaskDefinition.builder()
+ .key(KEY)
+ .description("List available tasks")
+ .taskClass(ListTask.class)
+ .build();
+
+ private final Tasks tasks;
+
+ public ListTask(Tasks tasks) {
+ this.tasks = tasks;
+ }
+
+ @Override
+ public void execute() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("\nAvailable tasks:\n");
+ for (TaskDefinition def : tasks.definitions()) {
+ sb.append(" - " + def.key() + ": " + def.description() + "\n");
+ }
+ sb.append("\n");
+ LOG.info(sb.toString());
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.task;
+
+import javax.annotation.CheckForNull;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.task.Task;
+import org.sonar.api.task.TaskDefinition;
+import org.sonar.batch.analysis.AnalysisProperties;
+import org.sonar.batch.analysis.DefaultAnalysisMode;
+import org.sonar.batch.bootstrap.GlobalProperties;
+import org.sonar.batch.cache.ProjectSyncContainer;
+import org.sonar.batch.scan.ProjectScanContainer;
+import org.sonar.core.platform.ComponentContainer;
+
+public class ScanTask implements Task {
+ public static final TaskDefinition DEFINITION = TaskDefinition.builder()
+ .description("Scan project")
+ .key(CoreProperties.SCAN_TASK)
+ .taskClass(ScanTask.class)
+ .build();
+
+ private final ComponentContainer taskContainer;
+ private final TaskProperties taskProps;
+
+ public ScanTask(TaskContainer taskContainer, TaskProperties taskProps) {
+ this.taskContainer = taskContainer;
+ this.taskProps = taskProps;
+ }
+
+ @Override
+ public void execute() {
+ AnalysisProperties props = new AnalysisProperties(taskProps.properties(), taskProps.property(CoreProperties.ENCRYPTION_SECRET_KEY_PATH));
+ if (isIssuesMode(props)) {
+ String projectKey = getProjectKeyWithBranch(props);
+ new ProjectSyncContainer(taskContainer, projectKey, false).execute();
+ }
+ new ProjectScanContainer(taskContainer, props).execute();
+ }
+
+ @CheckForNull
+ private static String getProjectKeyWithBranch(AnalysisProperties props) {
+ String projectKey = props.property(CoreProperties.PROJECT_KEY_PROPERTY);
+ if (projectKey != null && props.property(CoreProperties.PROJECT_BRANCH_PROPERTY) != null) {
+ projectKey = projectKey + ":" + props.property(CoreProperties.PROJECT_BRANCH_PROPERTY);
+ }
+ return projectKey;
+ }
+
+ private boolean isIssuesMode(AnalysisProperties props) {
+ DefaultAnalysisMode mode = new DefaultAnalysisMode(taskContainer.getComponentByType(GlobalProperties.class), props);
+ return mode.isIssues();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.task;
+
+import java.util.Map;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.batch.InstantiationStrategy;
+import org.sonar.api.config.EmailSettings;
+import org.sonar.api.task.Task;
+import org.sonar.api.task.TaskDefinition;
+import org.sonar.api.utils.MessageException;
+import org.sonar.batch.bootstrap.ExtensionInstaller;
+import org.sonar.batch.bootstrap.ExtensionMatcher;
+import org.sonar.batch.bootstrap.ExtensionUtils;
+import org.sonar.batch.bootstrap.GlobalProperties;
+import org.sonar.core.platform.ComponentContainer;
+
+public class TaskContainer extends ComponentContainer {
+
+ private final Map<String, String> taskProperties;
+ private final Object[] components;
+
+ public TaskContainer(ComponentContainer parent, Map<String, String> taskProperties, Object... components) {
+ super(parent);
+ this.taskProperties = taskProperties;
+ this.components = components;
+ }
+
+ @Override
+ protected void doBeforeStart() {
+ addTaskExtensions();
+ addCoreComponents();
+ for (Object component : components) {
+ add(component);
+ }
+ }
+
+ private void addCoreComponents() {
+ add(new TaskProperties(taskProperties, getParent().getComponentByType(GlobalProperties.class).property(CoreProperties.ENCRYPTION_SECRET_KEY_PATH)));
+ add(EmailSettings.class);
+ }
+
+ private void addTaskExtensions() {
+ getComponentByType(ExtensionInstaller.class).install(this, new TaskExtensionFilter());
+ }
+
+ static class TaskExtensionFilter implements ExtensionMatcher {
+ @Override
+ public boolean accept(Object extension) {
+ return ExtensionUtils.isBatchSide(extension)
+ && ExtensionUtils.isInstantiationStrategy(extension, InstantiationStrategy.PER_TASK);
+ }
+ }
+
+ @Override
+ public void doAfterStart() {
+ // default value is declared in CorePlugin
+ String taskKey = StringUtils.defaultIfEmpty(taskProperties.get(CoreProperties.TASK), CoreProperties.SCAN_TASK);
+ // Release memory
+ taskProperties.clear();
+
+ TaskDefinition def = getComponentByType(Tasks.class).definition(taskKey);
+ if (def == null) {
+ throw MessageException.of("Task '" + taskKey + "' does not exist. Please use '" + ListTask.KEY + "' task to see all available tasks.");
+ }
+ Task task = getComponentByType(def.taskClass());
+ if (task != null) {
+ task.execute();
+ } else {
+ throw new IllegalStateException("Task " + taskKey + " is badly defined");
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.task;
+
+import java.util.Map;
+import javax.annotation.Nullable;
+import org.sonar.batch.bootstrap.UserProperties;
+
+/**
+ * Batch properties that are specific to a task (for example
+ * coming from sonar-project.properties).
+ */
+public class TaskProperties extends UserProperties {
+
+ public TaskProperties(Map<String, String> properties, @Nullable String pathToSecretKey) {
+ super(properties, pathToSecretKey);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.task;
+
+import com.google.common.collect.ImmutableSortedMap;
+import com.google.common.collect.Maps;
+import java.util.Collection;
+import java.util.Map;
+import java.util.SortedMap;
+import org.sonar.api.batch.BatchSide;
+import org.sonar.api.batch.InstantiationStrategy;
+import org.sonar.api.task.Task;
+import org.sonar.api.task.TaskDefinition;
+
+@BatchSide
+@InstantiationStrategy(InstantiationStrategy.PER_TASK)
+public class Tasks {
+
+ private final SortedMap<String, TaskDefinition> byKey;
+
+ public Tasks(TaskDefinition[] definitions) {
+ SortedMap<String, TaskDefinition> map = Maps.newTreeMap();
+ for (TaskDefinition definition : definitions) {
+ if (map.containsKey(definition.key())) {
+ throw new IllegalStateException("Task '" + definition.key() + "' is declared twice");
+ }
+ map.put(definition.key(), definition);
+ }
+ this.byKey = ImmutableSortedMap.copyOf(map);
+ }
+
+ public TaskDefinition definition(String taskKey) {
+ return byKey.get(taskKey);
+ }
+
+ public Collection<TaskDefinition> definitions() {
+ return byKey.values();
+ }
+
+ /**
+ * Perform validation of task definitions
+ */
+ public void start() {
+ checkDuplicatedClasses();
+ }
+
+ private void checkDuplicatedClasses() {
+ Map<Class<? extends Task>, TaskDefinition> byClass = Maps.newHashMap();
+ for (TaskDefinition def : definitions()) {
+ TaskDefinition other = byClass.get(def.taskClass());
+ if (other == null) {
+ byClass.put(def.taskClass(), def);
+ } else {
+ throw new IllegalStateException("Task '" + def.taskClass().getName() + "' is defined twice: first by '" + other.key() + "' and then by '" + def.key() + "'");
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.task;
+
+import com.github.kevinsawicki.http.HttpRequest;
+import java.net.MalformedURLException;
+import java.net.URL;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.platform.Server;
+import org.sonar.api.task.Task;
+import org.sonar.api.task.TaskDefinition;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.batch.bootstrap.ServerClient;
+
+import static java.lang.String.format;
+
+public class ViewsTask implements Task {
+
+ private static final Logger LOG = Loggers.get(ViewsTask.class);
+
+ public static final String KEY = "views";
+
+ public static final TaskDefinition DEFINITION = TaskDefinition.builder()
+ .key(KEY)
+ .description("Trigger Views update")
+ .taskClass(ViewsTask.class)
+ .build();
+
+ private final ServerClient serverClient;
+ private final Server server;
+
+ public ViewsTask(ServerClient serverClient, Server server) {
+ this.serverClient = serverClient;
+ this.server = server;
+ }
+
+ @Override
+ public void execute() {
+ LOG.info("Trigger Views update");
+ URL url;
+ try {
+ url = new URL(serverClient.getURL() + "/api/views/run");
+ } catch (MalformedURLException e) {
+ throw new IllegalArgumentException("Invalid URL", e);
+ }
+ HttpRequest request = HttpRequest.post(url);
+ request.trustAllCerts();
+ request.trustAllHosts();
+ request.header("User-Agent", format("SonarQube %s", server.getVersion()));
+ request.basic(serverClient.getLogin(), serverClient.getPassword());
+ if (!request.ok()) {
+ int responseCode = request.code();
+ if (responseCode == 401) {
+ throw new IllegalStateException(format(serverClient.getMessageWhenNotAuthorized(), CoreProperties.LOGIN, CoreProperties.PASSWORD));
+ }
+ if (responseCode == 409) {
+ throw new IllegalStateException("A full refresh of Views is already queued or running");
+ }
+ if (responseCode == 403) {
+ // SONAR-4397 Details are in response content
+ throw new IllegalStateException(request.body());
+ }
+ throw new IllegalStateException(format("Fail to execute request [code=%s, url=%s]: %s", responseCode, url, request.body()));
+ }
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.batch.task;
+
+import javax.annotation.ParametersAreNonnullByDefault;
assertThat(filter.accept(MyProjectExtension.class)).isFalse();
assertThat(filter.accept(new MyServerExtension())).isFalse();
assertThat(filter.accept(MyServerExtension.class)).isFalse();
- assertThat(filter.accept(new MyTaskExtension())).isTrue();
- assertThat(filter.accept(MyTaskExtension.class)).isTrue();
+ assertThat(filter.accept(new MyTaskExtension())).isFalse();
+ assertThat(filter.accept(MyTaskExtension.class)).isFalse();
}
@InstantiationStrategy(InstantiationStrategy.PER_BATCH)
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.task;
+
+import java.util.Arrays;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.task.Task;
+import org.sonar.api.task.TaskDefinition;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ListTaskTest {
+
+ @Rule
+ public LogTester logTester = new LogTester();
+
+ @Test
+ public void should_list_available_tasks() {
+ Tasks tasks = mock(Tasks.class);
+ when(tasks.definitions()).thenReturn(Arrays.asList(
+ TaskDefinition.builder().key("foo").description("Foo").taskClass(FooTask.class).build(),
+ TaskDefinition.builder().key("purge").description("Purge database").taskClass(FakePurgeTask.class).build()));
+
+ ListTask task = new ListTask(tasks);
+
+ task.execute();
+
+ assertThat(logTester.logs(LoggerLevel.INFO)).hasSize(1);
+ assertThat(logTester.logs(LoggerLevel.INFO).get(0)).contains("Available tasks:", " - foo: Foo", " - purge: Purge database");
+ }
+
+ private static class FakePurgeTask implements Task {
+ public void execute() {
+ }
+ }
+
+ private static class FooTask implements Task {
+ public void execute() {
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.task;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.task.Task;
+import org.sonar.api.task.TaskDefinition;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class TasksTest {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void should_get_definitions() {
+ Tasks tasks = new Tasks(new TaskDefinition[] {ScanTask.DEFINITION, ListTask.DEFINITION});
+ assertThat(tasks.definitions()).hasSize(2);
+ }
+
+ @Test
+ public void should_get_definition_by_key() {
+ Tasks tasks = new Tasks(new TaskDefinition[] {ScanTask.DEFINITION, ListTask.DEFINITION});
+ tasks.start();
+ assertThat(tasks.definition(ListTask.DEFINITION.key())).isEqualTo(ListTask.DEFINITION);
+ }
+
+ @Test
+ public void should_return_null_if_task_not_found() {
+ Tasks tasks = new Tasks(new TaskDefinition[] {ScanTask.DEFINITION, ListTask.DEFINITION});
+
+ assertThat(tasks.definition("not-exists")).isNull();
+ }
+
+ @Test
+ public void should_fail_on_duplicated_keys() {
+ thrown.expect(IllegalStateException.class);
+ thrown.expectMessage("Task 'foo' is declared twice");
+
+ new Tasks(new TaskDefinition[] {
+ TaskDefinition.builder().key("foo").taskClass(FakeTask1.class).description("foo1").build(),
+ TaskDefinition.builder().key("foo").taskClass(FakeTask2.class).description("foo2").build()
+ });
+ }
+
+ @Test
+ public void should_fail_on_duplicated_class() {
+ Tasks tasks = new Tasks(new TaskDefinition[] {
+ TaskDefinition.builder().key("foo1").taskClass(FakeTask1.class).description("foo1").build(),
+ TaskDefinition.builder().key("foo2").taskClass(FakeTask1.class).description("foo1").build()
+ });
+
+ thrown.expect(IllegalStateException.class);
+ thrown.expectMessage("Task 'org.sonar.batch.task.TasksTest$FakeTask1' is defined twice: first by 'foo1' and then by 'foo2'");
+
+ tasks.start();
+ }
+
+ private static class FakeTask1 implements Task {
+ public void execute() {
+ }
+ }
+
+ private static class FakeTask2 implements Task {
+ public void execute() {
+ }
+
+ }
+
+}
/**
* @since 3.5
- * @deprecated since 5.2 no more task concept on batch side
*/
- @Deprecated
String TASK = "sonar.task";
/**
* @since 3.6
- * @deprecated since 5.2 no more task concept on batch side
*/
- @Deprecated
String SCAN_TASK = "scan";
/**
public @interface InstantiationStrategy {
/**
- * Shared extension. Lifecycle is the full analysis.
+ * Shared task extension. Available in task container.
+ */
+ String PER_TASK = "PER_TASK";
+
+ /**
+ * Shared extension. Available in top level project container.
*/
String PER_BATCH = "PER_BATCH";
*/
package org.sonar.api.task;
+import org.sonar.api.batch.BatchSide;
+import org.sonar.api.batch.InstantiationStrategy;
+
/**
* Implement this interface to provide the behavior of a task.
* @since 3.6
- * @deprecated since 5.1 all tasks (devcockpit, views) will be moved to server side
*/
-@Deprecated
-public interface Task extends TaskExtension {
+@BatchSide
+@InstantiationStrategy(InstantiationStrategy.PER_TASK)
+public interface Task {
void execute();
* All the classes implementing this interface can be injected in public constructors of {@link TaskExtension}.
*
* @since 3.6
- * @deprecated since 5.1 all tasks (devcockpit, views) will be moved to server side
+ * @deprecated since 5.1. Use {@link BatchSide} and {@link InstantiationStrategy#PER_TASK}
*/
@Deprecated
@BatchSide
-@InstantiationStrategy(InstantiationStrategy.PER_BATCH)
+@InstantiationStrategy(InstantiationStrategy.PER_TASK)
public interface TaskComponent {
}
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
-
import java.util.regex.Pattern;
+import org.sonar.api.ExtensionPoint;
+import org.sonar.api.batch.BatchSide;
+import org.sonar.api.batch.InstantiationStrategy;
/**
* Register and describe a {@link TaskExtension}.
*
* @since 3.6
- * @deprecated since 5.1 all tasks (devcockpit, views) will be moved to server side
*/
-@Deprecated
-public class TaskDefinition implements TaskExtension, Comparable<TaskDefinition> {
+@ExtensionPoint
+@BatchSide
+@InstantiationStrategy(InstantiationStrategy.PER_TASK)
+public class TaskDefinition implements Comparable<TaskDefinition> {
static final String KEY_PATTERN = "[a-zA-Z0-9\\-\\_]+";
private final String key;
*/
package org.sonar.api.task;
-import org.sonar.api.Extension;
+import org.sonar.api.batch.BatchSide;
+import org.sonar.api.batch.InstantiationStrategy;
/**
* Task extension point
*
* @since 3.6
- * @deprecated since 5.1 all tasks (devcockpit, views) will be moved to server side
+ * @deprecated since 5.1. Not used.
*/
@Deprecated
-public interface TaskExtension extends Extension, TaskComponent {
+@BatchSide
+@InstantiationStrategy(InstantiationStrategy.PER_TASK)
+public interface TaskExtension {
}