Merge "Update padding of file action buttons"
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 45bc045..91a837d 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -1133,6 +1133,18 @@
+
Default is true.
+[[change.api.allowedIdentifier]]change.api.allowedIdentifier::
++
+Change identifier(s) that are allowed on the API. See
+link:rest-api-changes.html#change-id[Change Id] for more information.
++
+Possible values are `ALL`, `TRIPLET`, `NUMERIC_ID`, `I_HASH`, and
+`COMMIT_HASH` or any combination of those as a string list.
+`PROJECT_NUMERIC_ID` is always allowed and doesn't need to be listed
+explicitly.
++
+Default is `ALL`.
+
[[change.cacheAutomerge]]change.cacheAutomerge::
+
When reviewing diff commits, the left-hand side shows the output of the
diff --git a/Documentation/pg-plugin-dev.txt b/Documentation/pg-plugin-dev.txt
index dbcbe49..a3f1e55 100644
--- a/Documentation/pg-plugin-dev.txt
+++ b/Documentation/pg-plugin-dev.txt
@@ -161,11 +161,14 @@
`plugin.hook(endpointName, opt_options)`
See list of supported link:pg-plugin-endpoints.html[endpoints].
+
Note: TODO
=== registerCustomComponent
`plugin.registerCustomComponent(endpointName, opt_moduleName, opt_options)`
+See list of supported link:pg-plugin-endpoints.html[endpoints].
+
Note: TODO
=== registerStyleModule
@@ -239,6 +242,28 @@
Note: TODO
+=== screen
+`plugin.screen(screenName, opt_moduleName)`
+
+.Params:
+- `*string* screenName` URL path fragment of the screen, e.g.
+`/x/pluginname/*screenname*`
+- `*string* opt_moduleName` (Optional) Web component to be instantiated for this
+screen.
+
+.Returns:
+- Instance of GrDomHook.
+
+=== screenUrl
+`plugin.url(opt_screenName)`
+
+.Params:
+- `*string* screenName` (optional) URL path fragment of the screen, e.g.
+`/x/pluginname/*screenname*`
+
+.Returns:
+- Absolute URL for the screen, e.g. `http://localhost/base/x/pluginname/screenname`
+
=== theme
`plugin.theme()`
diff --git a/Documentation/pg-plugin-project-api.txt b/Documentation/pg-plugin-project-api.txt
index 897430c..df0a6f4 100644
--- a/Documentation/pg-plugin-project-api.txt
+++ b/Documentation/pg-plugin-project-api.txt
@@ -13,7 +13,7 @@
- *checkVisibleCallback* function to configure command visibility.
.Returns
-- GrProjectApi for chainging.
+- GrProjectApi for chaining.
`checkVisibleCallback(projectName, projectConfig)`
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index 1cfd3e1..1606b8a 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -5384,11 +5384,12 @@
[[change-id]]
=== \{change-id\}
-Identifier that uniquely identifies one change.
+Identifier that uniquely identifies one change. It contains the URL-encoded
+project name as well as the change number: "'$$<project>~<numericId>$$'"
-This can be:
+Depending on the server's configuration, Gerrit can still support the following
+deprecated identifiers. These will be removed in a future release:
-* an ID of the change in the format "'$$<project>~<numericId>$$'"
* an ID of the change in the format "'$$<project>~<branch>~<Change-Id>$$'",
where for the branch the `refs/heads/` prefix can be omitted
("$$myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940$$")
@@ -5396,6 +5397,10 @@
("I8473b95934b5732ac55d26311a706c9c2bde9940")
* a numeric change ID ("4247")
+If you need more time to migrate off of old change IDs, please see
+link:config-gerrit.html#change.api.allowedIdentifier[change.api.allowedIdentifier]
+for more information on how to enable the use of deprecated identifiers.
+
[[comment-id]]
=== \{comment-id\}
UUID of a published comment.
diff --git a/contrib/abandon_stale.py b/contrib/abandon_stale.py
index cb1cc23..8d1c326 100755
--- a/contrib/abandon_stale.py
+++ b/contrib/abandon_stale.py
@@ -186,15 +186,21 @@
abandon_message += "\n\n" + options.message
for change in stale_changes:
number = change["_number"]
- try:
- owner = change["owner"]["name"]
- except:
- owner = "Unknown"
+ project = ""
+ if len(options.projects) != 1:
+ project = "%s: " % change["project"]
+ owner = ""
+ if options.verbose:
+ try:
+ o = change["owner"]["name"]
+ except KeyError:
+ o = "Unknown"
+ owner = " (%s)" % o
subject = change["subject"]
if len(subject) > 70:
subject = subject[:65] + " [...]"
change_id = change["id"]
- logging.info("%s (%s): %s", number, owner, subject)
+ logging.info("%s%s: %s%s", number, owner, project, subject)
if options.dry_run:
continue
diff --git a/java/com/google/gerrit/extensions/restapi/DeprecatedIdentifierException.java b/java/com/google/gerrit/extensions/restapi/DeprecatedIdentifierException.java
new file mode 100644
index 0000000..aa28cfc
--- /dev/null
+++ b/java/com/google/gerrit/extensions/restapi/DeprecatedIdentifierException.java
@@ -0,0 +1,25 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// 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 com.google.gerrit.extensions.restapi;
+
+/** Named resource was accessed using a deprecated identifier. */
+public class DeprecatedIdentifierException extends BadRequestException {
+ private static final long serialVersionUID = 1L;
+
+ /** Requested resource using a deprecated identifier. */
+ public DeprecatedIdentifierException(String msg) {
+ super(msg);
+ }
+}
diff --git a/java/com/google/gerrit/httpd/BUILD b/java/com/google/gerrit/httpd/BUILD
index 65943fc..d7cbdb8 100644
--- a/java/com/google/gerrit/httpd/BUILD
+++ b/java/com/google/gerrit/httpd/BUILD
@@ -15,6 +15,7 @@
"//java/com/google/gerrit/server",
"//java/com/google/gerrit/server/git/receive",
"//java/com/google/gerrit/server/ioutil",
+ "//java/com/google/gerrit/server/restapi",
"//java/com/google/gerrit/util/cli",
"//java/com/google/gerrit/util/http",
"//java/com/google/gwtexpui/linker:server",
diff --git a/java/com/google/gerrit/httpd/init/BUILD b/java/com/google/gerrit/httpd/init/BUILD
index 936044d..9624241 100644
--- a/java/com/google/gerrit/httpd/init/BUILD
+++ b/java/com/google/gerrit/httpd/init/BUILD
@@ -20,6 +20,7 @@
"//java/com/google/gerrit/server/api",
"//java/com/google/gerrit/server/cache/h2",
"//java/com/google/gerrit/server/git/receive",
+ "//java/com/google/gerrit/server/restapi",
"//java/com/google/gerrit/server/schema",
"//java/com/google/gerrit/sshd",
"//lib:guava",
diff --git a/java/com/google/gerrit/httpd/init/WebAppInitializer.java b/java/com/google/gerrit/httpd/init/WebAppInitializer.java
index b5995a8..5b9cf3b 100644
--- a/java/com/google/gerrit/httpd/init/WebAppInitializer.java
+++ b/java/com/google/gerrit/httpd/init/WebAppInitializer.java
@@ -55,7 +55,6 @@
import com.google.gerrit.server.config.GerritOptions;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.GerritServerConfigModule;
-import com.google.gerrit.server.config.RestCacheAdminModule;
import com.google.gerrit.server.config.SitePath;
import com.google.gerrit.server.events.EventBroker;
import com.google.gerrit.server.events.StreamEventsApiListener;
@@ -79,6 +78,7 @@
import com.google.gerrit.server.plugins.PluginRestApiModule;
import com.google.gerrit.server.project.DefaultPermissionBackendModule;
import com.google.gerrit.server.project.DefaultProjectNameLockManager;
+import com.google.gerrit.server.restapi.config.RestCacheAdminModule;
import com.google.gerrit.server.schema.DataSourceModule;
import com.google.gerrit.server.schema.DataSourceProvider;
import com.google.gerrit.server.schema.DataSourceType;
diff --git a/java/com/google/gerrit/httpd/restapi/ConfigRestApiServlet.java b/java/com/google/gerrit/httpd/restapi/ConfigRestApiServlet.java
index 87df4cf..4d56036 100644
--- a/java/com/google/gerrit/httpd/restapi/ConfigRestApiServlet.java
+++ b/java/com/google/gerrit/httpd/restapi/ConfigRestApiServlet.java
@@ -14,7 +14,7 @@
package com.google.gerrit.httpd.restapi;
-import com.google.gerrit.server.config.ConfigCollection;
+import com.google.gerrit.server.restapi.config.ConfigCollection;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
diff --git a/java/com/google/gerrit/pgm/BUILD b/java/com/google/gerrit/pgm/BUILD
index 3dce217..a255020 100644
--- a/java/com/google/gerrit/pgm/BUILD
+++ b/java/com/google/gerrit/pgm/BUILD
@@ -38,6 +38,7 @@
"//java/com/google/gerrit/server/api",
"//java/com/google/gerrit/server/cache/h2",
"//java/com/google/gerrit/server/git/receive",
+ "//java/com/google/gerrit/server/restapi",
"//java/com/google/gerrit/server/schema",
"//java/com/google/gerrit/sshd",
"//java/com/google/gwtexpui/linker:server",
diff --git a/java/com/google/gerrit/pgm/Daemon.java b/java/com/google/gerrit/pgm/Daemon.java
index 16d81b7..4bc06d0 100644
--- a/java/com/google/gerrit/pgm/Daemon.java
+++ b/java/com/google/gerrit/pgm/Daemon.java
@@ -64,7 +64,6 @@
import com.google.gerrit.server.config.GerritGlobalModule;
import com.google.gerrit.server.config.GerritOptions;
import com.google.gerrit.server.config.GerritServerConfig;
-import com.google.gerrit.server.config.RestCacheAdminModule;
import com.google.gerrit.server.events.EventBroker;
import com.google.gerrit.server.events.StreamEventsApiListener;
import com.google.gerrit.server.git.GarbageCollectionModule;
@@ -88,6 +87,7 @@
import com.google.gerrit.server.plugins.PluginRestApiModule;
import com.google.gerrit.server.project.DefaultPermissionBackendModule;
import com.google.gerrit.server.project.DefaultProjectNameLockManager;
+import com.google.gerrit.server.restapi.config.RestCacheAdminModule;
import com.google.gerrit.server.schema.DataSourceProvider;
import com.google.gerrit.server.schema.InMemoryAccountPatchReviewStore;
import com.google.gerrit.server.schema.JdbcAccountPatchReviewStore;
diff --git a/java/com/google/gerrit/reviewdb/client/Project.java b/java/com/google/gerrit/reviewdb/client/Project.java
index d656b68..c66b646 100644
--- a/java/com/google/gerrit/reviewdb/client/Project.java
+++ b/java/com/google/gerrit/reviewdb/client/Project.java
@@ -200,7 +200,8 @@
* Returns the name key of the parent project.
*
* @param allProjectsName name key of the wild project
- * @return name key of the parent project, {@code null} if this project is the wild project
+ * @return name key of the parent project, {@code null} if this project is the All-Projects
+ * project
*/
public Project.NameKey getParent(Project.NameKey allProjectsName) {
if (parent != null) {
diff --git a/java/com/google/gerrit/server/BUILD b/java/com/google/gerrit/server/BUILD
index 6052a63..fb1fc28 100644
--- a/java/com/google/gerrit/server/BUILD
+++ b/java/com/google/gerrit/server/BUILD
@@ -100,6 +100,7 @@
":server",
"//java/com/google/gerrit/extensions:api",
"//java/com/google/gerrit/server/git/receive",
+ "//java/com/google/gerrit/server/restapi",
"//lib:blame-cache",
"//lib:guava",
"//lib:soy",
diff --git a/java/com/google/gerrit/server/ChangeFinder.java b/java/com/google/gerrit/server/ChangeFinder.java
index 4b7cbac..cb82778 100644
--- a/java/com/google/gerrit/server/ChangeFinder.java
+++ b/java/com/google/gerrit/server/ChangeFinder.java
@@ -17,8 +17,10 @@
import com.google.common.base.Throwables;
import com.google.common.cache.Cache;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.common.primitives.Ints;
+import com.google.gerrit.extensions.restapi.DeprecatedIdentifierException;
import com.google.gerrit.index.IndexConfig;
import com.google.gerrit.metrics.Counter1;
import com.google.gerrit.metrics.Description;
@@ -30,6 +32,8 @@
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.cache.CacheModule;
import com.google.gerrit.server.change.ChangeTriplet;
+import com.google.gerrit.server.config.ConfigUtil;
+import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.query.change.ChangeData;
@@ -46,6 +50,7 @@
import java.util.Optional;
import java.util.Set;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
+import org.eclipse.jgit.lib.Config;
@Singleton
public class ChangeFinder {
@@ -60,10 +65,11 @@
};
}
- private enum ChangeIdType {
+ public enum ChangeIdType {
+ ALL,
TRIPLET,
NUMERIC_ID,
- CHANGE_ID,
+ I_HASH,
PROJECT_NUMERIC_ID,
COMMIT_HASH
}
@@ -74,6 +80,7 @@
private final Provider<ReviewDb> reviewDb;
private final ChangeNotes.Factory changeNotesFactory;
private final Counter1<ChangeIdType> changeIdCounter;
+ private final ImmutableSet<ChangeIdType> allowedIdTypes;
@Inject
ChangeFinder(
@@ -82,7 +89,8 @@
Provider<InternalChangeQuery> queryProvider,
Provider<ReviewDb> reviewDb,
ChangeNotes.Factory changeNotesFactory,
- MetricMaker metricMaker) {
+ MetricMaker metricMaker,
+ @GerritServerConfig Config config) {
this.indexConfig = indexConfig;
this.changeIdProjectCache = changeIdProjectCache;
this.queryProvider = queryProvider;
@@ -95,16 +103,41 @@
.setRate()
.setUnit("requests"),
Field.ofEnum(ChangeIdType.class, "change_id_type"));
+ List<ChangeIdType> configuredChangeIdTypes =
+ ConfigUtil.getEnumList(config, "change", "api", "allowedIdentifier", ChangeIdType.ALL);
+ // Ensure that PROJECT_NUMERIC_ID can't be removed
+ configuredChangeIdTypes.add(ChangeIdType.PROJECT_NUMERIC_ID);
+ this.allowedIdTypes = ImmutableSet.copyOf(configuredChangeIdTypes);
}
/**
* Find changes matching the given identifier.
*
- * @param id change identifier, either a numeric ID, a Change-Id, or project~branch~id triplet.
+ * @param id change identifier.
* @return possibly-empty list of notes for all matching changes; may or may not be visible.
* @throws OrmException if an error occurred querying the database.
*/
public List<ChangeNotes> find(String id) throws OrmException {
+ try {
+ return find(id, false);
+ } catch (DeprecatedIdentifierException e) {
+ // This can't happen because we don't enforce deprecation
+ throw new OrmException(e);
+ }
+ }
+
+ /**
+ * Find changes matching the given identifier.
+ *
+ * @param id change identifier.
+ * @param enforceDeprecation boolean to see if we should throw {@link
+ * DeprecatedIdentifierException} in case the identifier is deprecated
+ * @return possibly-empty list of notes for all matching changes; may or may not be visible.
+ * @throws OrmException if an error occurred querying the database
+ * @throws DeprecatedIdentifierException if the identifier is deprecated.
+ */
+ public List<ChangeNotes> find(String id, boolean enforceDeprecation)
+ throws OrmException, DeprecatedIdentifierException {
if (id.isEmpty()) {
return Collections.emptyList();
}
@@ -115,7 +148,7 @@
// Try project~numericChangeId
Integer n = Ints.tryParse(id.substring(z + 1));
if (n != null) {
- changeIdCounter.increment(ChangeIdType.PROJECT_NUMERIC_ID);
+ checkIdType(ChangeIdType.PROJECT_NUMERIC_ID, enforceDeprecation, n.toString());
return fromProjectNumber(id.substring(0, z), n.intValue());
}
}
@@ -124,7 +157,7 @@
// Try numeric changeId
Integer n = Ints.tryParse(id);
if (n != null) {
- changeIdCounter.increment(ChangeIdType.NUMERIC_ID);
+ checkIdType(ChangeIdType.NUMERIC_ID, enforceDeprecation, n.toString());
return find(new Change.Id(n));
}
}
@@ -135,7 +168,7 @@
// Try commit hash
if (id.matches("^([0-9a-fA-F]{" + RevId.ABBREV_LEN + "," + RevId.LEN + "})$")) {
- changeIdCounter.increment(ChangeIdType.COMMIT_HASH);
+ checkIdType(ChangeIdType.COMMIT_HASH, enforceDeprecation, id);
return asChangeNotes(query.byCommit(id));
}
@@ -144,7 +177,7 @@
Optional<ChangeTriplet> triplet = ChangeTriplet.parse(id, y, z);
if (triplet.isPresent()) {
ChangeTriplet t = triplet.get();
- changeIdCounter.increment(ChangeIdType.TRIPLET);
+ checkIdType(ChangeIdType.TRIPLET, enforceDeprecation, triplet.get().toString());
return asChangeNotes(query.byBranchKey(t.branch(), t.id()));
}
}
@@ -152,7 +185,7 @@
// Try isolated Ihash... format ("Change-Id: Ihash").
List<ChangeNotes> notes = asChangeNotes(query.byKeyPrefix(id));
if (!notes.isEmpty()) {
- changeIdCounter.increment(ChangeIdType.CHANGE_ID);
+ checkIdType(ChangeIdType.I_HASH, enforceDeprecation, id);
}
return notes;
}
@@ -222,4 +255,18 @@
}
return notes;
}
+
+ private void checkIdType(ChangeIdType type, boolean enforceDeprecation, String val)
+ throws DeprecatedIdentifierException {
+ if (enforceDeprecation
+ && !allowedIdTypes.contains(ChangeIdType.ALL)
+ && !allowedIdTypes.contains(type)) {
+ throw new DeprecatedIdentifierException(
+ String.format(
+ "The provided change identifier %s is deprecated. "
+ + "Use 'project~changeNumber' instead.",
+ val));
+ }
+ changeIdCounter.increment(type);
+ }
}
diff --git a/java/com/google/gerrit/server/ReviewersUtil.java b/java/com/google/gerrit/server/ReviewersUtil.java
index c566e59..a8410d8 100644
--- a/java/com/google/gerrit/server/ReviewersUtil.java
+++ b/java/com/google/gerrit/server/ReviewersUtil.java
@@ -18,36 +18,41 @@
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.gerrit.common.data.GroupReference;
import com.google.gerrit.extensions.common.GroupBaseInfo;
import com.google.gerrit.extensions.common.SuggestedReviewerInfo;
import com.google.gerrit.extensions.restapi.Url;
+import com.google.gerrit.index.IndexConfig;
+import com.google.gerrit.index.QueryOptions;
+import com.google.gerrit.index.query.FieldBundle;
+import com.google.gerrit.index.query.Predicate;
import com.google.gerrit.index.query.QueryParseException;
-import com.google.gerrit.index.query.QueryResult;
import com.google.gerrit.metrics.Description;
import com.google.gerrit.metrics.Description.Units;
import com.google.gerrit.metrics.MetricMaker;
import com.google.gerrit.metrics.Timer0;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.account.AccountControl;
import com.google.gerrit.server.account.AccountDirectory.FillOptions;
import com.google.gerrit.server.account.AccountLoader;
-import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.account.GroupBackend;
import com.google.gerrit.server.account.GroupMembers;
import com.google.gerrit.server.change.PostReviewers;
import com.google.gerrit.server.change.SuggestReviewers;
+import com.google.gerrit.server.index.account.AccountField;
+import com.google.gerrit.server.index.account.AccountIndexCollection;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.server.query.account.AccountPredicates;
import com.google.gerrit.server.query.account.AccountQueryBuilder;
-import com.google.gerrit.server.query.account.AccountQueryProcessor;
import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.ResultSet;
import com.google.inject.Inject;
-import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.io.IOException;
import java.util.ArrayList;
@@ -108,30 +113,36 @@
private final AccountLoader accountLoader;
private final AccountQueryBuilder accountQueryBuilder;
- private final Provider<AccountQueryProcessor> queryProvider;
private final GroupBackend groupBackend;
private final GroupMembers groupMembers;
private final ReviewerRecommender reviewerRecommender;
private final Metrics metrics;
+ private final AccountIndexCollection accountIndexes;
+ private final IndexConfig indexConfig;
+ private final AccountControl.Factory accountControlFactory;
@Inject
ReviewersUtil(
AccountLoader.Factory accountLoaderFactory,
AccountQueryBuilder accountQueryBuilder,
- Provider<AccountQueryProcessor> queryProvider,
GroupBackend groupBackend,
GroupMembers groupMembers,
ReviewerRecommender reviewerRecommender,
- Metrics metrics) {
+ Metrics metrics,
+ AccountIndexCollection accountIndexes,
+ IndexConfig indexConfig,
+ AccountControl.Factory accountControlFactory) {
Set<FillOptions> fillOptions = EnumSet.of(FillOptions.SECONDARY_EMAILS);
fillOptions.addAll(AccountLoader.DETAILED_OPTIONS);
this.accountLoader = accountLoaderFactory.create(fillOptions);
this.accountQueryBuilder = accountQueryBuilder;
- this.queryProvider = queryProvider;
this.groupBackend = groupBackend;
this.groupMembers = groupMembers;
this.reviewerRecommender = reviewerRecommender;
this.metrics = metrics;
+ this.accountIndexes = accountIndexes;
+ this.indexConfig = indexConfig;
+ this.accountControlFactory = accountControlFactory;
}
public interface VisibilityControl {
@@ -167,7 +178,9 @@
if (filteredRecommendations.size() >= limit) {
break;
}
- if (visibilityControl.isVisibleTo(reviewer)) {
+ // Check if change is visible to reviewer and if the current user can see reviewer
+ if (visibilityControl.isVisibleTo(reviewer)
+ && accountControlFactory.get().canSee(reviewer)) {
filteredRecommendations.add(reviewer);
}
}
@@ -191,14 +204,27 @@
private List<Account.Id> suggestAccounts(SuggestReviewers suggestReviewers) throws OrmException {
try (Timer0.Context ctx = metrics.queryAccountsLatency.start()) {
try {
- QueryResult<AccountState> result =
- queryProvider
- .get()
- .setUserProvidedLimit(suggestReviewers.getLimit() * CANDIDATE_LIST_MULTIPLIER)
- .query(
- AccountPredicates.andActive(
- accountQueryBuilder.defaultQuery(suggestReviewers.getQuery())));
- return result.entities().stream().map(a -> a.getAccount().getId()).collect(toList());
+ // For performance reasons we don't use AccountQueryProvider as it would always load the
+ // complete account from the cache (or worse, from NoteDb) even though we only need the ID
+ // which we can directly get from the returned results.
+ ResultSet<FieldBundle> result =
+ accountIndexes
+ .getSearchIndex()
+ .getSource(
+ Predicate.and(
+ AccountPredicates.isActive(),
+ accountQueryBuilder.defaultQuery(suggestReviewers.getQuery())),
+ QueryOptions.create(
+ indexConfig,
+ 0,
+ suggestReviewers.getLimit() * CANDIDATE_LIST_MULTIPLIER,
+ ImmutableSet.of(AccountField.ID.getName())))
+ .readRaw();
+ return result
+ .toList()
+ .stream()
+ .map(f -> new Account.Id(f.getValue(AccountField.ID).intValue()))
+ .collect(toList());
} catch (QueryParseException e) {
return ImmutableList.of();
}
diff --git a/java/com/google/gerrit/server/account/GroupMembers.java b/java/com/google/gerrit/server/account/GroupMembers.java
index 3bb9de2..a5876d8 100644
--- a/java/com/google/gerrit/server/account/GroupMembers.java
+++ b/java/com/google/gerrit/server/account/GroupMembers.java
@@ -17,6 +17,7 @@
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import com.google.common.collect.Sets;
+import com.google.gerrit.common.Nullable;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Project;
@@ -52,6 +53,25 @@
this.projectCache = projectCache;
}
+ /**
+ * Recursively enumerate the members of the given group. Should not be used with the
+ * PROJECT_OWNERS magical group.
+ */
+ public Set<Account> listAccounts(AccountGroup.UUID groupUUID) throws IOException {
+ if (SystemGroupBackend.PROJECT_OWNERS.equals(groupUUID)) {
+ throw new IllegalStateException("listAccounts called with PROJECT_OWNERS argument");
+ }
+ try {
+ return listAccounts(groupUUID, null, new HashSet<AccountGroup.UUID>());
+ } catch (NoSuchProjectException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * Recursively enumerate the members of the given group. The project should be specified so the
+ * PROJECT_OWNERS magical group can be expanded.
+ */
public Set<Account> listAccounts(AccountGroup.UUID groupUUID, Project.NameKey project)
throws NoSuchProjectException, IOException {
return listAccounts(groupUUID, project, new HashSet<AccountGroup.UUID>());
@@ -59,7 +79,7 @@
private Set<Account> listAccounts(
final AccountGroup.UUID groupUUID,
- final Project.NameKey project,
+ @Nullable final Project.NameKey project,
final Set<AccountGroup.UUID> seen)
throws NoSuchProjectException, IOException {
if (SystemGroupBackend.PROJECT_OWNERS.equals(groupUUID)) {
@@ -94,7 +114,7 @@
}
private Set<Account> getGroupMembers(
- InternalGroup group, Project.NameKey project, Set<AccountGroup.UUID> seen)
+ InternalGroup group, @Nullable Project.NameKey project, Set<AccountGroup.UUID> seen)
throws NoSuchProjectException, IOException {
seen.add(group.getGroupUUID());
GroupControl groupControl = groupControlFactory.controlFor(new InternalGroupDescription(group));
diff --git a/java/com/google/gerrit/server/account/StarredChanges.java b/java/com/google/gerrit/server/account/StarredChanges.java
index 38c95e6..6dfd132 100644
--- a/java/com/google/gerrit/server/account/StarredChanges.java
+++ b/java/com/google/gerrit/server/account/StarredChanges.java
@@ -72,7 +72,7 @@
@Override
public AccountResource.StarredChange parse(AccountResource parent, IdString id)
- throws ResourceNotFoundException, OrmException, PermissionBackendException {
+ throws RestApiException, OrmException, PermissionBackendException {
IdentifiedUser user = parent.getUser();
ChangeResource change = changes.parse(TopLevelResource.INSTANCE, id);
if (starredChangesUtil
@@ -103,7 +103,7 @@
@Override
public RestModifyView<AccountResource, EmptyInput> create(AccountResource parent, IdString id)
- throws UnprocessableEntityException {
+ throws RestApiException {
try {
return createProvider.get().setChange(changes.parse(TopLevelResource.INSTANCE, id));
} catch (ResourceNotFoundException e) {
diff --git a/java/com/google/gerrit/server/account/Stars.java b/java/com/google/gerrit/server/account/Stars.java
index 9019ad7..5eb8d7b 100644
--- a/java/com/google/gerrit/server/account/Stars.java
+++ b/java/com/google/gerrit/server/account/Stars.java
@@ -21,7 +21,7 @@
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.ChildCollection;
import com.google.gerrit.extensions.restapi.IdString;
-import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
+import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.extensions.restapi.RestView;
@@ -66,7 +66,7 @@
@Override
public Star parse(AccountResource parent, IdString id)
- throws ResourceNotFoundException, OrmException, PermissionBackendException {
+ throws RestApiException, OrmException, PermissionBackendException {
IdentifiedUser user = parent.getUser();
ChangeResource change = changes.parse(TopLevelResource.INSTANCE, id);
Set<String> labels = starredChangesUtil.getLabels(user.getAccountId(), change.getId());
diff --git a/java/com/google/gerrit/server/api/BUILD b/java/com/google/gerrit/server/api/BUILD
index 2741a0a..910ecd3 100644
--- a/java/com/google/gerrit/server/api/BUILD
+++ b/java/com/google/gerrit/server/api/BUILD
@@ -11,6 +11,7 @@
"//java/com/google/gerrit/lifecycle",
"//java/com/google/gerrit/reviewdb:server",
"//java/com/google/gerrit/server",
+ "//java/com/google/gerrit/server/restapi",
"//lib:guava",
"//lib:gwtorm",
"//lib:servlet-api-3_1",
diff --git a/java/com/google/gerrit/server/api/config/ServerImpl.java b/java/com/google/gerrit/server/api/config/ServerImpl.java
index 2148d97..ce87d1c 100644
--- a/java/com/google/gerrit/server/api/config/ServerImpl.java
+++ b/java/com/google/gerrit/server/api/config/ServerImpl.java
@@ -24,13 +24,13 @@
import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
import com.google.gerrit.extensions.common.ServerInfo;
import com.google.gerrit.extensions.restapi.RestApiException;
-import com.google.gerrit.server.config.CheckConsistency;
import com.google.gerrit.server.config.ConfigResource;
-import com.google.gerrit.server.config.GetDiffPreferences;
-import com.google.gerrit.server.config.GetPreferences;
-import com.google.gerrit.server.config.GetServerInfo;
-import com.google.gerrit.server.config.SetDiffPreferences;
-import com.google.gerrit.server.config.SetPreferences;
+import com.google.gerrit.server.restapi.config.CheckConsistency;
+import com.google.gerrit.server.restapi.config.GetDiffPreferences;
+import com.google.gerrit.server.restapi.config.GetPreferences;
+import com.google.gerrit.server.restapi.config.GetServerInfo;
+import com.google.gerrit.server.restapi.config.SetDiffPreferences;
+import com.google.gerrit.server.restapi.config.SetPreferences;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
diff --git a/java/com/google/gerrit/server/change/ChangesCollection.java b/java/com/google/gerrit/server/change/ChangesCollection.java
index a0b6c96..6ce661e 100644
--- a/java/com/google/gerrit/server/change/ChangesCollection.java
+++ b/java/com/google/gerrit/server/change/ChangesCollection.java
@@ -81,8 +81,8 @@
@Override
public ChangeResource parse(TopLevelResource root, IdString id)
- throws ResourceNotFoundException, OrmException, PermissionBackendException {
- List<ChangeNotes> notes = changeFinder.find(id.encoded());
+ throws RestApiException, OrmException, PermissionBackendException {
+ List<ChangeNotes> notes = changeFinder.find(id.encoded(), true);
if (notes.isEmpty()) {
throw new ResourceNotFoundException(id);
} else if (notes.size() != 1) {
diff --git a/java/com/google/gerrit/server/change/ConsistencyChecker.java b/java/com/google/gerrit/server/change/ConsistencyChecker.java
index a149935..e10197f 100644
--- a/java/com/google/gerrit/server/change/ConsistencyChecker.java
+++ b/java/com/google/gerrit/server/change/ConsistencyChecker.java
@@ -52,6 +52,7 @@
import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
import com.google.gerrit.server.update.BatchUpdate;
import com.google.gerrit.server.update.BatchUpdateOp;
+import com.google.gerrit.server.update.BatchUpdateReviewDb;
import com.google.gerrit.server.update.ChangeContext;
import com.google.gerrit.server.update.RepoContext;
import com.google.gerrit.server.update.RetryHelper;
@@ -667,7 +668,7 @@
public boolean updateChange(ChangeContext ctx)
throws OrmException, PatchSetInfoNotAvailableException {
// Delete dangling key references.
- ReviewDb db = DeleteChangeOp.unwrap(ctx.getDb());
+ ReviewDb db = BatchUpdateReviewDb.unwrap(ctx.getDb());
accountPatchReviewStore.get().clearReviewed(psId);
db.changeMessages().delete(db.changeMessages().byChange(psId.getParentKey()));
db.patchSetApprovals().delete(db.patchSetApprovals().byPatchSet(psId));
diff --git a/java/com/google/gerrit/server/change/DeleteChangeOp.java b/java/com/google/gerrit/server/change/DeleteChangeOp.java
index 8df6e59..130d040 100644
--- a/java/com/google/gerrit/server/change/DeleteChangeOp.java
+++ b/java/com/google/gerrit/server/change/DeleteChangeOp.java
@@ -23,7 +23,6 @@
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gerrit.reviewdb.server.ReviewDbUtil;
import com.google.gerrit.server.PatchSetUtil;
import com.google.gerrit.server.StarredChangesUtil;
import com.google.gerrit.server.project.NoSuchChangeException;
@@ -47,16 +46,6 @@
return cfg.getBoolean("change", "allowDrafts", true);
}
- static ReviewDb unwrap(ReviewDb db) {
- // This is special. We want to delete exactly the rows that are present in
- // the database, even when reading everything else from NoteDb, so we need
- // to bypass the write-only wrapper.
- if (db instanceof BatchUpdateReviewDb) {
- db = ((BatchUpdateReviewDb) db).unsafeGetDelegate();
- }
- return ReviewDbUtil.unwrapDb(db);
- }
-
private final PatchSetUtil psUtil;
private final StarredChangesUtil starredChangesUtil;
private final DynamicItem<AccountPatchReviewStore> accountPatchReviewStore;
@@ -123,7 +112,11 @@
private void deleteChangeElementsFromDb(ChangeContext ctx, Change.Id id) throws OrmException {
// Only delete from ReviewDb here; deletion from NoteDb is handled in
// BatchUpdate.
- ReviewDb db = unwrap(ctx.getDb());
+ //
+ // This is special. We want to delete exactly the rows that are present in
+ // the database, even when reading everything else from NoteDb, so we need
+ // to bypass the write-only wrapper.
+ ReviewDb db = BatchUpdateReviewDb.unwrap(ctx.getDb());
db.patchComments().delete(db.patchComments().byChange(id));
db.patchSetApprovals().delete(db.patchSetApprovals().byChange(id));
db.patchSets().delete(db.patchSets().byChange(id));
diff --git a/java/com/google/gerrit/server/change/PreviewSubmit.java b/java/com/google/gerrit/server/change/PreviewSubmit.java
index 3c83f81..21266a0 100644
--- a/java/com/google/gerrit/server/change/PreviewSubmit.java
+++ b/java/com/google/gerrit/server/change/PreviewSubmit.java
@@ -29,11 +29,12 @@
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.change.LimitedByteArrayOutputStream.LimitExceededException;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.git.MergeOp;
import com.google.gerrit.server.git.MergeOpRepoManager;
import com.google.gerrit.server.git.MergeOpRepoManager.OpenRepo;
+import com.google.gerrit.server.ioutil.LimitedByteArrayOutputStream;
+import com.google.gerrit.server.ioutil.LimitedByteArrayOutputStream.LimitExceededException;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.update.UpdateException;
diff --git a/java/com/google/gerrit/server/config/GerritGlobalModule.java b/java/com/google/gerrit/server/config/GerritGlobalModule.java
index 224bf29..51a9fea 100644
--- a/java/com/google/gerrit/server/config/GerritGlobalModule.java
+++ b/java/com/google/gerrit/server/config/GerritGlobalModule.java
@@ -173,6 +173,7 @@
import com.google.gerrit.server.query.change.ChangeQueryBuilder;
import com.google.gerrit.server.query.change.ChangeQueryProcessor;
import com.google.gerrit.server.query.change.ConflictsCacheImpl;
+import com.google.gerrit.server.restapi.config.ConfigRestModule;
import com.google.gerrit.server.rules.PrologModule;
import com.google.gerrit.server.rules.RulesCache;
import com.google.gerrit.server.ssh.SshAddressesModule;
@@ -305,7 +306,7 @@
install(new com.google.gerrit.server.access.Module());
install(new com.google.gerrit.server.account.Module());
install(new com.google.gerrit.server.change.Module());
- install(new com.google.gerrit.server.config.Module());
+ install(new ConfigRestModule());
install(new com.google.gerrit.server.group.Module(groupsMigration));
install(new com.google.gerrit.server.project.Module());
diff --git a/java/com/google/gerrit/server/ioutil/BUILD b/java/com/google/gerrit/server/ioutil/BUILD
index d45cf73..06843c5 100644
--- a/java/com/google/gerrit/server/ioutil/BUILD
+++ b/java/com/google/gerrit/server/ioutil/BUILD
@@ -4,6 +4,7 @@
visibility = ["//visibility:public"],
deps = [
"//java/com/google/gerrit/reviewdb:client",
+ "//lib:guava",
"//lib/jgit/org.eclipse.jgit.archive:jgit-archive",
"//lib/jgit/org.eclipse.jgit:jgit",
],
diff --git a/java/com/google/gerrit/server/change/LimitedByteArrayOutputStream.java b/java/com/google/gerrit/server/ioutil/LimitedByteArrayOutputStream.java
similarity index 85%
rename from java/com/google/gerrit/server/change/LimitedByteArrayOutputStream.java
rename to java/com/google/gerrit/server/ioutil/LimitedByteArrayOutputStream.java
index facc03c..015887b 100644
--- a/java/com/google/gerrit/server/change/LimitedByteArrayOutputStream.java
+++ b/java/com/google/gerrit/server/ioutil/LimitedByteArrayOutputStream.java
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.change;
+package com.google.gerrit.server.ioutil;
import static com.google.common.base.Preconditions.checkArgument;
@@ -20,7 +20,8 @@
import java.io.IOException;
import java.io.OutputStream;
-class LimitedByteArrayOutputStream extends OutputStream {
+/** A stream that throws an exception if it consumes data beyond a configured byte count. */
+public class LimitedByteArrayOutputStream extends OutputStream {
private final int maxSize;
private final ByteArrayOutputStream buffer;
@@ -32,7 +33,7 @@
* @param max the maximum size in bytes which may be stored.
* @param initial the initial size. It must be smaller than the max size.
*/
- LimitedByteArrayOutputStream(int max, int initial) {
+ public LimitedByteArrayOutputStream(int max, int initial) {
checkArgument(initial <= max);
maxSize = max;
buffer = new ByteArrayOutputStream(initial);
@@ -61,7 +62,7 @@
return buffer.toByteArray();
}
- static class LimitExceededException extends IOException {
+ public static class LimitExceededException extends IOException {
private static final long serialVersionUID = 1L;
}
}
diff --git a/java/com/google/gerrit/server/project/ChildProjects.java b/java/com/google/gerrit/server/project/ChildProjects.java
new file mode 100644
index 0000000..0b174f6
--- /dev/null
+++ b/java/com/google/gerrit/server/project/ChildProjects.java
@@ -0,0 +1,112 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// 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 com.google.gerrit.server.project;
+
+import static java.util.stream.Collectors.toList;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+import com.google.gerrit.extensions.common.ProjectInfo;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.config.AllProjectsName;
+import com.google.gerrit.server.permissions.PermissionBackend;
+import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.permissions.ProjectPermission;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/** Retrieve child projects (ie. projects whose access inherits from a given parent.) */
+@Singleton
+public class ChildProjects {
+ private final ProjectCache projectCache;
+ private final PermissionBackend permissionBackend;
+ private final Provider<CurrentUser> user;
+ private final AllProjectsName allProjects;
+ private final ProjectJson json;
+
+ @Inject
+ ChildProjects(
+ ProjectCache projectCache,
+ PermissionBackend permissionBackend,
+ Provider<CurrentUser> user,
+ AllProjectsName allProjectsName,
+ ProjectJson json) {
+ this.projectCache = projectCache;
+ this.permissionBackend = permissionBackend;
+ this.user = user;
+ this.allProjects = allProjectsName;
+ this.json = json;
+ }
+
+ /** Gets all child projects recursively. */
+ public List<ProjectInfo> list(Project.NameKey parent) throws PermissionBackendException {
+ Map<Project.NameKey, Project> projects = readAllProjects();
+ Multimap<Project.NameKey, Project.NameKey> children = parentToChildren(projects);
+ PermissionBackend.WithUser perm = permissionBackend.user(user);
+
+ List<ProjectInfo> results = new ArrayList<>();
+ depthFirstFormat(results, perm, projects, children, parent);
+ return results;
+ }
+
+ private Map<Project.NameKey, Project> readAllProjects() {
+ Map<Project.NameKey, Project> projects = new HashMap<>();
+ for (Project.NameKey name : projectCache.all()) {
+ ProjectState c = projectCache.get(name);
+ if (c != null) {
+ projects.put(c.getNameKey(), c.getProject());
+ }
+ }
+ return projects;
+ }
+
+ /** Map of parent project to direct child. */
+ private Multimap<Project.NameKey, Project.NameKey> parentToChildren(
+ Map<Project.NameKey, Project> projects) {
+ Multimap<Project.NameKey, Project.NameKey> m = ArrayListMultimap.create();
+ for (Map.Entry<Project.NameKey, Project> e : projects.entrySet()) {
+ if (!allProjects.equals(e.getKey())) {
+ m.put(e.getValue().getParent(allProjects), e.getKey());
+ }
+ }
+ return m;
+ }
+
+ private void depthFirstFormat(
+ List<ProjectInfo> results,
+ PermissionBackend.WithUser perm,
+ Map<Project.NameKey, Project> projects,
+ Multimap<Project.NameKey, Project.NameKey> children,
+ Project.NameKey parent)
+ throws PermissionBackendException {
+ List<Project.NameKey> canSee =
+ perm.filter(ProjectPermission.ACCESS, children.get(parent))
+ .stream()
+ .sorted()
+ .collect(toList());
+ children.removeAll(parent); // removing all entries prevents cycles.
+
+ for (Project.NameKey c : canSee) {
+ results.add(json.format(projects.get(c)));
+ depthFirstFormat(results, perm, projects, children, c);
+ }
+ }
+}
diff --git a/java/com/google/gerrit/server/project/CommitsCollection.java b/java/com/google/gerrit/server/project/CommitsCollection.java
index a504a1f..481c2c8 100644
--- a/java/com/google/gerrit/server/project/CommitsCollection.java
+++ b/java/com/google/gerrit/server/project/CommitsCollection.java
@@ -20,9 +20,7 @@
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestView;
import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.server.change.IncludedInResolver;
import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.git.VisibleRefFilter;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.query.change.InternalChangeQuery;
import com.google.gwtorm.server.OrmException;
@@ -31,11 +29,9 @@
import com.google.inject.Singleton;
import java.io.IOException;
import java.util.List;
-import java.util.Map;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
@@ -48,19 +44,19 @@
private final DynamicMap<RestView<CommitResource>> views;
private final GitRepositoryManager repoManager;
- private final VisibleRefFilter.Factory refFilter;
private final Provider<InternalChangeQuery> queryProvider;
+ private final Reachable reachable;
@Inject
public CommitsCollection(
DynamicMap<RestView<CommitResource>> views,
GitRepositoryManager repoManager,
- VisibleRefFilter.Factory refFilter,
- Provider<InternalChangeQuery> queryProvider) {
+ Provider<InternalChangeQuery> queryProvider,
+ Reachable reachable) {
this.views = views;
this.repoManager = repoManager;
- this.refFilter = refFilter;
this.queryProvider = queryProvider;
+ this.reachable = reachable;
}
@Override
@@ -114,21 +110,6 @@
log.error("Cannot look up change for commit " + commit.name() + " in " + project, e);
}
- return isReachableFrom(state, repo, commit, repo.getAllRefs());
- }
-
- public boolean isReachableFrom(
- ProjectState state, Repository repo, RevCommit commit, Map<String, Ref> refs) {
- try (RevWalk rw = new RevWalk(repo)) {
- refs = refFilter.create(state, repo).filter(refs, true);
- return IncludedInResolver.includedInAny(repo, rw, commit, refs.values());
- } catch (IOException e) {
- log.error(
- String.format(
- "Cannot verify permissions to commit object %s in repository %s",
- commit.name(), state.getNameKey()),
- e);
- return false;
- }
+ return reachable.fromRefs(state, repo, commit, repo.getAllRefs());
}
}
diff --git a/java/com/google/gerrit/server/project/ListChildProjects.java b/java/com/google/gerrit/server/project/ListChildProjects.java
index e5fe37d..9de0c87 100644
--- a/java/com/google/gerrit/server/project/ListChildProjects.java
+++ b/java/com/google/gerrit/server/project/ListChildProjects.java
@@ -16,8 +16,6 @@
import static java.util.stream.Collectors.toList;
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.Multimap;
import com.google.gerrit.extensions.common.ProjectInfo;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.reviewdb.client.Project;
@@ -28,7 +26,6 @@
import com.google.gerrit.server.permissions.ProjectPermission;
import com.google.inject.Inject;
import com.google.inject.Provider;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -44,6 +41,7 @@
private final Provider<CurrentUser> user;
private final AllProjectsName allProjects;
private final ProjectJson json;
+ private final ChildProjects childProjects;
@Inject
ListChildProjects(
@@ -51,12 +49,14 @@
PermissionBackend permissionBackend,
Provider<CurrentUser> user,
AllProjectsName allProjectsName,
- ProjectJson json) {
+ ProjectJson json,
+ ChildProjects childProjects) {
this.projectCache = projectCache;
this.permissionBackend = permissionBackend;
this.user = user;
this.allProjects = allProjectsName;
this.json = json;
+ this.childProjects = childProjects;
}
public void setRecursive(boolean recursive) {
@@ -66,8 +66,9 @@
@Override
public List<ProjectInfo> apply(ProjectResource rsrc) throws PermissionBackendException {
if (recursive) {
- return recursiveChildProjects(rsrc.getNameKey());
+ return childProjects.list(rsrc.getNameKey());
}
+
return directChildProjects(rsrc.getNameKey());
}
@@ -88,58 +89,4 @@
.map((p) -> json.format(children.get(p)))
.collect(toList());
}
-
- private List<ProjectInfo> recursiveChildProjects(Project.NameKey parent)
- throws PermissionBackendException {
- Map<Project.NameKey, Project> projects = readAllProjects();
- Multimap<Project.NameKey, Project.NameKey> children = parentToChildren(projects);
- PermissionBackend.WithUser perm = permissionBackend.user(user);
-
- List<ProjectInfo> results = new ArrayList<>();
- depthFirstFormat(results, perm, projects, children, parent);
- return results;
- }
-
- private Map<Project.NameKey, Project> readAllProjects() {
- Map<Project.NameKey, Project> projects = new HashMap<>();
- for (Project.NameKey name : projectCache.all()) {
- ProjectState c = projectCache.get(name);
- if (c != null) {
- projects.put(c.getNameKey(), c.getProject());
- }
- }
- return projects;
- }
-
- /** Map of parent project to direct child. */
- private Multimap<Project.NameKey, Project.NameKey> parentToChildren(
- Map<Project.NameKey, Project> projects) {
- Multimap<Project.NameKey, Project.NameKey> m = ArrayListMultimap.create();
- for (Map.Entry<Project.NameKey, Project> e : projects.entrySet()) {
- if (!allProjects.equals(e.getKey())) {
- m.put(e.getValue().getParent(allProjects), e.getKey());
- }
- }
- return m;
- }
-
- private void depthFirstFormat(
- List<ProjectInfo> results,
- PermissionBackend.WithUser perm,
- Map<Project.NameKey, Project> projects,
- Multimap<Project.NameKey, Project.NameKey> children,
- Project.NameKey parent)
- throws PermissionBackendException {
- List<Project.NameKey> canSee =
- perm.filter(ProjectPermission.ACCESS, children.get(parent))
- .stream()
- .sorted()
- .collect(toList());
- children.removeAll(parent); // removing all entries prevents cycles.
-
- for (Project.NameKey c : canSee) {
- results.add(json.format(projects.get(c)));
- depthFirstFormat(results, perm, projects, children, c);
- }
- }
}
diff --git a/java/com/google/gerrit/server/project/ProjectControl.java b/java/com/google/gerrit/server/project/ProjectControl.java
index 0e62b3fdc..97d0173 100644
--- a/java/com/google/gerrit/server/project/ProjectControl.java
+++ b/java/com/google/gerrit/server/project/ProjectControl.java
@@ -17,8 +17,6 @@
import static com.google.common.base.Preconditions.checkArgument;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Maps;
import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.Permission;
import com.google.gerrit.common.data.PermissionRule;
@@ -60,18 +58,11 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.RefDatabase;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/** Access control management for a user accessing a project's data. */
class ProjectControl {
- private static final Logger log = LoggerFactory.getLogger(ProjectControl.class);
-
static class GenericFactory {
private final ProjectCache projectCache;
@@ -112,7 +103,7 @@
private final PermissionBackend.WithUser perm;
private final CurrentUser user;
private final ProjectState state;
- private final CommitsCollection commits;
+ private final Reachable reachable;
private final ChangeControl.Factory changeControlFactory;
private final PermissionCollection.Factory permissionFilter;
@@ -125,7 +116,7 @@
@GitUploadPackGroups Set<AccountGroup.UUID> uploadGroups,
@GitReceivePackGroups Set<AccountGroup.UUID> receiveGroups,
PermissionCollection.Factory permissionFilter,
- CommitsCollection commits,
+ Reachable reachable,
ChangeControl.Factory changeControlFactory,
PermissionBackend permissionBackend,
@Assisted CurrentUser who,
@@ -134,7 +125,7 @@
this.uploadGroups = uploadGroups;
this.receiveGroups = receiveGroups;
this.permissionFilter = permissionFilter;
- this.commits = commits;
+ this.reachable = reachable;
this.perm = permissionBackend.user(who);
user = who;
state = ps;
@@ -173,6 +164,10 @@
return ctl;
}
+ boolean isReachableFromHeadsOrTags(Repository repo, RevCommit commit) {
+ return reachable.fromHeadsOrTags(state, repo, commit);
+ }
+
CurrentUser getUser() {
return user;
}
@@ -352,26 +347,6 @@
}
}
- boolean isReachableFromHeadsOrTags(Repository repo, RevCommit commit) {
- try {
- RefDatabase refdb = repo.getRefDatabase();
- Collection<Ref> heads = refdb.getRefs(Constants.R_HEADS).values();
- Collection<Ref> tags = refdb.getRefs(Constants.R_TAGS).values();
- Map<String, Ref> refs = Maps.newHashMapWithExpectedSize(heads.size() + tags.size());
- for (Ref r : Iterables.concat(heads, tags)) {
- refs.put(r.getName(), r);
- }
- return commits.isReachableFrom(state, repo, commit, refs);
- } catch (IOException e) {
- log.error(
- String.format(
- "Cannot verify permissions to commit object %s in repository %s",
- commit.name(), getProject().getNameKey()),
- e);
- return false;
- }
- }
-
boolean canRead() {
return !isHidden() && allRefsAreVisible(Collections.emptySet());
}
diff --git a/java/com/google/gerrit/server/project/Reachable.java b/java/com/google/gerrit/server/project/Reachable.java
new file mode 100644
index 0000000..42389d3
--- /dev/null
+++ b/java/com/google/gerrit/server/project/Reachable.java
@@ -0,0 +1,83 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// 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 com.google.gerrit.server.project;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
+import com.google.gerrit.server.change.IncludedInResolver;
+import com.google.gerrit.server.git.VisibleRefFilter;
+import com.google.inject.Inject;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefDatabase;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Report whether a commit is reachable from a set of commits. This is used for checking if a user
+ * has read permissions on a commit.
+ */
+public class Reachable {
+ private final VisibleRefFilter.Factory refFilter;
+ private static final Logger log = LoggerFactory.getLogger(Reachable.class);
+
+ @Inject
+ Reachable(VisibleRefFilter.Factory refFilter) {
+ this.refFilter = refFilter;
+ }
+
+ /** @return true if a commit is reachable from a given set of refs. */
+ public boolean fromRefs(
+ ProjectState state, Repository repo, RevCommit commit, Map<String, Ref> refs) {
+ try (RevWalk rw = new RevWalk(repo)) {
+ Map<String, Ref> filtered = refFilter.create(state, repo).filter(refs, true);
+ return IncludedInResolver.includedInAny(repo, rw, commit, filtered.values());
+ } catch (IOException e) {
+ log.error(
+ String.format(
+ "Cannot verify permissions to commit object %s in repository %s",
+ commit.name(), state.getNameKey()),
+ e);
+ return false;
+ }
+ }
+
+ /** @return true if a commit is reachable from a repo's branches and tags. */
+ boolean fromHeadsOrTags(ProjectState state, Repository repo, RevCommit commit) {
+ try {
+ RefDatabase refdb = repo.getRefDatabase();
+ Collection<Ref> heads = refdb.getRefs(Constants.R_HEADS).values();
+ Collection<Ref> tags = refdb.getRefs(Constants.R_TAGS).values();
+ Map<String, Ref> refs = Maps.newHashMapWithExpectedSize(heads.size() + tags.size());
+ for (Ref r : Iterables.concat(heads, tags)) {
+ refs.put(r.getName(), r);
+ }
+ return fromRefs(state, repo, commit, refs);
+ } catch (IOException e) {
+ log.error(
+ String.format(
+ "Cannot verify permissions to commit object %s in repository %s",
+ commit.name(), state.getProject().getNameKey()),
+ e);
+ return false;
+ }
+ }
+}
diff --git a/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java b/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
index ebb3e65..3f41219 100644
--- a/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
+++ b/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
@@ -51,6 +51,7 @@
import com.google.gerrit.server.account.AccountResolver;
import com.google.gerrit.server.account.GroupBackend;
import com.google.gerrit.server.account.GroupBackends;
+import com.google.gerrit.server.account.GroupMembers;
import com.google.gerrit.server.account.VersionedAccountDestinations;
import com.google.gerrit.server.account.VersionedAccountQueries;
import com.google.gerrit.server.change.ChangeTriplet;
@@ -59,7 +60,6 @@
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.strategy.SubmitDryRun;
-import com.google.gerrit.server.group.ListMembers;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gerrit.server.index.change.ChangeIndex;
import com.google.gerrit.server.index.change.ChangeIndexCollection;
@@ -70,7 +70,7 @@
import com.google.gerrit.server.notedb.ReviewerStateInternal;
import com.google.gerrit.server.patch.PatchListCache;
import com.google.gerrit.server.permissions.PermissionBackend;
-import com.google.gerrit.server.project.ListChildProjects;
+import com.google.gerrit.server.project.ChildProjects;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
@@ -210,12 +210,12 @@
final PatchListCache patchListCache;
final ProjectCache projectCache;
final Provider<InternalChangeQuery> queryProvider;
- final Provider<ListChildProjects> listChildProjects;
- final Provider<ListMembers> listMembers;
+ final ChildProjects childProjects;
final Provider<ReviewDb> db;
final StarredChangesUtil starredChangesUtil;
final SubmitDryRun submitDryRun;
final boolean allowsDrafts;
+ final GroupMembers groupMembers;
private final Provider<CurrentUser> self;
@@ -240,16 +240,16 @@
PatchListCache patchListCache,
GitRepositoryManager repoManager,
ProjectCache projectCache,
- Provider<ListChildProjects> listChildProjects,
+ ChildProjects childProjects,
ChangeIndexCollection indexes,
SubmitDryRun submitDryRun,
ConflictsCache conflictsCache,
IndexConfig indexConfig,
- Provider<ListMembers> listMembers,
StarredChangesUtil starredChangesUtil,
AccountCache accountCache,
@GerritServerConfig Config cfg,
- NotesMigration notesMigration) {
+ NotesMigration notesMigration,
+ GroupMembers groupMembers) {
this(
db,
queryProvider,
@@ -269,16 +269,16 @@
patchListCache,
repoManager,
projectCache,
- listChildProjects,
+ childProjects,
submitDryRun,
conflictsCache,
indexes != null ? indexes.getSearchIndex() : null,
indexConfig,
- listMembers,
starredChangesUtil,
accountCache,
cfg == null ? true : cfg.getBoolean("change", "allowDrafts", true),
- notesMigration);
+ notesMigration,
+ groupMembers);
}
private Arguments(
@@ -300,16 +300,16 @@
PatchListCache patchListCache,
GitRepositoryManager repoManager,
ProjectCache projectCache,
- Provider<ListChildProjects> listChildProjects,
+ ChildProjects childProjects,
SubmitDryRun submitDryRun,
ConflictsCache conflictsCache,
ChangeIndex index,
IndexConfig indexConfig,
- Provider<ListMembers> listMembers,
StarredChangesUtil starredChangesUtil,
AccountCache accountCache,
boolean allowsDrafts,
- NotesMigration notesMigration) {
+ NotesMigration notesMigration,
+ GroupMembers groupMembers) {
this.db = db;
this.queryProvider = queryProvider;
this.rewriter = rewriter;
@@ -327,17 +327,17 @@
this.patchListCache = patchListCache;
this.repoManager = repoManager;
this.projectCache = projectCache;
- this.listChildProjects = listChildProjects;
+ this.childProjects = childProjects;
this.submitDryRun = submitDryRun;
this.conflictsCache = conflictsCache;
this.index = index;
this.indexConfig = indexConfig;
- this.listMembers = listMembers;
this.starredChangesUtil = starredChangesUtil;
this.accountCache = accountCache;
this.allowsDrafts = allowsDrafts;
this.hasOperands = hasOperands;
this.notesMigration = notesMigration;
+ this.groupMembers = groupMembers;
}
Arguments asUser(CurrentUser otherUser) {
@@ -360,16 +360,16 @@
patchListCache,
repoManager,
projectCache,
- listChildProjects,
+ childProjects,
submitDryRun,
conflictsCache,
index,
indexConfig,
- listMembers,
starredChangesUtil,
accountCache,
allowsDrafts,
- notesMigration);
+ notesMigration,
+ groupMembers);
}
Arguments asUser(Account.Id otherId) {
@@ -653,7 +653,7 @@
@Operator
public Predicate<ChangeData> parentproject(String name) {
- return new ParentProjectPredicate(args.projectCache, args.listChildProjects, args.self, name);
+ return new ParentProjectPredicate(args.projectCache, args.childProjects, name);
}
@Operator
@@ -775,12 +775,8 @@
// expand a group predicate into multiple user predicates
if (group != null) {
Set<Account.Id> allMembers =
- args.listMembers
- .get()
- .getTransitiveMembers(group)
- .stream()
- .map(a -> new Account.Id(a._accountId))
- .collect(toSet());
+ args.groupMembers.listAccounts(group).stream().map(a -> a.getId()).collect(toSet());
+
int maxTerms = args.indexConfig.maxTerms();
if (allMembers.size() > maxTerms) {
// limit the number of query terms otherwise Gerrit will barf
@@ -906,7 +902,6 @@
}
// If its not an account, maybe its a group?
- //
Collection<GroupReference> suggestions = args.groupBackend.suggest(who, null);
if (!suggestions.isEmpty()) {
HashSet<AccountGroup.UUID> ids = new HashSet<>();
diff --git a/java/com/google/gerrit/server/query/change/ParentProjectPredicate.java b/java/com/google/gerrit/server/query/change/ParentProjectPredicate.java
index e3ff21a..a9de2b1 100644
--- a/java/com/google/gerrit/server/query/change/ParentProjectPredicate.java
+++ b/java/com/google/gerrit/server/query/change/ParentProjectPredicate.java
@@ -18,13 +18,10 @@
import com.google.gerrit.index.query.OrPredicate;
import com.google.gerrit.index.query.Predicate;
import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.permissions.PermissionBackendException;
-import com.google.gerrit.server.project.ListChildProjects;
+import com.google.gerrit.server.project.ChildProjects;
import com.google.gerrit.server.project.ProjectCache;
-import com.google.gerrit.server.project.ProjectResource;
import com.google.gerrit.server.project.ProjectState;
-import com.google.inject.Provider;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -37,19 +34,13 @@
protected final String value;
public ParentProjectPredicate(
- ProjectCache projectCache,
- Provider<ListChildProjects> listChildProjects,
- Provider<CurrentUser> self,
- String value) {
- super(predicates(projectCache, listChildProjects, self, value));
+ ProjectCache projectCache, ChildProjects childProjects, String value) {
+ super(predicates(projectCache, childProjects, value));
this.value = value;
}
protected static List<Predicate<ChangeData>> predicates(
- ProjectCache projectCache,
- Provider<ListChildProjects> listChildProjects,
- Provider<CurrentUser> self,
- String value) {
+ ProjectCache projectCache, ChildProjects childProjects, String value) {
ProjectState projectState = projectCache.get(new Project.NameKey(value));
if (projectState == null) {
return Collections.emptyList();
@@ -58,10 +49,7 @@
List<Predicate<ChangeData>> r = new ArrayList<>();
r.add(new ProjectPredicate(projectState.getName()));
try {
- ProjectResource proj = new ProjectResource(projectState, self.get());
- ListChildProjects children = listChildProjects.get();
- children.setRecursive(true);
- for (ProjectInfo p : children.apply(proj)) {
+ for (ProjectInfo p : childProjects.list(projectState.getNameKey())) {
r.add(new ProjectPredicate(p.name));
}
} catch (PermissionBackendException e) {
diff --git a/java/com/google/gerrit/server/restapi/BUILD b/java/com/google/gerrit/server/restapi/BUILD
new file mode 100644
index 0000000..e0262bb
--- /dev/null
+++ b/java/com/google/gerrit/server/restapi/BUILD
@@ -0,0 +1,22 @@
+package(
+ default_visibility = ["//visibility:public"],
+)
+
+java_library(
+ name = "restapi",
+ srcs = glob(["**/*.java"]),
+ deps = [
+ "//java/com/google/gerrit/common:server",
+ "//java/com/google/gerrit/extensions:api",
+ "//java/com/google/gerrit/reviewdb:server",
+ "//java/com/google/gerrit/server",
+ "//java/org/eclipse/jgit:server",
+ "//lib:args4j",
+ "//lib:guava",
+ "//lib:gwtorm",
+ "//lib:servlet-api-3_1",
+ "//lib/guice",
+ "//lib/jgit/org.eclipse.jgit:jgit",
+ "//lib/log:api",
+ ],
+)
diff --git a/java/com/google/gerrit/server/config/CachesCollection.java b/java/com/google/gerrit/server/restapi/config/CachesCollection.java
similarity index 95%
rename from java/com/google/gerrit/server/config/CachesCollection.java
rename to java/com/google/gerrit/server/restapi/config/CachesCollection.java
index 7ecfa63..cfdc648 100644
--- a/java/com/google/gerrit/server/config/CachesCollection.java
+++ b/java/com/google/gerrit/server/restapi/config/CachesCollection.java
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.config;
+package com.google.gerrit.server.restapi.config;
import static com.google.gerrit.common.data.GlobalCapability.MAINTAIN_SERVER;
import static com.google.gerrit.common.data.GlobalCapability.VIEW_CACHES;
@@ -28,6 +28,8 @@
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.RestView;
import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.config.CacheResource;
+import com.google.gerrit.server.config.ConfigResource;
import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
diff --git a/java/com/google/gerrit/server/config/CapabilitiesCollection.java b/java/com/google/gerrit/server/restapi/config/CapabilitiesCollection.java
similarity index 91%
rename from java/com/google/gerrit/server/config/CapabilitiesCollection.java
rename to java/com/google/gerrit/server/restapi/config/CapabilitiesCollection.java
index 1124048..ae1278d 100644
--- a/java/com/google/gerrit/server/config/CapabilitiesCollection.java
+++ b/java/com/google/gerrit/server/restapi/config/CapabilitiesCollection.java
@@ -12,13 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.config;
+package com.google.gerrit.server.restapi.config;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.ChildCollection;
import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestView;
+import com.google.gerrit.server.config.CapabilityResource;
+import com.google.gerrit.server.config.ConfigResource;
import com.google.inject.Inject;
import com.google.inject.Singleton;
diff --git a/java/com/google/gerrit/server/config/CheckConsistency.java b/java/com/google/gerrit/server/restapi/config/CheckConsistency.java
similarity index 97%
rename from java/com/google/gerrit/server/config/CheckConsistency.java
rename to java/com/google/gerrit/server/restapi/config/CheckConsistency.java
index 38813de..95b20c2 100644
--- a/java/com/google/gerrit/server/config/CheckConsistency.java
+++ b/java/com/google/gerrit/server/restapi/config/CheckConsistency.java
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.config;
+package com.google.gerrit.server.restapi.config;
import com.google.gerrit.extensions.api.config.ConsistencyCheckInfo;
import com.google.gerrit.extensions.api.config.ConsistencyCheckInfo.CheckAccountExternalIdsResultInfo;
@@ -25,6 +25,7 @@
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.account.AccountsConsistencyChecker;
import com.google.gerrit.server.account.externalids.ExternalIdsConsistencyChecker;
+import com.google.gerrit.server.config.ConfigResource;
import com.google.gerrit.server.group.db.GroupsConsistencyChecker;
import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackend;
diff --git a/java/com/google/gerrit/server/config/ConfigCollection.java b/java/com/google/gerrit/server/restapi/config/ConfigCollection.java
similarity index 94%
rename from java/com/google/gerrit/server/config/ConfigCollection.java
rename to java/com/google/gerrit/server/restapi/config/ConfigCollection.java
index f268110..934dbc1 100644
--- a/java/com/google/gerrit/server/config/ConfigCollection.java
+++ b/java/com/google/gerrit/server/restapi/config/ConfigCollection.java
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.config;
+package com.google.gerrit.server.restapi.config;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.IdString;
@@ -20,6 +20,7 @@
import com.google.gerrit.extensions.restapi.RestCollection;
import com.google.gerrit.extensions.restapi.RestView;
import com.google.gerrit.extensions.restapi.TopLevelResource;
+import com.google.gerrit.server.config.ConfigResource;
import com.google.inject.Inject;
import com.google.inject.Singleton;
diff --git a/java/com/google/gerrit/server/config/Module.java b/java/com/google/gerrit/server/restapi/config/ConfigRestModule.java
similarity index 83%
rename from java/com/google/gerrit/server/config/Module.java
rename to java/com/google/gerrit/server/restapi/config/ConfigRestModule.java
index 7bf5ad5..71b2f9c 100644
--- a/java/com/google/gerrit/server/config/Module.java
+++ b/java/com/google/gerrit/server/restapi/config/ConfigRestModule.java
@@ -12,23 +12,23 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.config;
+package com.google.gerrit.server.restapi.config;
-import static com.google.gerrit.server.config.CapabilityResource.CAPABILITY_KIND;
import static com.google.gerrit.server.config.ConfigResource.CONFIG_KIND;
import static com.google.gerrit.server.config.TaskResource.TASK_KIND;
-import static com.google.gerrit.server.config.TopMenuResource.TOP_MENU_KIND;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.RestApiModule;
+import com.google.gerrit.server.config.CapabilityResource;
+import com.google.gerrit.server.config.TopMenuResource;
-public class Module extends RestApiModule {
+public class ConfigRestModule extends RestApiModule {
@Override
protected void configure() {
- DynamicMap.mapOf(binder(), CAPABILITY_KIND);
+ DynamicMap.mapOf(binder(), CapabilityResource.CAPABILITY_KIND);
DynamicMap.mapOf(binder(), CONFIG_KIND);
DynamicMap.mapOf(binder(), TASK_KIND);
- DynamicMap.mapOf(binder(), TOP_MENU_KIND);
+ DynamicMap.mapOf(binder(), TopMenuResource.TOP_MENU_KIND);
child(CONFIG_KIND, "capabilities").to(CapabilitiesCollection.class);
child(CONFIG_KIND, "tasks").to(TasksCollection.class);
get(TASK_KIND).to(GetTask.class);
diff --git a/java/com/google/gerrit/server/config/ConfirmEmail.java b/java/com/google/gerrit/server/restapi/config/ConfirmEmail.java
similarity index 94%
rename from java/com/google/gerrit/server/config/ConfirmEmail.java
rename to java/com/google/gerrit/server/restapi/config/ConfirmEmail.java
index 1044bbb..f6ceb68b 100644
--- a/java/com/google/gerrit/server/config/ConfirmEmail.java
+++ b/java/com/google/gerrit/server/restapi/config/ConfirmEmail.java
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.config;
+package com.google.gerrit.server.restapi.config;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.DefaultInput;
@@ -23,8 +23,9 @@
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.account.AccountException;
import com.google.gerrit.server.account.AccountManager;
-import com.google.gerrit.server.config.ConfirmEmail.Input;
+import com.google.gerrit.server.config.ConfigResource;
import com.google.gerrit.server.mail.EmailTokenVerifier;
+import com.google.gerrit.server.restapi.config.ConfirmEmail.Input;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
diff --git a/java/com/google/gerrit/server/config/DeleteTask.java b/java/com/google/gerrit/server/restapi/config/DeleteTask.java
similarity index 93%
rename from java/com/google/gerrit/server/config/DeleteTask.java
rename to java/com/google/gerrit/server/restapi/config/DeleteTask.java
index d20589a..a08b036 100644
--- a/java/com/google/gerrit/server/config/DeleteTask.java
+++ b/java/com/google/gerrit/server/restapi/config/DeleteTask.java
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.config;
+package com.google.gerrit.server.restapi.config;
import static com.google.gerrit.common.data.GlobalCapability.KILL_TASK;
import static com.google.gerrit.common.data.GlobalCapability.MAINTAIN_SERVER;
@@ -22,6 +22,7 @@
import com.google.gerrit.extensions.common.Input;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView;
+import com.google.gerrit.server.config.TaskResource;
import com.google.gerrit.server.git.WorkQueue.Task;
import com.google.inject.Singleton;
diff --git a/java/com/google/gerrit/server/config/FlushCache.java b/java/com/google/gerrit/server/restapi/config/FlushCache.java
similarity index 95%
rename from java/com/google/gerrit/server/config/FlushCache.java
rename to java/com/google/gerrit/server/restapi/config/FlushCache.java
index 5d2ec36..55e9dc3 100644
--- a/java/com/google/gerrit/server/config/FlushCache.java
+++ b/java/com/google/gerrit/server/restapi/config/FlushCache.java
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.config;
+package com.google.gerrit.server.restapi.config;
import static com.google.gerrit.common.data.GlobalCapability.FLUSH_CACHES;
import static com.google.gerrit.common.data.GlobalCapability.MAINTAIN_SERVER;
@@ -23,6 +23,7 @@
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.config.CacheResource;
import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
diff --git a/java/com/google/gerrit/server/config/GetCache.java b/java/com/google/gerrit/server/restapi/config/GetCache.java
similarity index 77%
rename from java/com/google/gerrit/server/config/GetCache.java
rename to java/com/google/gerrit/server/restapi/config/GetCache.java
index 53628cc..5abaf1e 100644
--- a/java/com/google/gerrit/server/config/GetCache.java
+++ b/java/com/google/gerrit/server/restapi/config/GetCache.java
@@ -12,17 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.config;
+package com.google.gerrit.server.restapi.config;
import com.google.gerrit.extensions.restapi.RestReadView;
-import com.google.gerrit.server.config.ListCaches.CacheInfo;
+import com.google.gerrit.server.config.CacheResource;
import com.google.inject.Singleton;
@Singleton
public class GetCache implements RestReadView<CacheResource> {
@Override
- public CacheInfo apply(CacheResource rsrc) {
- return new CacheInfo(rsrc.getName(), rsrc.getCache());
+ public ListCaches.CacheInfo apply(CacheResource rsrc) {
+ return new ListCaches.CacheInfo(rsrc.getName(), rsrc.getCache());
}
}
diff --git a/java/com/google/gerrit/server/config/GetDiffPreferences.java b/java/com/google/gerrit/server/restapi/config/GetDiffPreferences.java
similarity index 94%
rename from java/com/google/gerrit/server/config/GetDiffPreferences.java
rename to java/com/google/gerrit/server/restapi/config/GetDiffPreferences.java
index 8393fb4..6e72503 100644
--- a/java/com/google/gerrit/server/config/GetDiffPreferences.java
+++ b/java/com/google/gerrit/server/restapi/config/GetDiffPreferences.java
@@ -11,7 +11,7 @@
// 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 com.google.gerrit.server.config;
+package com.google.gerrit.server.restapi.config;
import static com.google.gerrit.server.config.ConfigUtil.loadSection;
@@ -20,6 +20,8 @@
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.server.account.VersionedAccountPreferences;
+import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.config.ConfigResource;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.UserConfigSections;
import com.google.inject.Inject;
diff --git a/java/com/google/gerrit/server/config/GetPreferences.java b/java/com/google/gerrit/server/restapi/config/GetPreferences.java
similarity index 94%
rename from java/com/google/gerrit/server/config/GetPreferences.java
rename to java/com/google/gerrit/server/restapi/config/GetPreferences.java
index ed212f4..c8a173f 100644
--- a/java/com/google/gerrit/server/config/GetPreferences.java
+++ b/java/com/google/gerrit/server/restapi/config/GetPreferences.java
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.config;
+package com.google.gerrit.server.restapi.config;
import static com.google.gerrit.server.config.ConfigUtil.loadSection;
@@ -20,6 +20,8 @@
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.server.account.GeneralPreferencesLoader;
import com.google.gerrit.server.account.VersionedAccountPreferences;
+import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.config.ConfigResource;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.UserConfigSections;
import com.google.inject.Inject;
diff --git a/java/com/google/gerrit/server/config/GetServerInfo.java b/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
similarity index 95%
rename from java/com/google/gerrit/server/config/GetServerInfo.java
rename to java/com/google/gerrit/server/restapi/config/GetServerInfo.java
index 90e2838..cacbd34 100644
--- a/java/com/google/gerrit/server/config/GetServerInfo.java
+++ b/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.config;
+package com.google.gerrit.server.restapi.config;
import static java.util.stream.Collectors.toList;
@@ -48,6 +48,16 @@
import com.google.gerrit.server.change.AllowedFormats;
import com.google.gerrit.server.change.ArchiveFormat;
import com.google.gerrit.server.change.Submit;
+import com.google.gerrit.server.config.AgreementJson;
+import com.google.gerrit.server.config.AllProjectsName;
+import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.config.AnonymousCowardName;
+import com.google.gerrit.server.config.AuthConfig;
+import com.google.gerrit.server.config.ConfigResource;
+import com.google.gerrit.server.config.ConfigUtil;
+import com.google.gerrit.server.config.GerritOptions;
+import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.documentation.QueryDocumentationExecutor;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gerrit.server.index.change.ChangeIndexCollection;
diff --git a/java/com/google/gerrit/server/config/GetSummary.java b/java/com/google/gerrit/server/restapi/config/GetSummary.java
similarity index 97%
rename from java/com/google/gerrit/server/config/GetSummary.java
rename to java/com/google/gerrit/server/restapi/config/GetSummary.java
index 82912c0..26f069c 100644
--- a/java/com/google/gerrit/server/config/GetSummary.java
+++ b/java/com/google/gerrit/server/restapi/config/GetSummary.java
@@ -12,11 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.config;
+package com.google.gerrit.server.restapi.config;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.extensions.restapi.RestReadView;
+import com.google.gerrit.server.config.ConfigResource;
+import com.google.gerrit.server.config.SitePath;
import com.google.gerrit.server.git.WorkQueue;
import com.google.gerrit.server.git.WorkQueue.Task;
import com.google.inject.Inject;
diff --git a/java/com/google/gerrit/server/config/GetTask.java b/java/com/google/gerrit/server/restapi/config/GetTask.java
similarity index 79%
rename from java/com/google/gerrit/server/config/GetTask.java
rename to java/com/google/gerrit/server/restapi/config/GetTask.java
index e4b3320..a32f3ba 100644
--- a/java/com/google/gerrit/server/config/GetTask.java
+++ b/java/com/google/gerrit/server/restapi/config/GetTask.java
@@ -12,17 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.config;
+package com.google.gerrit.server.restapi.config;
import com.google.gerrit.extensions.restapi.RestReadView;
-import com.google.gerrit.server.config.ListTasks.TaskInfo;
+import com.google.gerrit.server.config.TaskResource;
import com.google.inject.Singleton;
@Singleton
public class GetTask implements RestReadView<TaskResource> {
@Override
- public TaskInfo apply(TaskResource rsrc) {
- return new TaskInfo(rsrc.getTask());
+ public ListTasks.TaskInfo apply(TaskResource rsrc) {
+ return new ListTasks.TaskInfo(rsrc.getTask());
}
}
diff --git a/java/com/google/gerrit/server/config/GetVersion.java b/java/com/google/gerrit/server/restapi/config/GetVersion.java
similarity index 91%
rename from java/com/google/gerrit/server/config/GetVersion.java
rename to java/com/google/gerrit/server/restapi/config/GetVersion.java
index c71cb69..8135719 100644
--- a/java/com/google/gerrit/server/config/GetVersion.java
+++ b/java/com/google/gerrit/server/restapi/config/GetVersion.java
@@ -12,11 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.config;
+package com.google.gerrit.server.restapi.config;
import com.google.gerrit.common.Version;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestReadView;
+import com.google.gerrit.server.config.ConfigResource;
import com.google.inject.Singleton;
@Singleton
diff --git a/java/com/google/gerrit/server/config/ListCaches.java b/java/com/google/gerrit/server/restapi/config/ListCaches.java
similarity index 97%
rename from java/com/google/gerrit/server/config/ListCaches.java
rename to java/com/google/gerrit/server/restapi/config/ListCaches.java
index d78f61d..c0a9d71 100644
--- a/java/com/google/gerrit/server/config/ListCaches.java
+++ b/java/com/google/gerrit/server/restapi/config/ListCaches.java
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.config;
+package com.google.gerrit.server.restapi.config;
import static com.google.gerrit.common.data.GlobalCapability.MAINTAIN_SERVER;
import static com.google.gerrit.common.data.GlobalCapability.VIEW_CACHES;
@@ -27,6 +27,7 @@
import com.google.gerrit.extensions.restapi.BinaryResult;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.server.cache.PersistentCache;
+import com.google.gerrit.server.config.ConfigResource;
import com.google.inject.Inject;
import java.util.ArrayList;
import java.util.Collections;
diff --git a/java/com/google/gerrit/server/config/ListCapabilities.java b/java/com/google/gerrit/server/restapi/config/ListCapabilities.java
similarity index 94%
rename from java/com/google/gerrit/server/config/ListCapabilities.java
rename to java/com/google/gerrit/server/restapi/config/ListCapabilities.java
index b8d1888..6a1e5f6 100644
--- a/java/com/google/gerrit/server/config/ListCapabilities.java
+++ b/java/com/google/gerrit/server/restapi/config/ListCapabilities.java
@@ -12,12 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.config;
+package com.google.gerrit.server.restapi.config;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.config.CapabilityDefinition;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.RestReadView;
+import com.google.gerrit.server.config.CapabilityConstants;
+import com.google.gerrit.server.config.ConfigResource;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
diff --git a/java/com/google/gerrit/server/config/ListTasks.java b/java/com/google/gerrit/server/restapi/config/ListTasks.java
similarity index 97%
rename from java/com/google/gerrit/server/config/ListTasks.java
rename to java/com/google/gerrit/server/restapi/config/ListTasks.java
index bbda9eb..71ee5ad 100644
--- a/java/com/google/gerrit/server/config/ListTasks.java
+++ b/java/com/google/gerrit/server/restapi/config/ListTasks.java
@@ -12,13 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.config;
+package com.google.gerrit.server.restapi.config;
import com.google.common.collect.ComparisonChain;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.config.ConfigResource;
import com.google.gerrit.server.git.TaskInfoFactory;
import com.google.gerrit.server.git.WorkQueue;
import com.google.gerrit.server.git.WorkQueue.ProjectTask;
diff --git a/java/com/google/gerrit/server/config/ListTopMenus.java b/java/com/google/gerrit/server/restapi/config/ListTopMenus.java
similarity index 92%
rename from java/com/google/gerrit/server/config/ListTopMenus.java
rename to java/com/google/gerrit/server/restapi/config/ListTopMenus.java
index a7ba938..7a85bcd 100644
--- a/java/com/google/gerrit/server/config/ListTopMenus.java
+++ b/java/com/google/gerrit/server/restapi/config/ListTopMenus.java
@@ -12,11 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.config;
+package com.google.gerrit.server.restapi.config;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.extensions.webui.TopMenu;
+import com.google.gerrit.server.config.ConfigResource;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.util.ArrayList;
diff --git a/java/com/google/gerrit/server/config/PostCaches.java b/java/com/google/gerrit/server/restapi/config/PostCaches.java
similarity index 94%
rename from java/com/google/gerrit/server/config/PostCaches.java
rename to java/com/google/gerrit/server/restapi/config/PostCaches.java
index d08f0a9..f21672c 100644
--- a/java/com/google/gerrit/server/config/PostCaches.java
+++ b/java/com/google/gerrit/server/restapi/config/PostCaches.java
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.config;
+package com.google.gerrit.server.restapi.config;
import static com.google.gerrit.common.data.GlobalCapability.FLUSH_CACHES;
import static com.google.gerrit.common.data.GlobalCapability.MAINTAIN_SERVER;
@@ -25,8 +25,10 @@
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
-import com.google.gerrit.server.config.PostCaches.Input;
+import com.google.gerrit.server.config.CacheResource;
+import com.google.gerrit.server.config.ConfigResource;
import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.restapi.config.PostCaches.Input;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.util.ArrayList;
diff --git a/java/com/google/gerrit/server/config/RestCacheAdminModule.java b/java/com/google/gerrit/server/restapi/config/RestCacheAdminModule.java
similarity index 95%
rename from java/com/google/gerrit/server/config/RestCacheAdminModule.java
rename to java/com/google/gerrit/server/restapi/config/RestCacheAdminModule.java
index 992c62e..7283033 100644
--- a/java/com/google/gerrit/server/config/RestCacheAdminModule.java
+++ b/java/com/google/gerrit/server/restapi/config/RestCacheAdminModule.java
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.config;
+package com.google.gerrit.server.restapi.config;
import static com.google.gerrit.server.config.CacheResource.CACHE_KIND;
import static com.google.gerrit.server.config.ConfigResource.CONFIG_KIND;
diff --git a/java/com/google/gerrit/server/config/SetDiffPreferences.java b/java/com/google/gerrit/server/restapi/config/SetDiffPreferences.java
similarity index 93%
rename from java/com/google/gerrit/server/config/SetDiffPreferences.java
rename to java/com/google/gerrit/server/restapi/config/SetDiffPreferences.java
index 80c4625..a61b2aa 100644
--- a/java/com/google/gerrit/server/config/SetDiffPreferences.java
+++ b/java/com/google/gerrit/server/restapi/config/SetDiffPreferences.java
@@ -11,12 +11,11 @@
// 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 com.google.gerrit.server.config;
+package com.google.gerrit.server.restapi.config;
import static com.google.gerrit.server.config.ConfigUtil.loadSection;
import static com.google.gerrit.server.config.ConfigUtil.skipField;
import static com.google.gerrit.server.config.ConfigUtil.storeSection;
-import static com.google.gerrit.server.config.GetDiffPreferences.readFromGit;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
@@ -24,6 +23,8 @@
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.server.account.VersionedAccountPreferences;
+import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.config.ConfigResource;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.UserConfigSections;
@@ -65,7 +66,7 @@
if (!hasSetFields(in)) {
throw new BadRequestException("unsupported option");
}
- return writeToGit(readFromGit(gitManager, allUsersName, in));
+ return writeToGit(GetDiffPreferences.readFromGit(gitManager, allUsersName, in));
}
private DiffPreferencesInfo writeToGit(DiffPreferencesInfo in)
diff --git a/java/com/google/gerrit/server/config/SetPreferences.java b/java/com/google/gerrit/server/restapi/config/SetPreferences.java
similarity index 94%
rename from java/com/google/gerrit/server/config/SetPreferences.java
rename to java/com/google/gerrit/server/restapi/config/SetPreferences.java
index 55337d5..e2671d1 100644
--- a/java/com/google/gerrit/server/config/SetPreferences.java
+++ b/java/com/google/gerrit/server/restapi/config/SetPreferences.java
@@ -12,12 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.config;
+package com.google.gerrit.server.restapi.config;
import static com.google.gerrit.server.config.ConfigUtil.loadSection;
import static com.google.gerrit.server.config.ConfigUtil.skipField;
import static com.google.gerrit.server.config.ConfigUtil.storeSection;
-import static com.google.gerrit.server.config.GetPreferences.readFromGit;
+import static com.google.gerrit.server.restapi.config.GetPreferences.readFromGit;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
@@ -27,6 +27,8 @@
import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.account.GeneralPreferencesLoader;
import com.google.gerrit.server.account.VersionedAccountPreferences;
+import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.config.ConfigResource;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.UserConfigSections;
diff --git a/java/com/google/gerrit/server/config/TasksCollection.java b/java/com/google/gerrit/server/restapi/config/TasksCollection.java
similarity index 95%
rename from java/com/google/gerrit/server/config/TasksCollection.java
rename to java/com/google/gerrit/server/restapi/config/TasksCollection.java
index fcaee8e..f5b6e56 100644
--- a/java/com/google/gerrit/server/config/TasksCollection.java
+++ b/java/com/google/gerrit/server/restapi/config/TasksCollection.java
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.config;
+package com.google.gerrit.server.restapi.config;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.AuthException;
@@ -21,6 +21,8 @@
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestView;
import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.config.ConfigResource;
+import com.google.gerrit.server.config.TaskResource;
import com.google.gerrit.server.git.WorkQueue;
import com.google.gerrit.server.git.WorkQueue.ProjectTask;
import com.google.gerrit.server.git.WorkQueue.Task;
diff --git a/java/com/google/gerrit/server/config/TopMenuCollection.java b/java/com/google/gerrit/server/restapi/config/TopMenuCollection.java
similarity index 91%
rename from java/com/google/gerrit/server/config/TopMenuCollection.java
rename to java/com/google/gerrit/server/restapi/config/TopMenuCollection.java
index 2fc2dc1..36a1b04 100644
--- a/java/com/google/gerrit/server/config/TopMenuCollection.java
+++ b/java/com/google/gerrit/server/restapi/config/TopMenuCollection.java
@@ -12,13 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.config;
+package com.google.gerrit.server.restapi.config;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.ChildCollection;
import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestView;
+import com.google.gerrit.server.config.ConfigResource;
+import com.google.gerrit.server.config.TopMenuResource;
import com.google.inject.Inject;
import com.google.inject.Singleton;
diff --git a/java/com/google/gerrit/server/update/BatchUpdateReviewDb.java b/java/com/google/gerrit/server/update/BatchUpdateReviewDb.java
index 21e1f92..3b8f871 100644
--- a/java/com/google/gerrit/server/update/BatchUpdateReviewDb.java
+++ b/java/com/google/gerrit/server/update/BatchUpdateReviewDb.java
@@ -17,6 +17,7 @@
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.server.ChangeAccess;
import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.reviewdb.server.ReviewDbUtil;
import com.google.gerrit.reviewdb.server.ReviewDbWrapper;
import com.google.gwtorm.server.AtomicUpdate;
@@ -28,6 +29,14 @@
changesWrapper = new BatchUpdateChanges(delegate.changes());
}
+ /** @return the underlying delegate. Supports BatchUpdateReviewDb too. */
+ public static ReviewDb unwrap(ReviewDb db) {
+ if (db instanceof BatchUpdateReviewDb) {
+ db = ((BatchUpdateReviewDb) db).unsafeGetDelegate();
+ }
+ return ReviewDbUtil.unwrapDb(db);
+ }
+
public ReviewDb unsafeGetDelegate() {
return delegate;
}
diff --git a/java/com/google/gerrit/server/update/NoteDbBatchUpdate.java b/java/com/google/gerrit/server/update/NoteDbBatchUpdate.java
index ceef352..c10ae1b 100644
--- a/java/com/google/gerrit/server/update/NoteDbBatchUpdate.java
+++ b/java/com/google/gerrit/server/update/NoteDbBatchUpdate.java
@@ -61,8 +61,8 @@
* <p>Used when {@code noteDb.changes.disableReviewDb=true}, at which point ReviewDb is not
* consulted during updates.
*/
-class NoteDbBatchUpdate extends BatchUpdate {
- interface AssistedFactory {
+public class NoteDbBatchUpdate extends BatchUpdate {
+ public interface AssistedFactory {
NoteDbBatchUpdate create(
ReviewDb db, Project.NameKey project, CurrentUser user, Timestamp when);
}
diff --git a/java/com/google/gerrit/server/update/ReviewDbBatchUpdate.java b/java/com/google/gerrit/server/update/ReviewDbBatchUpdate.java
index 6835cb4..07ae04d 100644
--- a/java/com/google/gerrit/server/update/ReviewDbBatchUpdate.java
+++ b/java/com/google/gerrit/server/update/ReviewDbBatchUpdate.java
@@ -100,10 +100,10 @@
* The implementation in this class is well-tested, and it is strongly recommended that you not
* attempt to reimplement this logic. Use {@code BatchUpdate} if at all possible.
*/
-class ReviewDbBatchUpdate extends BatchUpdate {
+public class ReviewDbBatchUpdate extends BatchUpdate {
private static final Logger log = LoggerFactory.getLogger(ReviewDbBatchUpdate.class);
- interface AssistedFactory {
+ public interface AssistedFactory {
ReviewDbBatchUpdate create(
ReviewDb db, Project.NameKey project, CurrentUser user, Timestamp when);
}
diff --git a/java/com/google/gerrit/sshd/BUILD b/java/com/google/gerrit/sshd/BUILD
index a33ce86..3ed1f2f 100644
--- a/java/com/google/gerrit/sshd/BUILD
+++ b/java/com/google/gerrit/sshd/BUILD
@@ -14,6 +14,7 @@
"//java/com/google/gerrit/server/cache/h2",
"//java/com/google/gerrit/server/git/receive",
"//java/com/google/gerrit/server/ioutil",
+ "//java/com/google/gerrit/server/restapi",
"//java/com/google/gerrit/server/schema",
"//java/com/google/gerrit/util/cli",
"//java/org/eclipse/jgit:server",
diff --git a/java/com/google/gerrit/sshd/commands/FlushCaches.java b/java/com/google/gerrit/sshd/commands/FlushCaches.java
index 392fd29..2271ece 100644
--- a/java/com/google/gerrit/sshd/commands/FlushCaches.java
+++ b/java/com/google/gerrit/sshd/commands/FlushCaches.java
@@ -16,17 +16,17 @@
import static com.google.gerrit.common.data.GlobalCapability.FLUSH_CACHES;
import static com.google.gerrit.common.data.GlobalCapability.MAINTAIN_SERVER;
-import static com.google.gerrit.server.config.PostCaches.Operation.FLUSH;
-import static com.google.gerrit.server.config.PostCaches.Operation.FLUSH_ALL;
+import static com.google.gerrit.server.restapi.config.PostCaches.Operation.FLUSH;
+import static com.google.gerrit.server.restapi.config.PostCaches.Operation.FLUSH_ALL;
import static com.google.gerrit.sshd.CommandMetaData.Mode.MASTER_OR_SLAVE;
import com.google.gerrit.extensions.annotations.RequiresAnyCapability;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.server.config.ConfigResource;
-import com.google.gerrit.server.config.ListCaches;
-import com.google.gerrit.server.config.ListCaches.OutputFormat;
-import com.google.gerrit.server.config.PostCaches;
import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.restapi.config.ListCaches;
+import com.google.gerrit.server.restapi.config.ListCaches.OutputFormat;
+import com.google.gerrit.server.restapi.config.PostCaches;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.inject.Inject;
diff --git a/java/com/google/gerrit/sshd/commands/KillCommand.java b/java/com/google/gerrit/sshd/commands/KillCommand.java
index 3465a9c..a7e751a 100644
--- a/java/com/google/gerrit/sshd/commands/KillCommand.java
+++ b/java/com/google/gerrit/sshd/commands/KillCommand.java
@@ -22,10 +22,10 @@
import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.server.config.ConfigResource;
-import com.google.gerrit.server.config.DeleteTask;
import com.google.gerrit.server.config.TaskResource;
-import com.google.gerrit.server.config.TasksCollection;
import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.restapi.config.DeleteTask;
+import com.google.gerrit.server.restapi.config.TasksCollection;
import com.google.gerrit.sshd.AdminHighPriorityCommand;
import com.google.gerrit.sshd.SshCommand;
import com.google.inject.Inject;
diff --git a/java/com/google/gerrit/sshd/commands/ShowCaches.java b/java/com/google/gerrit/sshd/commands/ShowCaches.java
index 1ed7db3..a356f7f 100644
--- a/java/com/google/gerrit/sshd/commands/ShowCaches.java
+++ b/java/com/google/gerrit/sshd/commands/ShowCaches.java
@@ -26,18 +26,18 @@
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.config.ConfigResource;
-import com.google.gerrit.server.config.GetSummary;
-import com.google.gerrit.server.config.GetSummary.JvmSummaryInfo;
-import com.google.gerrit.server.config.GetSummary.MemSummaryInfo;
-import com.google.gerrit.server.config.GetSummary.SummaryInfo;
-import com.google.gerrit.server.config.GetSummary.TaskSummaryInfo;
-import com.google.gerrit.server.config.GetSummary.ThreadSummaryInfo;
-import com.google.gerrit.server.config.ListCaches;
-import com.google.gerrit.server.config.ListCaches.CacheInfo;
-import com.google.gerrit.server.config.ListCaches.CacheType;
import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.restapi.config.GetSummary;
+import com.google.gerrit.server.restapi.config.GetSummary.JvmSummaryInfo;
+import com.google.gerrit.server.restapi.config.GetSummary.MemSummaryInfo;
+import com.google.gerrit.server.restapi.config.GetSummary.SummaryInfo;
+import com.google.gerrit.server.restapi.config.GetSummary.TaskSummaryInfo;
+import com.google.gerrit.server.restapi.config.GetSummary.ThreadSummaryInfo;
+import com.google.gerrit.server.restapi.config.ListCaches;
+import com.google.gerrit.server.restapi.config.ListCaches.CacheInfo;
+import com.google.gerrit.server.restapi.config.ListCaches.CacheType;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.gerrit.sshd.SshDaemon;
diff --git a/java/com/google/gerrit/sshd/commands/ShowQueue.java b/java/com/google/gerrit/sshd/commands/ShowQueue.java
index 0296690..6d2fbb4 100644
--- a/java/com/google/gerrit/sshd/commands/ShowQueue.java
+++ b/java/com/google/gerrit/sshd/commands/ShowQueue.java
@@ -23,13 +23,13 @@
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.config.ConfigResource;
-import com.google.gerrit.server.config.ListTasks;
-import com.google.gerrit.server.config.ListTasks.TaskInfo;
import com.google.gerrit.server.git.WorkQueue;
import com.google.gerrit.server.git.WorkQueue.Task;
import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.restapi.config.ListTasks;
+import com.google.gerrit.server.restapi.config.ListTasks.TaskInfo;
import com.google.gerrit.sshd.AdminHighPriorityCommand;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
diff --git a/java/com/google/gerrit/testing/BUILD b/java/com/google/gerrit/testing/BUILD
index 2715c75..59102a9 100644
--- a/java/com/google/gerrit/testing/BUILD
+++ b/java/com/google/gerrit/testing/BUILD
@@ -25,6 +25,7 @@
"//java/com/google/gerrit/server:module",
"//java/com/google/gerrit/server/api",
"//java/com/google/gerrit/server/cache/h2",
+ "//java/com/google/gerrit/server/restapi",
"//java/com/google/gerrit/server/schema",
"//lib:gwtorm",
"//lib:h2",
diff --git a/javatests/com/google/gerrit/acceptance/api/change/ChangeIdIT.java b/javatests/com/google/gerrit/acceptance/api/change/ChangeIdIT.java
index e0fc358..0b7f340 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/ChangeIdIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/ChangeIdIT.java
@@ -17,10 +17,12 @@
import static com.google.common.truth.Truth.assertThat;
import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.GerritConfig;
import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.extensions.api.changes.ChangeApi;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.ChangeInput;
+import com.google.gerrit.extensions.restapi.DeprecatedIdentifierException;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.reviewdb.client.Project;
import org.junit.Before;
@@ -119,4 +121,27 @@
exception.expect(ResourceNotFoundException.class);
gApi.changes().id("I1234567890");
}
+
+ @Test
+ @GerritConfig(
+ name = "change.api.allowedIdentifier",
+ values = {"PROJECT_NUMERIC_ID", "NUMERIC_ID"}
+ )
+ public void deprecatedChangeIdReturnsBadRequest() throws Exception {
+ // project~changeNumber still works
+ ChangeApi cApi1 = gApi.changes().id(project.get(), changeInfo._number);
+ assertThat(cApi1.get().changeId).isEqualTo(changeInfo.changeId);
+ // Change number still works
+ ChangeApi cApi2 = gApi.changes().id(changeInfo._number);
+ assertThat(cApi2.get().changeId).isEqualTo(changeInfo.changeId);
+ // IHash throws
+ ChangeInfo ci =
+ gApi.changes().create(new ChangeInput(project.get(), "master", "different message")).get();
+ exception.expect(DeprecatedIdentifierException.class);
+ exception.expectMessage(
+ "The provided change identifier "
+ + ci.changeId
+ + " is deprecated. Use 'project~changeNumber' instead.");
+ gApi.changes().id(ci.changeId);
+ }
}
diff --git a/javatests/com/google/gerrit/acceptance/rest/config/BUILD b/javatests/com/google/gerrit/acceptance/rest/config/BUILD
index 825523d..8550423 100644
--- a/javatests/com/google/gerrit/acceptance/rest/config/BUILD
+++ b/javatests/com/google/gerrit/acceptance/rest/config/BUILD
@@ -4,4 +4,7 @@
srcs = glob(["*IT.java"]),
group = "rest_config",
labels = ["rest"],
+ deps = [
+ "//java/com/google/gerrit/server/restapi",
+ ],
)
diff --git a/javatests/com/google/gerrit/acceptance/rest/config/CacheOperationsIT.java b/javatests/com/google/gerrit/acceptance/rest/config/CacheOperationsIT.java
index 2ef74b4..65ed7e4 100644
--- a/javatests/com/google/gerrit/acceptance/rest/config/CacheOperationsIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/config/CacheOperationsIT.java
@@ -15,15 +15,15 @@
package com.google.gerrit.acceptance.rest.config;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.server.config.PostCaches.Operation.FLUSH;
-import static com.google.gerrit.server.config.PostCaches.Operation.FLUSH_ALL;
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
+import static com.google.gerrit.server.restapi.config.PostCaches.Operation.FLUSH;
+import static com.google.gerrit.server.restapi.config.PostCaches.Operation.FLUSH_ALL;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
import com.google.gerrit.common.data.GlobalCapability;
-import com.google.gerrit.server.config.ListCaches.CacheInfo;
-import com.google.gerrit.server.config.PostCaches;
+import com.google.gerrit.server.restapi.config.ListCaches.CacheInfo;
+import com.google.gerrit.server.restapi.config.PostCaches;
import java.util.Arrays;
import org.junit.Test;
diff --git a/javatests/com/google/gerrit/acceptance/rest/config/ConfirmEmailIT.java b/javatests/com/google/gerrit/acceptance/rest/config/ConfirmEmailIT.java
index f196684..7133580 100644
--- a/javatests/com/google/gerrit/acceptance/rest/config/ConfirmEmailIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/config/ConfirmEmailIT.java
@@ -15,8 +15,8 @@
package com.google.gerrit.acceptance.rest.config;
import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.server.config.ConfirmEmail;
import com.google.gerrit.server.mail.EmailTokenVerifier;
+import com.google.gerrit.server.restapi.config.ConfirmEmail;
import com.google.gerrit.testing.ConfigSuite;
import com.google.gwtjsonrpc.server.SignedToken;
import com.google.inject.Inject;
diff --git a/javatests/com/google/gerrit/acceptance/rest/config/FlushCacheIT.java b/javatests/com/google/gerrit/acceptance/rest/config/FlushCacheIT.java
index bc27fff..caecefa 100644
--- a/javatests/com/google/gerrit/acceptance/rest/config/FlushCacheIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/config/FlushCacheIT.java
@@ -20,7 +20,7 @@
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
import com.google.gerrit.common.data.GlobalCapability;
-import com.google.gerrit.server.config.ListCaches.CacheInfo;
+import com.google.gerrit.server.restapi.config.ListCaches.CacheInfo;
import org.junit.Test;
public class FlushCacheIT extends AbstractDaemonTest {
diff --git a/javatests/com/google/gerrit/acceptance/rest/config/GetCacheIT.java b/javatests/com/google/gerrit/acceptance/rest/config/GetCacheIT.java
index fe600cc..247d63b 100644
--- a/javatests/com/google/gerrit/acceptance/rest/config/GetCacheIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/config/GetCacheIT.java
@@ -18,8 +18,8 @@
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.server.config.ListCaches.CacheInfo;
-import com.google.gerrit.server.config.ListCaches.CacheType;
+import com.google.gerrit.server.restapi.config.ListCaches.CacheInfo;
+import com.google.gerrit.server.restapi.config.ListCaches.CacheType;
import org.junit.Test;
public class GetCacheIT extends AbstractDaemonTest {
diff --git a/javatests/com/google/gerrit/acceptance/rest/config/GetTaskIT.java b/javatests/com/google/gerrit/acceptance/rest/config/GetTaskIT.java
index 900b4be..6d2c6dfa 100644
--- a/javatests/com/google/gerrit/acceptance/rest/config/GetTaskIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/config/GetTaskIT.java
@@ -18,7 +18,7 @@
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.server.config.ListTasks.TaskInfo;
+import com.google.gerrit.server.restapi.config.ListTasks.TaskInfo;
import com.google.gson.reflect.TypeToken;
import java.util.List;
import org.junit.Test;
diff --git a/javatests/com/google/gerrit/acceptance/rest/config/KillTaskIT.java b/javatests/com/google/gerrit/acceptance/rest/config/KillTaskIT.java
index 7cd9584..c19f5d0 100644
--- a/javatests/com/google/gerrit/acceptance/rest/config/KillTaskIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/config/KillTaskIT.java
@@ -20,7 +20,7 @@
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.server.config.ListTasks.TaskInfo;
+import com.google.gerrit.server.restapi.config.ListTasks.TaskInfo;
import com.google.gson.reflect.TypeToken;
import java.util.List;
import java.util.Optional;
diff --git a/javatests/com/google/gerrit/acceptance/rest/config/ListCachesIT.java b/javatests/com/google/gerrit/acceptance/rest/config/ListCachesIT.java
index 4d48bf4..ae17be0 100644
--- a/javatests/com/google/gerrit/acceptance/rest/config/ListCachesIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/config/ListCachesIT.java
@@ -20,8 +20,8 @@
import com.google.common.collect.Ordering;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.server.config.ListCaches.CacheInfo;
-import com.google.gerrit.server.config.ListCaches.CacheType;
+import com.google.gerrit.server.restapi.config.ListCaches.CacheInfo;
+import com.google.gerrit.server.restapi.config.ListCaches.CacheType;
import com.google.gson.reflect.TypeToken;
import java.util.Arrays;
import java.util.List;
diff --git a/javatests/com/google/gerrit/acceptance/rest/config/ListTasksIT.java b/javatests/com/google/gerrit/acceptance/rest/config/ListTasksIT.java
index ee6411a..674ca79 100644
--- a/javatests/com/google/gerrit/acceptance/rest/config/ListTasksIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/config/ListTasksIT.java
@@ -18,7 +18,7 @@
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.server.config.ListTasks.TaskInfo;
+import com.google.gerrit.server.restapi.config.ListTasks.TaskInfo;
import com.google.gson.reflect.TypeToken;
import java.util.List;
import org.junit.Test;
diff --git a/javatests/com/google/gerrit/server/BUILD b/javatests/com/google/gerrit/server/BUILD
index 5bdfe39..a228ed6 100644
--- a/javatests/com/google/gerrit/server/BUILD
+++ b/javatests/com/google/gerrit/server/BUILD
@@ -42,6 +42,7 @@
"//java/com/google/gerrit/reviewdb:server",
"//java/com/google/gerrit/server",
"//java/com/google/gerrit/server/project/testing:project-test-util",
+ "//java/com/google/gerrit/server/restapi",
"//java/com/google/gerrit/server/schema",
"//java/com/google/gerrit/testing:gerrit-test-util",
"//java/org/eclipse/jgit:server",
diff --git a/javatests/com/google/gerrit/server/config/ListCapabilitiesTest.java b/javatests/com/google/gerrit/server/config/ListCapabilitiesTest.java
index 6fe48dc..bcba665 100644
--- a/javatests/com/google/gerrit/server/config/ListCapabilitiesTest.java
+++ b/javatests/com/google/gerrit/server/config/ListCapabilitiesTest.java
@@ -22,7 +22,8 @@
import com.google.gerrit.extensions.annotations.Exports;
import com.google.gerrit.extensions.config.CapabilityDefinition;
import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.server.config.ListCapabilities.CapabilityInfo;
+import com.google.gerrit.server.restapi.config.ListCapabilities;
+import com.google.gerrit.server.restapi.config.ListCapabilities.CapabilityInfo;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
diff --git a/lib/jgit/jgit.bzl b/lib/jgit/jgit.bzl
index e737f47..1723713 100644
--- a/lib/jgit/jgit.bzl
+++ b/lib/jgit/jgit.bzl
@@ -1,8 +1,8 @@
load("//tools/bzl:maven_jar.bzl", "GERRIT", "MAVEN_LOCAL", "MAVEN_CENTRAL", "maven_jar")
-_JGIT_VERS = "4.9.1.201712030800-r.66-gf8eff40ca"
+_JGIT_VERS = "4.9.2.201712150930-r.171-gfdbaa25db"
-_DOC_VERS = "4.9.1.201712030800-r" # Set to _JGIT_VERS unless using a snapshot
+_DOC_VERS = "4.9.2.201712150930-r" # Set to _JGIT_VERS unless using a snapshot
JGIT_DOC_URL = "http://download.eclipse.org/jgit/site/" + _DOC_VERS + "/apidocs"
@@ -26,28 +26,28 @@
name = "jgit_lib",
artifact = "org.eclipse.jgit:org.eclipse.jgit:" + _JGIT_VERS,
repository = _JGIT_REPO,
- sha1 = "0b974aa9c6c929c39c506ab2705d42f3d7da84c7",
- src_sha1 = "8884bef0415e092563b60b2167adbb09ac19d131",
+ sha1 = "29b822410b29286a09df728f8379e5cb8b1a486e",
+ src_sha1 = "5106b81910a057470cfd2584d9cb3502bcbebbc2",
unsign = True,
)
maven_jar(
name = "jgit_servlet",
artifact = "org.eclipse.jgit:org.eclipse.jgit.http.server:" + _JGIT_VERS,
repository = _JGIT_REPO,
- sha1 = "19c6bcdf5e0ba1907f6eeb18ae02d6ae04f630e3",
+ sha1 = "01f6718f6b629e28caad38e00190811b38574e74",
unsign = True,
)
maven_jar(
name = "jgit_archive",
artifact = "org.eclipse.jgit:org.eclipse.jgit.archive:" + _JGIT_VERS,
repository = _JGIT_REPO,
- sha1 = "0063dde3c017e05ee4e84ae16c97cb8817b91782",
+ sha1 = "9c9e9332e7dc724dbe1837e21feccd98bc25e6b4",
)
maven_jar(
name = "jgit_junit",
artifact = "org.eclipse.jgit:org.eclipse.jgit.junit:" + _JGIT_VERS,
repository = _JGIT_REPO,
- sha1 = "a9cb1e58df9bd876a2e81130f61a9bac0f182520",
+ sha1 = "4154c70b78b62035dad446332b24f7816b7a2a1b",
unsign = True,
)
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js
index 7c648d4..8cc7465 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js
@@ -134,10 +134,21 @@
_computeLabelValues(labelName, _labels) {
const result = [];
const labels = _labels.base;
- const t = labels[labelName];
- if (!t) { return result; }
- const approvals = t.all || [];
- const values = Object.keys(t.values);
+ const labelInfo = labels[labelName];
+ if (!labelInfo) { return result; }
+ if (!labelInfo.values) {
+ if (labelInfo.rejected || labelInfo.approved) {
+ const ok = labelInfo.approved || !labelInfo.rejected;
+ return [{
+ value: ok ? '👍️' : '👎️',
+ className: ok ? 'positive' : 'negative',
+ account: ok ? labelInfo.approved : labelInfo.rejected,
+ }];
+ }
+ return result;
+ }
+ const approvals = labelInfo.all || [];
+ const values = Object.keys(labelInfo.values);
for (const label of approvals) {
if (label.value && label.value != labels[labelName].default_value) {
let labelClassName;
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.html b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.html
index 7374bb7..868a147 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.html
@@ -664,6 +664,32 @@
});
suite('label colors', () => {
+ test('valueless label rejected', () => {
+ element.change = {
+ labels: {
+ 'Do-Not-Submit': {
+ rejected: {name: 'someone'},
+ },
+ },
+ };
+ flushAsynchronousOperations();
+ const labels = Polymer.dom(element.root).querySelectorAll('gr-label');
+ assert.isTrue(labels[0].classList.contains('negative'));
+ });
+
+ test('valueless label approved', () => {
+ element.change = {
+ labels: {
+ 'To-The-Infinity': {
+ approved: {name: 'someone'},
+ },
+ },
+ };
+ flushAsynchronousOperations();
+ const labels = Polymer.dom(element.root).querySelectorAll('gr-label');
+ assert.isTrue(labels[0].classList.contains('positive'));
+ });
+
test('-2 to +2', () => {
element.change = {
labels: {
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.html b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.html
index 7524abcb..3189cd4 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.html
@@ -45,22 +45,22 @@
background-color: #fff9c4;
}
.patchInfo-header {
+ align-items: center;
background-color: #fafafa;
border-top: 1px solid #ddd;
display: flex;
padding: 6px var(--default-horizontal-margin);
}
- .patchInfo-header-wrapper {
- align-items: center;
- display: flex;
- width: 100%;
- }
.patchInfo-left {
+ align-items: baseline;
+ display: flex;
+ }
+ .patchInfoContent {
align-items: center;
display: flex;
flex-wrap: wrap;
}
- .patchInfo-header-wrapper .container.latestPatchContainer {
+ .patchInfo-header .container.latestPatchContainer {
display: none;
}
.patchInfoOldPatchSet .container.latestPatchContainer {
@@ -75,7 +75,7 @@
.mobile {
display: none;
}
- .patchInfo-header-wrapper .container {
+ .patchInfo-header .container {
align-items: center;
display: flex;
}
@@ -137,6 +137,7 @@
display: initial;
}
.editLoaded .showOnEdit.flexContainer {
+ align-items: center;
display: flex;
}
.label {
@@ -150,9 +151,9 @@
}
</style>
<div class$="patchInfo-header [[_computeEditLoadedClass(editLoaded)]] [[_computePatchInfoClass(patchNum, allPatchSets)]]">
- <div class="patchInfo-header-wrapper">
- <div class="patchInfo-left">
- <h3 class="label">Files</h3>
+ <div class="patchInfo-left">
+ <h3 class="label">Files</h3>
+ <div class="patchInfoContent">
<gr-patch-range-select
id="rangeSelect"
change-comments="[[changeComments]]"
@@ -199,62 +200,62 @@
</template>
</span>
</div>
- <div class$="rightControls [[_computeExpandedClass(filesExpanded)]]">
- <span class="showOnEdit flexContainer">
- <gr-edit-controls id="editControls" change="[[change]]"></gr-edit-controls>
- <span class="separator"></span>
- </span>
- <span class="downloadContainer desktop">
- <gr-button link
- class="download"
- on-tap="_handleDownloadTap">Download</gr-button>
- </span>
- <template is="dom-if"
- if="[[_fileListActionsVisible(shownFileCount, _maxFilesForBulkActions)]]">
- <gr-button
- id="expandBtn"
- link
- on-tap="_expandAllDiffs">Expand All</gr-button>
- <gr-button
- id="collapseBtn"
- link
- on-tap="_collapseAllDiffs">Collapse All</gr-button>
- </template>
- <template is="dom-if"
- if="[[!_fileListActionsVisible(shownFileCount, _maxFilesForBulkActions)]]">
- <div class="warning">
- Bulk actions disabled because there are too many files.
- </div>
- </template>
- <div class="fileViewActions">
- <span class="separator"></span>
- <span>Diff Views:</span>
- <gr-button
- id="sideBySideBtn"
- link
- has-tooltip
- title="Side-by-side diff"
- class$="[[_computeSelectedClass(diffViewMode, _VIEW_MODES.SIDE_BY_SIDE)]]"
- on-tap="_handleSideBySideTap"><iron-icon icon="gr-icons:side-by-side"></iron-icon></gr-button>
- <gr-button
- id="unifiedBtn"
- link
- has-tooltip
- title="Unified dff"
- class$="[[_computeSelectedClass(diffViewMode, _VIEW_MODES.UNIFIED)]]"
- on-tap="_handleUnifiedTap"><iron-icon icon="gr-icons:unified"></iron-icon></gr-button>
- <span id="diffPrefsContainer"
- class="hideOnEdit"
- hidden$="[[_computePrefsButtonHidden(diffPrefs, loggedIn)]]"
- hidden>
- <gr-button
- link
- has-tooltip
- title="Diff preferences"
- class="prefsButton desktop"
- on-tap="_handlePrefsTap"><iron-icon icon="gr-icons:settings"></iron-icon></gr-button>
- </span>
+ </div>
+ <div class$="rightControls [[_computeExpandedClass(filesExpanded)]]">
+ <span class="showOnEdit flexContainer">
+ <gr-edit-controls id="editControls" change="[[change]]"></gr-edit-controls>
+ <span class="separator"></span>
+ </span>
+ <span class="downloadContainer desktop">
+ <gr-button link
+ class="download"
+ on-tap="_handleDownloadTap">Download</gr-button>
+ </span>
+ <template is="dom-if"
+ if="[[_fileListActionsVisible(shownFileCount, _maxFilesForBulkActions)]]">
+ <gr-button
+ id="expandBtn"
+ link
+ on-tap="_expandAllDiffs">Expand All</gr-button>
+ <gr-button
+ id="collapseBtn"
+ link
+ on-tap="_collapseAllDiffs">Collapse All</gr-button>
+ </template>
+ <template is="dom-if"
+ if="[[!_fileListActionsVisible(shownFileCount, _maxFilesForBulkActions)]]">
+ <div class="warning">
+ Bulk actions disabled because there are too many files.
</div>
+ </template>
+ <div class="fileViewActions">
+ <span class="separator"></span>
+ <span>Diff Views:</span>
+ <gr-button
+ id="sideBySideBtn"
+ link
+ has-tooltip
+ title="Side-by-side diff"
+ class$="[[_computeSelectedClass(diffViewMode, _VIEW_MODES.SIDE_BY_SIDE)]]"
+ on-tap="_handleSideBySideTap"><iron-icon icon="gr-icons:side-by-side"></iron-icon></gr-button>
+ <gr-button
+ id="unifiedBtn"
+ link
+ has-tooltip
+ title="Unified dff"
+ class$="[[_computeSelectedClass(diffViewMode, _VIEW_MODES.UNIFIED)]]"
+ on-tap="_handleUnifiedTap"><iron-icon icon="gr-icons:unified"></iron-icon></gr-button>
+ <span id="diffPrefsContainer"
+ class="hideOnEdit"
+ hidden$="[[_computePrefsButtonHidden(diffPrefs, loggedIn)]]"
+ hidden>
+ <gr-button
+ link
+ has-tooltip
+ title="Diff preferences"
+ class="prefsButton desktop"
+ on-tap="_handlePrefsTap"><iron-icon icon="gr-icons:settings"></iron-icon></gr-button>
+ </span>
</div>
</div>
</div>
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
index c4120eb..44c7e2d 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
@@ -819,6 +819,12 @@
* @param {!Array} record The splice record in the expanded paths list.
*/
_expandedPathsChanged(record) {
+ // Clear content for any diffs that are not open so if they get re-opened
+ // the stale content does not flash before it is cleared and reloaded.
+ const collapsedDiffs = this.diffs.filter(diff =>
+ this._expandedFilePaths.indexOf(diff.path) === -1);
+ this._clearCollapsedDiffs(collapsedDiffs);
+
if (!record) { return; }
this.filesExpanded = this._computeExpandedFiles(
@@ -843,6 +849,12 @@
this.$.diffCursor.handleDiffUpdate();
},
+ _clearCollapsedDiffs(collapsedDiffs) {
+ for (const diff of collapsedDiffs) {
+ diff.clearDiffContent();
+ }
+ },
+
/**
* Given an array of paths and a NodeList of diff elements, render the diff
* for each path in order, awaiting the previous render to complete before
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
index 0a45fe3..4c1326a 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
@@ -831,39 +831,44 @@
test('_togglePathExpanded', () => {
const path = 'path/to/my/file.txt';
- element.files = [{__path: path}];
- const renderStub = sandbox.stub(element, '_renderInOrder')
- .returns(Promise.resolve());
+ element._files = [{__path: path}];
+ const renderSpy = sandbox.spy(element, '_renderInOrder');
+ const collapseStub = sandbox.stub(element, '_clearCollapsedDiffs');
assert.equal(element._expandedFilePaths.length, 0);
element._togglePathExpanded(path);
flushAsynchronousOperations();
+ assert.equal(collapseStub.lastCall.args[0].length, 0);
- assert.equal(renderStub.callCount, 1);
+ assert.equal(renderSpy.callCount, 1);
assert.include(element._expandedFilePaths, path);
element._togglePathExpanded(path);
flushAsynchronousOperations();
- assert.equal(renderStub.callCount, 2);
+ assert.equal(renderSpy.callCount, 2);
assert.notInclude(element._expandedFilePaths, path);
+ assert.equal(collapseStub.lastCall.args[0].length, 1);
});
- test('collapseAllDiffs', () => {
- sandbox.stub(element, '_renderInOrder')
- .returns(Promise.resolve());
+ test('expandAllDiffs and collapseAllDiffs', () => {
+ const collapseStub = sandbox.stub(element, '_clearCollapsedDiffs');
const cursorUpdateStub = sandbox.stub(element.$.diffCursor,
'handleDiffUpdate');
const path = 'path/to/my/file.txt';
- element.files = [{__path: path}];
- element._expandedFilePaths = [path];
- element._showInlineDiffs = true;
+ element._files = [{__path: path}];
+ element.expandAllDiffs();
+ flushAsynchronousOperations();
+ assert.isTrue(element._showInlineDiffs);
+ assert.isTrue(cursorUpdateStub.calledOnce);
+ assert.equal(collapseStub.lastCall.args[0].length, 0);
element.collapseAllDiffs();
flushAsynchronousOperations();
assert.equal(element._expandedFilePaths.length, 0);
assert.isFalse(element._showInlineDiffs);
- assert.isTrue(cursorUpdateStub.calledOnce);
+ assert.isTrue(cursorUpdateStub.calledTwice);
+ assert.equal(collapseStub.lastCall.args[0].length, 1);
});
test('_expandedPathsChanged', done => {
diff --git a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.html b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.html
index b11c230..8324ab2 100644
--- a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.html
+++ b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.html
@@ -73,10 +73,10 @@
--button-background-color: var(--vote-color-min);
}
iron-selector > gr-button.iron-selected.negative {
- --button-background-color: #var(--vote-color-negative);;
+ --button-background-color: var(--vote-color-negative);
}
iron-selector > gr-button.iron-selected.neutral {
- --button-background-color: var(--vote-color-neutral);;
+ --button-background-color: var(--vote-color-neutral);
}
.placeholder {
display: inline-block;
diff --git a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.js b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.js
index fff3580..968766d 100644
--- a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.js
+++ b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.js
@@ -142,7 +142,9 @@
},
_computeLabelValueTitle(labels, label, value) {
- return labels[label] && labels[label].values[value];
+ return labels[label] &&
+ labels[label].values &&
+ labels[label].values[value];
},
});
})();
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html
index d2effdd..335cc49 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html
@@ -45,6 +45,7 @@
.titleText::before {
background-image: var(--header-icon);
background-size: var(--header-icon-size) var(--header-icon-size);
+ background-repeat: no-repeat;
content: "";
display: inline-block;
height: var(--header-icon-size);
diff --git a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html
index b59ad9d..f8c7e74 100644
--- a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html
+++ b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html
@@ -72,14 +72,15 @@
View: {
ADMIN: 'admin',
- CHANGE: 'change',
AGREEMENTS: 'agreements',
+ CHANGE: 'change',
DASHBOARD: 'dashboard',
DIFF: 'diff',
EDIT: 'edit',
+ GROUP: 'group',
+ PLUGIN_SCREEN: 'plugin-screen',
SEARCH: 'search',
SETTINGS: 'settings',
- GROUP: 'group',
},
GroupDetailView: {
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router.js b/polygerrit-ui/app/elements/core/gr-router/gr-router.js
index 5d26cb6..6d7e78d 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router.js
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router.js
@@ -130,6 +130,8 @@
// Matches /c/<changeNum>/ /<URL tail>
// Catches improperly encoded URLs (context: Issue 7100)
IMPROPERLY_ENCODED_PLUS: /^\/c\/(.+)\/\ \/(.+)$/,
+
+ PLUGIN_SCREEN: /^\/x\/([\w-]+)\/([\w-]+)\/?/,
};
/**
@@ -621,6 +623,14 @@
page((ctx, next) => {
document.body.scrollTop = 0;
+ if (ctx.hash.match(RoutePattern.PLUGIN_SCREEN)) {
+ // Redirect all urls using hash #/x/plugin/screen to /x/plugin/screen
+ // This is needed to allow plugins to add basic #/x/ screen links to
+ // any location.
+ this._redirect(ctx.hash);
+ return;
+ }
+
// Fire asynchronously so that the URL is changed by the time the event
// is processed.
this.async(() => {
@@ -748,6 +758,8 @@
this._mapRoute(RoutePattern.IMPROPERLY_ENCODED_PLUS,
'_handleImproperlyEncodedPlusRoute');
+ this._mapRoute(RoutePattern.PLUGIN_SCREEN, '_handlePluginScreen');
+
// Note: this route should appear last so it only catches URLs unmatched
// by other patterns.
this._mapRoute(RoutePattern.DEFAULT, '_handleDefaultRoute');
@@ -1276,6 +1288,13 @@
this._redirect(`/c/${ctx.params[0]}/+/${ctx.params[1]}${hash}`);
},
+ _handlePluginScreen(ctx) {
+ const view = Gerrit.Nav.View.PLUGIN_SCREEN;
+ const plugin = ctx.params[0];
+ const screen = ctx.params[1];
+ this._setParams({view, plugin, screen});
+ },
+
/**
* Catchall route for when no other route is matched.
*/
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html b/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html
index 7159e0a..2f29667 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html
@@ -168,6 +168,7 @@
'_handleTagListFilterOffsetRoute',
'_handleTagListFilterRoute',
'_handleTagListOffsetRoute',
+ '_handlePluginScreen',
];
// Handler names that check authentication themselves, and thus don't need
@@ -1332,6 +1333,16 @@
assert.deepEqual(setParamsStub.lastCall.args[0], appParams);
});
});
+
+ test('_handlePluginScreen', () => {
+ const ctx = {params: ['foo', 'bar']};
+ assertDataToParams(ctx, '_handlePluginScreen', {
+ view: Gerrit.Nav.View.PLUGIN_SCREEN,
+ plugin: 'foo',
+ screen: 'bar',
+ });
+ assert.isFalse(redirectStub.called);
+ });
});
suite('_parseQueryString', () => {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
index 5f3269a..75ed70c 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
@@ -176,7 +176,7 @@
this.clearBlame();
this._safetyBypass = null;
this._showWarning = false;
- this._clearDiffContent();
+ this.clearDiffContent();
const promises = [];
@@ -615,7 +615,7 @@
return this.prefs;
},
- _clearDiffContent() {
+ clearDiffContent() {
this.$.diffTable.innerHTML = null;
},
diff --git a/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.html b/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.html
new file mode 100644
index 0000000..b5573ab
--- /dev/null
+++ b/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.html
@@ -0,0 +1,43 @@
+<!--
+Copyright (C) 2017 The Android Open Source Project
+
+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.
+-->
+
+<link rel="import" href="../../../bower_components/polymer/polymer.html">
+<link rel="import" href="../../../styles/shared-styles.html">
+
+<dom-module id="gr-default-editor">
+ <template>
+ <style include="shared-styles">
+ textarea {
+ border: 1px solid #ddd;
+ border-radius: 3px;
+ box-sizing: border-box;
+ font-family: var(--monospace-font-family);
+ min-height: 60vh;
+ resize: none;
+ white-space: pre;
+ width: 100%;
+ }
+ textarea:focus {
+ outline: none;
+ }
+ </style>
+ <textarea
+ id="textarea"
+ value="[[fileContent]]"
+ on-input="_handleTextareaInput"></textarea>
+ </template>
+ <script src="gr-default-editor.js"></script>
+</dom-module>
\ No newline at end of file
diff --git a/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.js b/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.js
new file mode 100644
index 0000000..f30f9fa
--- /dev/null
+++ b/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.js
@@ -0,0 +1,35 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// 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.
+(function() {
+ 'use strict';
+
+ Polymer({
+ is: 'gr-default-editor',
+
+ /**
+ * Fired when the content of the editor changes.
+ *
+ * @event content-change
+ */
+
+ properties: {
+ fileContent: String,
+ },
+
+ _handleTextareaInput(e) {
+ this.dispatchEvent(new CustomEvent('content-change',
+ {detail: {value: e.target.value}, bubbles: true}));
+ },
+ });
+})();
\ No newline at end of file
diff --git a/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor_test.html b/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor_test.html
new file mode 100644
index 0000000..43ec9e5
--- /dev/null
+++ b/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor_test.html
@@ -0,0 +1,55 @@
+<!--
+Copyright (C) 2017 The Android Open Source Project
+
+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.
+-->
+
+<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+<title>gr-default-editor</title>
+
+<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
+<script src="../../../bower_components/web-component-tester/browser.js"></script>
+<link rel="import" href="../../../test/common-test-setup.html"/>
+
+<link rel="import" href="gr-default-editor.html">
+
+<script>void(0);</script>
+
+<test-fixture id="basic">
+ <template>
+ <gr-default-editor></gr-default-editor>
+ </template>
+</test-fixture>
+
+<script>
+ suite('gr-default-editor tests', () => {
+ let element;
+
+ setup(() => {
+ element = fixture('basic');
+ element.fileContent = '';
+ });
+
+ test('fires content-change event', done => {
+ const contentChangedHandler = e => {
+ assert.equal(e.detail.value, 'test');
+ done();
+ };
+ const textarea = element.$.textarea;
+ element.addEventListener('content-change', contentChangedHandler);
+ textarea.value = 'test';
+ textarea.dispatchEvent(new CustomEvent('input',
+ {target: textarea, bubbles: true}));
+ });
+ });
+</script>
\ No newline at end of file
diff --git a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.html b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.html
index 3042e76..10da09b 100644
--- a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.html
+++ b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.html
@@ -26,9 +26,9 @@
<link rel="import" href="../../shared/gr-editable-label/gr-editable-label.html">
<link rel="import" href="../../shared/gr-fixed-panel/gr-fixed-panel.html">
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
+<link rel="import" href="../gr-default-editor/gr-default-editor.html">
<link rel="import" href="../../../styles/shared-styles.html">
-
<dom-module id="gr-editor-view">
<template>
<style include="shared-styles">
@@ -54,19 +54,6 @@
.textareaWrapper {
margin: var(--default-horizontal-margin);
}
- .textareaWrapper textarea {
- border: 1px solid #ddd;
- border-radius: 3px;
- box-sizing: border-box;
- font-family: var(--monospace-font-family);
- min-height: 60vh;
- resize: none;
- white-space: pre;
- width: 100%;
- }
- .textareaWrapper textarea:focus {
- outline: none;
- }
.textareaWrapper .editButtons {
display: none;
}
@@ -96,11 +83,11 @@
</header>
</gr-fixed-panel>
<div class="textareaWrapper">
- <gr-endpoint-decorator name="editor">
+ <gr-endpoint-decorator id="editorEndpoint" name="editor">
<gr-endpoint-param name="fileContent" value="[[_newContent]]"></gr-endpoint-param>
<gr-endpoint-param name="prefs" value="[[_prefs]]"></gr-endpoint-param>
<gr-endpoint-param name="fileType" value="[[_type]]"></gr-endpoint-param>
- <textarea value="{{_newContent::input}}" id="file"></textarea>
+ <gr-default-editor id="file" file-content="[[_newContent]]"></gr-default-editor>
</gr-endpoint-decorator>
</div>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
diff --git a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.js b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.js
index f31608d..447c258 100644
--- a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.js
+++ b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.js
@@ -53,6 +53,10 @@
Gerrit.PathListBehavior,
],
+ listeners: {
+ 'content-change': '_handleContentChange',
+ },
+
attached() {
this._getEditPrefs().then(prefs => { this._prefs = prefs; });
},
@@ -132,5 +136,9 @@
// TODO(kaspern): Add a confirm dialog if there are unsaved changes.
this._viewEditInChangeView();
},
+
+ _handleContentChange(e) {
+ if (e.detail.value) { this.set('_newContent', e.detail.value); }
+ },
});
})();
diff --git a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.html b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.html
index 05a247a..fa9bcec 100644
--- a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.html
+++ b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.html
@@ -114,6 +114,17 @@
});
});
+ test('reacts to content-change event', () => {
+ element._newContent = 'test';
+ element.$.editorEndpoint.dispatchEvent(new CustomEvent('content-change', {
+ bubbles: true,
+ detail: {value: 'new content value'},
+ }));
+ flushAsynchronousOperations();
+
+ assert.equal(element._newContent, 'new content value');
+ });
+
suite('edit file content', () => {
const originalText = 'file text';
const newText = 'file text changed';
@@ -127,7 +138,7 @@
});
test('initial load', () => {
- assert.equal(element.$.file.value, originalText);
+ assert.equal(element.$.file.fileContent, originalText);
assert.isTrue(element.$.save.hasAttribute('disabled'));
});
@@ -137,7 +148,6 @@
element._newContent = newText;
flushAsynchronousOperations();
- assert.equal(element.$.file.value, newText);
assert.isFalse(element.$.save.hasAttribute('disabled'));
MockInteractions.tap(element.$.save);
@@ -157,7 +167,6 @@
element._newContent = newText;
flushAsynchronousOperations();
- assert.equal(element.$.file.value, newText);
assert.isFalse(element.$.save.hasAttribute('disabled'));
MockInteractions.tap(element.$.save);
@@ -174,7 +183,6 @@
element._newContent = newText;
flushAsynchronousOperations();
- assert.equal(element.$.file.value, newText);
assert.isFalse(element.$.save.hasAttribute('disabled'));
MockInteractions.tap(element.$.cancel);
diff --git a/polygerrit-ui/app/elements/gr-app.html b/polygerrit-ui/app/elements/gr-app.html
index 035e906..95cddab 100644
--- a/polygerrit-ui/app/elements/gr-app.html
+++ b/polygerrit-ui/app/elements/gr-app.html
@@ -48,6 +48,7 @@
<link rel="import" href="./diff/gr-diff-view/gr-diff-view.html">
<link rel="import" href="./edit/gr-editor-view/gr-editor-view.html">
<link rel="import" href="./plugins/gr-endpoint-decorator/gr-endpoint-decorator.html">
+<link rel="import" href="./plugins/gr-endpoint-param/gr-endpoint-param.html">
<link rel="import" href="./plugins/gr-external-style/gr-external-style.html">
<link rel="import" href="./plugins/gr-plugin-host/gr-plugin-host.html">
<link rel="import" href="./settings/gr-cla-view/gr-cla-view.html">
@@ -172,6 +173,11 @@
<gr-admin-view path="[[_path]]"
params=[[params]]></gr-admin-view>
</template>
+ <template is="dom-if" if="[[_showPluginScreen]]" restamp="true">
+ <gr-endpoint-decorator name="[[_pluginScreenName]]">
+ <gr-endpoint-param name="token" value="[[params.screen]]"></gr-endpoint-param>
+ </gr-endpoint-decorator>
+ </template>
<template is="dom-if" if="[[_showCLAView]]" restamp="true">
<gr-cla-view path="[[_path]]"></gr-cla-view>
</template>
diff --git a/polygerrit-ui/app/elements/gr-app.js b/polygerrit-ui/app/elements/gr-app.js
index 637cce5..bb24c74 100644
--- a/polygerrit-ui/app/elements/gr-app.js
+++ b/polygerrit-ui/app/elements/gr-app.js
@@ -36,7 +36,7 @@
properties: {
/**
- * @type {{ query: string, view: string }}
+ * @type {{ query: string, view: string, screen: string }}
*/
params: Object,
keyEventTarget: {
@@ -72,6 +72,7 @@
_showAdminView: Boolean,
_showCLAView: Boolean,
_showEditorView: Boolean,
+ _showPluginScreen: Boolean,
/** @type {?} */
_viewState: Object,
/** @type {?} */
@@ -79,6 +80,10 @@
_lastSearchPage: String,
_path: String,
_isShadowDom: Boolean,
+ _pluginScreenName: {
+ type: String,
+ computed: '_computePluginScreenName(params)',
+ },
},
listeners: {
@@ -160,6 +165,14 @@
view === Gerrit.Nav.View.GROUP);
this.set('_showCLAView', view === Gerrit.Nav.View.AGREEMENTS);
this.set('_showEditorView', view === Gerrit.Nav.View.EDIT);
+ const isPluginScreen = view === Gerrit.Nav.View.PLUGIN_SCREEN;
+ this.set('_showPluginScreen', false);
+ // Navigation within plugin screens does not restamp gr-endpoint-decorator
+ // because _showPluginScreen value does not change. To force restamp,
+ // change _showPluginScreen value between true and false.
+ if (isPluginScreen) {
+ this.async(() => this.set('_showPluginScreen', true), 1);
+ }
if (this.params.justRegistered) {
this.$.registration.open();
}
@@ -282,5 +295,9 @@
Gerrit.Nav.navigateToStatusSearch(status);
}
},
+
+ _computePluginScreenName({plugin, screen}) {
+ return Gerrit._getPluginScreenName(plugin, screen);
+ },
});
})();
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html
index 9c11522..504504e 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html
@@ -456,5 +456,33 @@
assert.isFalse(stub.called);
});
});
+
+ suite('screen', () => {
+ test('screenUrl()', () => {
+ sandbox.stub(Gerrit.BaseUrlBehavior, 'getBaseUrl').returns('/base');
+ assert.equal(plugin.screenUrl(), 'http://test.com/base/x/testplugin');
+ assert.equal(
+ plugin.screenUrl('foo'), 'http://test.com/base/x/testplugin/foo');
+ });
+
+ test('deprecated works', () => {
+ const stub = sandbox.stub();
+ const hookStub = {onAttached: sandbox.stub()};
+ sandbox.stub(plugin, 'hook').returns(hookStub);
+ plugin.deprecated.screen('foo', stub);
+ assert.isTrue(plugin.hook.calledWith('testplugin-screen-foo'));
+ const fakeEl = {style: {display: ''}};
+ hookStub.onAttached.callArgWith(0, fakeEl);
+ assert.isTrue(stub.called);
+ assert.equal(fakeEl.style.display, 'none');
+ });
+
+ test('works', () => {
+ sandbox.stub(plugin, 'registerCustomComponent');
+ plugin.screen('foo', 'some-module');
+ assert.isTrue(plugin.registerCustomComponent.calledWith(
+ 'testplugin-screen-foo', 'some-module'));
+ });
+ });
});
</script>
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js
index af7c155..2950c05 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js
@@ -23,7 +23,7 @@
*/
const plugins = {};
- const stubbedMethods = ['_loadedGwt', 'screen', 'settingsScreen', 'panel'];
+ const stubbedMethods = ['_loadedGwt', 'settingsScreen', 'panel'];
const GWT_PLUGIN_STUB = {};
for (const name of stubbedMethods) {
GWT_PLUGIN_STUB[name] = warnNotSupported.bind(null, name);
@@ -92,7 +92,11 @@
url.href, '— Unable to determine name.');
return;
}
- return pathname.split('/')[2];
+ // Pathname should normally look like this:
+ // /plugins/PLUGINNAME/static/SCRIPTNAME.html
+ // Or, for app/samples:
+ // /plugins/PLUGINNAME.html
+ return pathname.split('/')[2].split('.')[0];
}
function Plugin(opt_url) {
@@ -105,8 +109,9 @@
}
this.deprecated = {
install: deprecatedAPI.install.bind(this),
- popup: deprecatedAPI.popup.bind(this),
onAction: deprecatedAPI.onAction.bind(this),
+ popup: deprecatedAPI.popup.bind(this),
+ screen: deprecatedAPI.screen.bind(this),
};
this._url = new URL(opt_url);
@@ -159,6 +164,13 @@
this._name + (opt_path || '/');
};
+ Plugin.prototype.screenUrl = function(opt_screenName) {
+ const origin = this._url.origin;
+ const base = Gerrit.BaseUrlBehavior.getBaseUrl();
+ const tokenPart = opt_screenName ? '/' + opt_screenName : '';
+ return `${origin}${base}/x/${this.getPluginName()}${tokenPart}`;
+ };
+
Plugin.prototype._send = function(method, url, opt_callback, opt_payload) {
return send(method, this.url(url), opt_callback, opt_payload);
};
@@ -237,6 +249,15 @@
return api.open();
};
+ Plugin.prototype.screen = function(screenName, opt_moduleName) {
+ if (opt_moduleName && typeof opt_moduleName !== 'string') {
+ throw new Error('deprecated, use deprecated.screen');
+ }
+ return this.registerCustomComponent(
+ Gerrit._getPluginScreenName(this.getPluginName(), screenName),
+ opt_moduleName);
+ };
+
const deprecatedAPI = {
install() {
console.log('Installing deprecated APIs is deprecated!');
@@ -277,6 +298,29 @@
});
},
+ screen(pattern, callback) {
+ console.warn('plugin.deprecated.screen is deprecated,' +
+ ' use plugin.screen instead!');
+ if (pattern instanceof RegExp) {
+ console.error('deprecated.screen() does not support RegExp. ' +
+ 'Please use strings for patterns.');
+ return;
+ }
+ this.hook(Gerrit._getPluginScreenName(this.getPluginName(), pattern))
+ .onAttached(el => {
+ el.style.display = 'none';
+ callback({
+ body: el,
+ token: el.token,
+ onUnload: () => {},
+ setTitle: () => {},
+ setWindowTitle: () => {},
+ show: () => {
+ el.style.display = 'initial';
+ },
+ });
+ });
+ },
};
const Gerrit = window.Gerrit || {};
@@ -420,5 +464,9 @@
return Gerrit._pluginsPending === 0;
};
+ Gerrit._getPluginScreenName = function(pluginName, screenName) {
+ return `${pluginName}-screen-${screenName}`;
+ };
+
window.Gerrit = Gerrit;
})(window);
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
index 6c052ae..5118d70 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
@@ -1344,7 +1344,7 @@
// X-FYI-Content-Type header of the response.
const type = res.headers.get('X-FYI-Content-Type');
return this.getResponseObject(res).then(content => {
- return {content, type};
+ return {content, type, ok: true};
});
});
},
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
index bf238af..6542bb6 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
@@ -1199,7 +1199,8 @@
.returns(Promise.resolve('new content'));
return element.getFileInChangeEdit('1', 'test/path').then(res => {
- assert.deepEqual(res, {content: 'new content', type: 'text/java'});
+ assert.deepEqual(res,
+ {content: 'new content', type: 'text/java', ok: true});
});
});
});
diff --git a/polygerrit-ui/app/samples/some-screen.html b/polygerrit-ui/app/samples/some-screen.html
new file mode 100644
index 0000000..de29315
--- /dev/null
+++ b/polygerrit-ui/app/samples/some-screen.html
@@ -0,0 +1,49 @@
+<dom-module id="some-screen">
+ <script>
+ Gerrit.install(plugin => {
+ // Recommended approach for screen() API.
+ plugin.screen('main', 'some-screen-main');
+
+ const mainUrl = plugin.screenUrl('main');
+
+ // Support for deprecated screen API.
+ plugin.deprecated.screen('foo', ({token, body, show}) => {
+ body.innerHTML = `This is a plugin screen at ${token}<br/>` +
+ `<a href="${mainUrl}">Go to main plugin screen</a>`;
+ show();
+ });
+
+ // Quick and dirty way to get something on screen.
+ plugin.screen('bar').onAttached(el => {
+ el.innerHTML = `This is a plugin screen at ${el.token}<br/>` +
+ `<a href="${mainUrl}">Go to main plugin screen</a>`;
+ });
+
+ // Add a "Plugin screen" link to the change view screen.
+ plugin.hook('change-metadata-item').onAttached(el => {
+ el.innerHTML = `<a href="${mainUrl}">Plugin screen</a>`;
+ });
+ });
+ </script>
+</dom-module>
+
+<dom-module id="some-screen-main">
+ <template>
+ This is the <b>main</b> plugin screen at [[token]]
+ <ul>
+ <li><a href$="[[rootUrl]]/foo">via deprecated</a></li>
+ <li><a href$="[[rootUrl]]/bar">without component</a></li>
+ </ul>
+ </template>
+ <script>
+ Polymer({
+ is: 'some-screen-main',
+ properties: {
+ rootUrl: String,
+ },
+ attached() {
+ this.rootUrl = `${this.plugin.screenUrl()}`;
+ },
+ });
+ </script>
+</dom-module>
diff --git a/polygerrit-ui/app/test/index.html b/polygerrit-ui/app/test/index.html
index 68dbfd6..f903790 100644
--- a/polygerrit-ui/app/test/index.html
+++ b/polygerrit-ui/app/test/index.html
@@ -104,6 +104,7 @@
'diff/gr-selection-action-box/gr-selection-action-box_test.html',
'diff/gr-syntax-layer/gr-syntax-layer_test.html',
'diff/gr-syntax-lib-loader/gr-syntax-lib-loader_test.html',
+ 'edit/gr-default-editor/gr-default-editor_test.html',
'edit/gr-edit-controls/gr-edit-controls_test.html',
'edit/gr-edit-file-controls/gr-edit-file-controls_test.html',
'edit/gr-editor-view/gr-editor-view_test.html',
diff --git a/polygerrit-ui/server.go b/polygerrit-ui/server.go
index 5be1c60..ece071c 100644
--- a/polygerrit-ui/server.go
+++ b/polygerrit-ui/server.go
@@ -200,7 +200,7 @@
// Any path prefixes that should resolve to index.html.
var (
- fePaths = []string{"/q/", "/c/", "/p/", "/dashboard/", "/admin/"}
+ fePaths = []string{"/q/", "/c/", "/p/", "/x/", "/dashboard/", "/admin/"}
issueNumRE = regexp.MustCompile(`^\/\d+\/?$`)
)