plugins/task: Move TaskExpression iteration to Preloader
Having this iteration inside TaskConfig class prevents us from
referencing tasks from other files from a TaskExpression in
future. Ideally, TaskConfig shouldn't know about the Preloader
and this change removes cyclic dependency between them.
Change-Id: I34e710b2df2567217653ac545cdc26f21105aa10
diff --git a/BUILD b/BUILD
index 108dae2..dbe73f9 100644
--- a/BUILD
+++ b/BUILD
@@ -1,6 +1,7 @@
load(
"//tools/bzl:plugin.bzl",
"PLUGIN_DEPS",
+ "PLUGIN_TEST_DEPS",
"gerrit_plugin",
)
load("//tools/bzl:genrule2.bzl", "genrule2")
@@ -70,7 +71,7 @@
name = "junit-tests",
size = "small",
srcs = glob(["src/test/java/**/*Test.java"]),
- deps = [plugin_name],
+ deps = PLUGIN_TEST_DEPS + [plugin_name],
)
sh_test(
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/Preloader.java b/src/main/java/com/googlesource/gerrit/plugins/task/Preloader.java
index 63fb0db..c48ed6e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/Preloader.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/Preloader.java
@@ -20,36 +20,62 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.NoSuchElementException;
import java.util.Optional;
import org.eclipse.jgit.errors.ConfigInvalidException;
/** Use to pre-load a task definition with values from its preload-task definition. */
public class Preloader {
- protected final TaskConfig config;
- protected final Map<String, Optional<Task>> optionalTaskByExpression = new HashMap<>();
+ protected final Map<TaskExpressionKey, Optional<Task>> optionalTaskByExpression = new HashMap<>();
- public Preloader(TaskConfig config) {
- this.config = config;
+ public List<Task> getRootTasks(TaskConfig cfg) {
+ return getTasks(cfg, TaskConfig.SECTION_ROOT);
}
- public Optional<Task> preloadOptional(TaskExpression expression) throws ConfigInvalidException {
- Optional<Task> task = optionalTaskByExpression.get(expression.getKey());
+ public List<Task> getTasks(TaskConfig cfg) {
+ return getTasks(cfg, TaskConfig.SECTION_TASK);
+ }
+
+ protected List<Task> getTasks(TaskConfig cfg, String type) {
+ List<Task> preloaded = new ArrayList<>();
+ for (Task task : cfg.getTasks(type)) {
+ try {
+ preloaded.add(preload(task));
+ } catch (ConfigInvalidException e) {
+ preloaded.add(null);
+ }
+ }
+ return preloaded;
+ }
+
+ /**
+ * Get a preloaded Task for this TaskExpression.
+ *
+ * @param expression
+ * @return Optional<Task> which is empty if the expression is optional and no tasks are resolved
+ * @throws ConfigInvalidException if the expression requires a task and no tasks are resolved
+ */
+ public Optional<Task> getOptionalTask(TaskConfig cfg, TaskExpression expression)
+ throws ConfigInvalidException {
+ Optional<Task> task = optionalTaskByExpression.get(expression.key);
if (task == null) {
- task = loadOptional(expression);
- optionalTaskByExpression.put(expression.getKey(), task);
+ task = preloadOptionalTask(cfg, expression);
+ optionalTaskByExpression.put(expression.key, task);
}
return task;
}
- protected Optional<Task> loadOptional(TaskExpression expression) throws ConfigInvalidException {
- Optional<Task> definition = config.getOptionalTask(expression);
+ protected Optional<Task> preloadOptionalTask(TaskConfig cfg, TaskExpression expression)
+ throws ConfigInvalidException {
+ Optional<Task> definition = loadOptionalTask(cfg, expression);
return definition.isPresent() ? Optional.of(preload(definition.get())) : definition;
}
public Task preload(Task definition) throws ConfigInvalidException {
String expression = definition.preloadTask;
if (expression != null) {
- Optional<Task> preloadFrom = preloadOptional(new TaskExpression(expression));
+ Optional<Task> preloadFrom =
+ getOptionalTask(definition.config, new TaskExpression(definition.file(), expression));
if (preloadFrom.isPresent()) {
return preloadFrom(definition, preloadFrom.get());
}
@@ -57,6 +83,22 @@
return definition;
}
+ protected Optional<Task> loadOptionalTask(TaskConfig cfg, TaskExpression expression)
+ throws ConfigInvalidException {
+ try {
+ for (String name : expression) {
+ Optional<Task> task = cfg.getOptionalTask(name);
+ if (task.isPresent()) {
+ return task;
+ }
+ }
+ } catch (NoSuchElementException e) {
+ // expression was not optional but we ran out of names to try
+ throw new ConfigInvalidException("task not defined");
+ }
+ return Optional.empty();
+ }
+
protected static Task preloadFrom(Task definition, Task preloadFrom) {
Task preloadTo = definition.config.new Task(definition.subSection);
for (Field field : definition.getClass().getFields()) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/TaskConfig.java b/src/main/java/com/googlesource/gerrit/plugins/task/TaskConfig.java
index 8b172d7..698b33a 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/TaskConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/TaskConfig.java
@@ -26,10 +26,8 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.Set;
-import org.eclipse.jgit.errors.ConfigInvalidException;
/** Task Configuration file living in git */
public class TaskConfig extends AbstractVersionedMetaData {
@@ -138,6 +136,10 @@
return key.task();
}
+ public FileKey file() {
+ return key.subSection().file();
+ }
+
public TaskKey key() {
return key;
}
@@ -214,8 +216,6 @@
public boolean isVisible;
public boolean isTrusted;
- protected final Preloader preloader;
-
public TaskConfig(FileKey file, boolean isVisible, boolean isTrusted) {
this(file.branch(), file, isVisible, isTrusted);
}
@@ -226,27 +226,6 @@
this.file = file;
this.isVisible = isVisible;
this.isTrusted = isTrusted;
- preloader = new Preloader(this);
- }
-
- public List<Task> getPreloadedRootTasks() {
- return getPreloadedTasks(SECTION_ROOT);
- }
-
- public List<Task> getPreloadedTasks() {
- return getPreloadedTasks(SECTION_TASK);
- }
-
- protected List<Task> getPreloadedTasks(String type) {
- List<Task> preloaded = new ArrayList<>();
- for (Task task : getTasks(type)) {
- try {
- preloaded.add(preloader.preload(task));
- } catch (ConfigInvalidException e) {
- preloaded.add(null);
- }
- }
- return preloaded;
}
protected List<Task> getTasks(String type) {
@@ -267,34 +246,6 @@
return externals;
}
- /**
- * Get a preloaded Task for this TaskExpression.
- *
- * @param TaskExpression
- * @return Optional<Task> which is empty if the expression is optional and no tasks are resolved
- * @throws ConfigInvalidException if the expression requires a task and no tasks are resolved
- */
- public Optional<Task> getPreloadedOptionalTask(TaskExpression expression)
- throws ConfigInvalidException {
- return preloader.preloadOptional(expression);
- }
-
- protected Optional<Task> getOptionalTask(TaskExpression expression)
- throws ConfigInvalidException {
- try {
- for (String name : expression) {
- Optional<Task> task = getOptionalTask(name);
- if (task.isPresent()) {
- return task;
- }
- }
- } catch (NoSuchElementException e) {
- // expression was not optional but we ran out of names to try
- throw new ConfigInvalidException("task not defined");
- }
- return Optional.empty();
- }
-
protected Optional<Task> getOptionalTask(String name) {
SubSectionKey subSection = subSectionKey(SECTION_TASK, name);
return getNames(subSection).isEmpty()
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/TaskExpression.java b/src/main/java/com/googlesource/gerrit/plugins/task/TaskExpression.java
index 036071b..90dffff 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/TaskExpression.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/TaskExpression.java
@@ -37,21 +37,16 @@
*/
public class TaskExpression implements Iterable<String> {
protected static final Pattern EXPRESSION_PATTERN = Pattern.compile("([^ |]+[^|]*)(\\|)?");
+ protected final TaskExpressionKey key;
- protected final String expression;
-
- public TaskExpression(String expression) {
- this.expression = expression;
- }
-
- public String getKey() {
- return expression;
+ public TaskExpression(FileKey key, String expression) {
+ this.key = TaskExpressionKey.create(key, expression);
}
@Override
public Iterator<String> iterator() {
return new Iterator<String>() {
- Matcher m = EXPRESSION_PATTERN.matcher(expression);
+ Matcher m = EXPRESSION_PATTERN.matcher(key.expression());
Boolean hasNext;
boolean optional;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/TaskExpressionKey.java b/src/main/java/com/googlesource/gerrit/plugins/task/TaskExpressionKey.java
new file mode 100644
index 0000000..69afd26
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/TaskExpressionKey.java
@@ -0,0 +1,15 @@
+package com.googlesource.gerrit.plugins.task;
+
+import com.google.auto.value.AutoValue;
+
+/** A key for TaskExpression. */
+@AutoValue
+public abstract class TaskExpressionKey {
+ public static TaskExpressionKey create(FileKey file, String expression) {
+ return new AutoValue_TaskExpressionKey(file, expression);
+ }
+
+ public abstract FileKey file();
+
+ public abstract String expression();
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/TaskTree.java b/src/main/java/com/googlesource/gerrit/plugins/task/TaskTree.java
index 93565f6..cb92805 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/TaskTree.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/TaskTree.java
@@ -70,6 +70,7 @@
protected final AllUsersNameProvider allUsers;
protected final CurrentUser user;
protected final TaskConfigFactory taskFactory;
+ protected final Preloader preloader;
protected final NodeList root = new NodeList();
protected final Provider<ChangeQueryBuilder> changeQueryBuilderProvider;
protected final Provider<ChangeQueryProcessor> changeQueryProcessorProvider;
@@ -84,13 +85,15 @@
CurrentUser user,
TaskConfigFactory taskFactory,
Provider<ChangeQueryBuilder> changeQueryBuilderProvider,
- Provider<ChangeQueryProcessor> changeQueryProcessorProvider) {
+ Provider<ChangeQueryProcessor> changeQueryProcessorProvider,
+ Preloader preloader) {
this.accountResolver = accountResolver;
this.allUsers = allUsers;
this.user = user != null ? user : anonymousUser;
this.taskFactory = taskFactory;
this.changeQueryProcessorProvider = changeQueryProcessorProvider;
this.changeQueryBuilderProvider = changeQueryBuilderProvider;
+ this.preloader = preloader;
}
public void masquerade(PatchSetArgument psa) {
@@ -112,7 +115,7 @@
protected Set<String> names = new HashSet<>();
protected void addSubNodes() throws ConfigInvalidException, IOException, OrmException {
- addPreloaded(taskFactory.getRootConfig().getPreloadedRootTasks());
+ addPreloaded(preloader.getRootTasks(taskFactory.getRootConfig()));
}
protected void addPreloaded(List<Task> defs) throws ConfigInvalidException, OrmException {
@@ -228,7 +231,8 @@
protected void addSubTasks() throws ConfigInvalidException, OrmException {
for (String expression : task.subTasks) {
try {
- Optional<Task> def = task.config.getPreloadedOptionalTask(new TaskExpression(expression));
+ Optional<Task> def =
+ preloader.getOptionalTask(task.config, new TaskExpression(task.file(), expression));
if (def.isPresent()) {
addPreloaded(def.get());
}
@@ -288,7 +292,7 @@
protected void addStaticTypeTasks(TasksFactory tasksFactory, NamesFactory namesFactory)
throws ConfigInvalidException, OrmException {
for (String name : namesFactory.names) {
- addPreloaded(preload(task.config.new Task(tasksFactory, name)));
+ addPreloaded(preloader.preload(task.config.new Task(tasksFactory, name)));
}
}
@@ -303,7 +307,8 @@
.entities();
for (ChangeData changeData : changeDataList) {
addPreloaded(
- preload(task.config.new Task(tasksFactory, changeData.getId().toString())),
+ preloader.preload(
+ task.config.new Task(tasksFactory, changeData.getId().toString())),
(parent, definition) ->
new Node(parent, definition) {
@Override
@@ -329,7 +334,7 @@
protected List<Task> getPreloadedTasks(FileKey file)
throws ConfigInvalidException, IOException {
- return taskFactory.getTaskConfig(file, task.isTrusted).getPreloadedTasks();
+ return preloader.getTasks(taskFactory.getTaskConfig(file, task.isTrusted));
}
@Override
@@ -360,8 +365,4 @@
}
return new Branch.NameKey(allUsers.get(), RefNames.refsUsers(acct.getId()));
}
-
- protected static Task preload(Task task) throws ConfigInvalidException {
- return task.config.preloader.preload(task);
- }
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/task/TaskExpressionTest.java b/src/test/java/com/googlesource/gerrit/plugins/task/TaskExpressionTest.java
index 13e471f..ac4ee88 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/task/TaskExpressionTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/task/TaskExpressionTest.java
@@ -14,6 +14,8 @@
package com.googlesource.gerrit.plugins.task;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Project;
import java.util.Iterator;
import java.util.NoSuchElementException;
import junit.framework.TestCase;
@@ -30,16 +32,17 @@
public static String SIMPLE = "simple";
public static String WORLD = "world";
public static String PEACE = "peace";
+ public static FileKey file = createFileKey("foo", "bar", "baz");
public void testBlank() {
- TaskExpression exp = new TaskExpression("");
+ TaskExpression exp = getTaskExpression("");
Iterator<String> it = exp.iterator();
assertTrue(it.hasNext());
assertNoSuchElementException(it);
}
public void testRequiredSingleName() {
- TaskExpression exp = new TaskExpression(SIMPLE);
+ TaskExpression exp = getTaskExpression(SIMPLE);
Iterator<String> it = exp.iterator();
assertTrue(it.hasNext());
assertEquals(it.next(), SIMPLE);
@@ -48,7 +51,7 @@
}
public void testOptionalSingleName() {
- TaskExpression exp = new TaskExpression(SIMPLE + "|");
+ TaskExpression exp = getTaskExpression(SIMPLE + "|");
Iterator<String> it = exp.iterator();
assertTrue(it.hasNext());
assertEquals(it.next(), SIMPLE);
@@ -56,7 +59,7 @@
}
public void testRequiredTwoNames() {
- TaskExpression exp = new TaskExpression(WORLD + "|" + PEACE);
+ TaskExpression exp = getTaskExpression(WORLD + "|" + PEACE);
Iterator<String> it = exp.iterator();
assertTrue(it.hasNext());
assertEquals(it.next(), WORLD);
@@ -67,7 +70,7 @@
}
public void testOptionalTwoNames() {
- TaskExpression exp = new TaskExpression(WORLD + "|" + PEACE + "|");
+ TaskExpression exp = getTaskExpression(WORLD + "|" + PEACE + "|");
Iterator<String> it = exp.iterator();
assertTrue(it.hasNext());
assertEquals(it.next(), WORLD);
@@ -77,14 +80,14 @@
}
public void testBlankSpaces() {
- TaskExpression exp = new TaskExpression(" ");
+ TaskExpression exp = getTaskExpression(" ");
Iterator<String> it = exp.iterator();
assertTrue(it.hasNext());
assertNoSuchElementException(it);
}
public void testRequiredSingleNameLeadingSpaces() {
- TaskExpression exp = new TaskExpression(" " + SIMPLE);
+ TaskExpression exp = getTaskExpression(" " + SIMPLE);
Iterator<String> it = exp.iterator();
assertTrue(it.hasNext());
assertEquals(it.next(), SIMPLE);
@@ -93,7 +96,7 @@
}
public void testRequiredSingleNameTrailingSpaces() {
- TaskExpression exp = new TaskExpression(SIMPLE + " ");
+ TaskExpression exp = getTaskExpression(SIMPLE + " ");
Iterator<String> it = exp.iterator();
assertTrue(it.hasNext());
assertEquals(it.next(), SIMPLE);
@@ -102,7 +105,7 @@
}
public void testOptionalSingleNameLeadingSpaces() {
- TaskExpression exp = new TaskExpression(" " + SIMPLE + "|");
+ TaskExpression exp = getTaskExpression(" " + SIMPLE + "|");
Iterator<String> it = exp.iterator();
assertTrue(it.hasNext());
assertEquals(it.next(), SIMPLE);
@@ -110,7 +113,7 @@
}
public void testOptionalSingleNameTrailingSpaces() {
- TaskExpression exp = new TaskExpression(SIMPLE + "| ");
+ TaskExpression exp = getTaskExpression(SIMPLE + "| ");
Iterator<String> it = exp.iterator();
assertTrue(it.hasNext());
assertEquals(it.next(), SIMPLE);
@@ -118,7 +121,7 @@
}
public void testOptionalSingleNameMiddleSpaces() {
- TaskExpression exp = new TaskExpression(SIMPLE + " |");
+ TaskExpression exp = getTaskExpression(SIMPLE + " |");
Iterator<String> it = exp.iterator();
assertTrue(it.hasNext());
assertEquals(it.next(), SIMPLE);
@@ -126,7 +129,7 @@
}
public void testRequiredTwoNamesMiddleSpaces() {
- TaskExpression exp = new TaskExpression(WORLD + " | " + PEACE);
+ TaskExpression exp = getTaskExpression(WORLD + " | " + PEACE);
Iterator<String> it = exp.iterator();
assertTrue(it.hasNext());
assertEquals(it.next(), WORLD);
@@ -136,6 +139,30 @@
assertNoSuchElementException(it);
}
+ public void testDifferentKeyOnDifferentFile() {
+ TaskExpression exp = getTaskExpression(createFileKey("foo", "bar", "baz"), SIMPLE);
+ TaskExpression otherExp = getTaskExpression(createFileKey("foo", "bar", "other"), SIMPLE);
+ assertFalse(exp.key.equals(otherExp.key));
+ }
+
+ public void testDifferentKeyOnDifferentBranch() {
+ TaskExpression exp = getTaskExpression(createFileKey("foo", "bar", "baz"), SIMPLE);
+ TaskExpression otherExp = getTaskExpression(createFileKey("foo", "other", "baz"), SIMPLE);
+ assertFalse(exp.key.equals(otherExp.key));
+ }
+
+ public void testDifferentKeyOnDifferentProject() {
+ TaskExpression exp = getTaskExpression(createFileKey("foo", "bar", "baz"), SIMPLE);
+ TaskExpression otherExp = getTaskExpression(createFileKey("other", "bar", "baz"), SIMPLE);
+ assertFalse(exp.key.equals(otherExp.key));
+ }
+
+ public void testDifferentKeyOnDifferentExpression() {
+ TaskExpression exp = getTaskExpression(SIMPLE);
+ TaskExpression otherExp = getTaskExpression(PEACE);
+ assertFalse(exp.key.equals(otherExp.key));
+ }
+
protected static void assertNoSuchElementException(Iterator<String> it) {
try {
it.next();
@@ -144,4 +171,16 @@
assertTrue(true);
}
}
+
+ protected TaskExpression getTaskExpression(String expression) {
+ return getTaskExpression(file, expression);
+ }
+
+ protected TaskExpression getTaskExpression(FileKey file, String expression) {
+ return new TaskExpression(file, expression);
+ }
+
+ protected static FileKey createFileKey(String project, String branch, String file) {
+ return FileKey.create(new Branch.NameKey(new Project.NameKey(project), branch), file);
+ }
}
diff --git a/tools/bzl/plugin.bzl b/tools/bzl/plugin.bzl
index 89a1643..67536ef 100644
--- a/tools/bzl/plugin.bzl
+++ b/tools/bzl/plugin.bzl
@@ -2,7 +2,9 @@
"@com_googlesource_gerrit_bazlets//:gerrit_plugin.bzl",
_gerrit_plugin = "gerrit_plugin",
_plugin_deps = "PLUGIN_DEPS",
+ _plugin_test_deps = "PLUGIN_TEST_DEPS",
)
gerrit_plugin = _gerrit_plugin
PLUGIN_DEPS = _plugin_deps
+PLUGIN_TEST_DEPS = _plugin_test_deps
\ No newline at end of file