Merge changes from topic "auto-annotations"
* changes:
ConfigAnnotationParser: Use AutoAnnotation to construct GerritConfig
Replace ApproveOption with AutoAnnotation
Move newOption method to a new public class
CmdLineParser: Replace HelpOption with AutoAnnotation
CmdLineParser: Replace PrefixedOption with AutoAnnotation
Implement @Export with AutoAnnotation
diff --git a/.gitignore b/.gitignore
index 8cd43dd..c0e14ab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,6 +32,18 @@
/local.properties
/node_modules/
/package-lock.json
-/plugins/cookbook-plugin/
+/plugins/*
+!/plugins/BUILD
+!/plugins/codemirror-editor
+!/plugins/commit-message-length-validator
+!/plugins/delete-project
+!/plugins/download-commands
+!/plugins/external_plugin_deps.bzl
+!/plugins/gitiles
+!/plugins/hooks
+!/plugins/replication
+!/plugins/reviewnotes
+!/plugins/singleusergroup
+!/plugins/webhooks
/test_site
/tools/format
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 8479a8e..c0f195d 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -979,6 +979,11 @@
Caches parsed `rules.pl` contents for each project. This cache uses the same
size as the `projects` cache, and cannot be configured independently.
+cache `"pure_revert"`::
++
+Result of checking if one change or commit is a pure/clean revert of
+another.
+
cache `"sshkeys"`::
+
Caches unpacked versions of user SSH keys, so the internal SSH daemon
diff --git a/Documentation/config-plugins.txt b/Documentation/config-plugins.txt
index 3a80910..81c9927 100644
--- a/Documentation/config-plugins.txt
+++ b/Documentation/config-plugins.txt
@@ -234,6 +234,17 @@
link:https://gerrit.googlesource.com/plugins/changemessage/+doc/master/src/main/resources/Documentation/config.md[
Configuration]
+[[checks]]
+=== checks
+
+The checks plugin provides a REST API and UI extensions for integrating
+CI systems with Gerrit.
+
+link:https://gerrit-review.googlesource.com/admin/repos/plugins/checks[
+Project] |
+link:https://gerrit.googlesource.com/plugins/checks/+doc/master/src/main/resources/Documentation/about.md[
+Plugin Documentation]]
+
[[egit]]
=== egit
diff --git a/Documentation/dev-plugins.txt b/Documentation/dev-plugins.txt
index 1d10025..1e54cbf 100644
--- a/Documentation/dev-plugins.txt
+++ b/Documentation/dev-plugins.txt
@@ -718,7 +718,6 @@
[source,java]
----
-@Singleton
public class SampleOperator
implements ChangeQueryBuilder.ChangeOperatorFactory {
public static class MyPredicate extends OperatorChangePredicate<ChangeData> {
@@ -751,7 +750,6 @@
new `has:sample_pluginName` operand is shown below:
====
- @Singleton
public class SampleHasOperand implements ChangeHasOperandFactory {
public static class Module extends AbstractModule {
@Override
diff --git a/WORKSPACE b/WORKSPACE
index a984c41..b4b1a64 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -156,18 +156,18 @@
sha1 = "94ad16d728b374d65bd897625f3fbb3da223a2b6",
)
-FLOGGER_VERS = "0.3.1"
+FLOGGER_VERS = "0.4"
maven_jar(
name = "flogger",
artifact = "com.google.flogger:flogger:" + FLOGGER_VERS,
- sha1 = "585030fe1ec709760cbef997a459729fb965df0e",
+ sha1 = "9c8863dcc913b56291c0c88e6d4ca9715b43df98",
)
maven_jar(
name = "flogger-log4j-backend",
artifact = "com.google.flogger:flogger-log4j-backend:" + FLOGGER_VERS,
- sha1 = "d5085e3996bddc4b105d53b886190cc9a8811a9e",
+ sha1 = "17aa5e31daa1354187e14b6978597d630391c028",
)
maven_jar(
@@ -1054,12 +1054,12 @@
sha1 = "76716d529710fc03d1d429b43e3cedd4419f78d4",
)
-# When upgrading elasticsearch-rest-client, also upgrade http-niocore
+# When upgrading elasticsearch-rest-client, also upgrade httpcore-nio
# and httpasyncclient as necessary.
maven_jar(
name = "elasticsearch-rest-client",
- artifact = "org.elasticsearch.client:elasticsearch-rest-client:6.6.1",
- sha1 = "dc1c9284ffca28cd169fae2776c3956e90b76c00",
+ artifact = "org.elasticsearch.client:elasticsearch-rest-client:6.6.2",
+ sha1 = "2c429141e488091c358aa43b1e6873d457464c5d",
)
JACKSON_VERSION = "2.9.8"
@@ -1070,18 +1070,18 @@
sha1 = "0f5a654e4675769c716e5b387830d19b501ca191",
)
-TESTCONTAINERS_VERSION = "1.10.3"
+TESTCONTAINERS_VERSION = "1.10.7"
maven_jar(
name = "testcontainers",
artifact = "org.testcontainers:testcontainers:" + TESTCONTAINERS_VERSION,
- sha1 = "e561ce99fc616b383d85f35ce881e58e8de59ae7",
+ sha1 = "e7575fedfd010ca1ad80c8c9bf971a8057b1ff8a",
)
maven_jar(
name = "testcontainers-elasticsearch",
artifact = "org.testcontainers:elasticsearch:" + TESTCONTAINERS_VERSION,
- sha1 = "0cb114ecba0ed54a116e2be2f031bc45ca4cbfc8",
+ sha1 = "1ee43ebd81aea1f29bf60a56643bad80c134f998",
)
maven_jar(
diff --git a/java/com/google/gerrit/acceptance/AbstractPluginFieldsTest.java b/java/com/google/gerrit/acceptance/AbstractPluginFieldsTest.java
index 9d62e20..ccd30ab 100644
--- a/java/com/google/gerrit/acceptance/AbstractPluginFieldsTest.java
+++ b/java/com/google/gerrit/acceptance/AbstractPluginFieldsTest.java
@@ -14,6 +14,7 @@
package com.google.gerrit.acceptance;
+import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.truth.Truth.assertThat;
import static java.util.Objects.requireNonNull;
@@ -31,6 +32,8 @@
import com.google.gerrit.server.restapi.change.GetChange;
import com.google.gerrit.server.restapi.change.QueryChanges;
import com.google.gerrit.sshd.commands.Query;
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
import com.google.inject.AbstractModule;
import com.google.inject.Module;
import java.util.List;
@@ -164,6 +167,27 @@
return pluginInfo.stream().map(MyInfo.class::cast).collect(toImmutableList());
}
+ /**
+ * Decode {@code MyInfo}s from a raw list of maps returned from Gson.
+ *
+ * <p>This method is used instead of decoding {@code ChangeInfo} or {@code ChangAttribute}, since
+ * Gson would decode the {@code plugins} field as a {@code List<PluginDefinedInfo>}, which would
+ * return the base type and silently ignore any fields that are defined only in the subclass.
+ * Instead, decode the enclosing {@code ChangeInfo} or {@code ChangeAttribute} as a raw {@code
+ * Map<String, Object>}, and pass the {@code "plugins"} value to this method.
+ *
+ * @param gson Gson converter.
+ * @param plugins list of {@code MyInfo} objects, each as a raw map returned from Gson.
+ * @return decoded list of {@code MyInfo}s.
+ */
+ protected static List<MyInfo> decodeRawPluginsList(Gson gson, @Nullable Object plugins) {
+ if (plugins == null) {
+ return null;
+ }
+ checkArgument(plugins instanceof List, "not a list: %s", plugins);
+ return gson.fromJson(gson.toJson(plugins), new TypeToken<List<MyInfo>>() {}.getType());
+ }
+
@FunctionalInterface
protected interface PluginInfoGetter {
List<MyInfo> call(Change.Id id) throws Exception;
diff --git a/java/com/google/gerrit/pgm/util/BatchProgramModule.java b/java/com/google/gerrit/pgm/util/BatchProgramModule.java
index b700835..956ec75 100644
--- a/java/com/google/gerrit/pgm/util/BatchProgramModule.java
+++ b/java/com/google/gerrit/pgm/util/BatchProgramModule.java
@@ -58,6 +58,7 @@
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.extensions.events.RevisionCreated;
import com.google.gerrit.server.git.MergeUtil;
+import com.google.gerrit.server.git.PureRevertCache;
import com.google.gerrit.server.git.SearchingChangeCacheImpl;
import com.google.gerrit.server.git.TagCache;
import com.google.gerrit.server.mail.send.ReplacePatchSetSender;
@@ -160,6 +161,7 @@
install(ChangeKindCacheImpl.module());
install(MergeabilityCacheImpl.module());
install(TagCache.module());
+ install(PureRevertCache.module());
factory(CapabilityCollection.Factory.class);
factory(ChangeData.AssistedFactory.class);
factory(ProjectState.Factory.class);
diff --git a/java/com/google/gerrit/server/cache/serialize/ProtobufSerializer.java b/java/com/google/gerrit/server/cache/serialize/ProtobufSerializer.java
new file mode 100644
index 0000000..180646b
--- /dev/null
+++ b/java/com/google/gerrit/server/cache/serialize/ProtobufSerializer.java
@@ -0,0 +1,38 @@
+// Copyright (C) 2019 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.cache.serialize;
+
+import com.google.gerrit.proto.Protos;
+import com.google.protobuf.MessageLite;
+import com.google.protobuf.Parser;
+
+/** A CacheSerializer for Protobuf messages. */
+public class ProtobufSerializer<T extends MessageLite> implements CacheSerializer<T> {
+ private final Parser<T> parser;
+
+ public ProtobufSerializer(Parser<T> parser) {
+ this.parser = parser;
+ }
+
+ @Override
+ public byte[] serialize(T object) {
+ return Protos.toByteArray(object);
+ }
+
+ @Override
+ public T deserialize(byte[] in) {
+ return Protos.parseUnchecked(parser, in);
+ }
+}
diff --git a/java/com/google/gerrit/server/change/PureRevert.java b/java/com/google/gerrit/server/change/PureRevert.java
index 0135683..e7fb67a 100644
--- a/java/com/google/gerrit/server/change/PureRevert.java
+++ b/java/com/google/gerrit/server/change/PureRevert.java
@@ -14,109 +14,49 @@
package com.google.gerrit.server.change;
-import com.google.gerrit.common.Nullable;
-import com.google.gerrit.extensions.common.PureRevertInfo;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gerrit.server.PatchSetUtil;
-import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.git.MergeUtil;
+import com.google.gerrit.server.git.PureRevertCache;
import com.google.gerrit.server.notedb.ChangeNotes;
-import com.google.gerrit.server.project.ProjectCache;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.util.List;
-import org.eclipse.jgit.diff.DiffEntry;
-import org.eclipse.jgit.diff.DiffFormatter;
+import java.util.Optional;
import org.eclipse.jgit.errors.InvalidObjectIdException;
-import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.ObjectInserter;
-import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.merge.ThreeWayMerger;
-import org.eclipse.jgit.revwalk.RevCommit;
-import org.eclipse.jgit.revwalk.RevWalk;
+/** Can check if a change is a pure revert (= a revert with no further modifications). */
@Singleton
public class PureRevert {
- private final MergeUtil.Factory mergeUtilFactory;
- private final GitRepositoryManager repoManager;
- private final ProjectCache projectCache;
- private final ChangeNotes.Factory notesFactory;
- private final PatchSetUtil psUtil;
+ private final PureRevertCache pureRevertCache;
@Inject
- PureRevert(
- MergeUtil.Factory mergeUtilFactory,
- GitRepositoryManager repoManager,
- ProjectCache projectCache,
- ChangeNotes.Factory notesFactory,
- PatchSetUtil psUtil) {
- this.mergeUtilFactory = mergeUtilFactory;
- this.repoManager = repoManager;
- this.projectCache = projectCache;
- this.notesFactory = notesFactory;
- this.psUtil = psUtil;
+ PureRevert(PureRevertCache pureRevertCache) {
+ this.pureRevertCache = pureRevertCache;
}
- public PureRevertInfo get(ChangeNotes notes, @Nullable String claimedOriginal)
+ public boolean get(ChangeNotes notes, Optional<String> claimedOriginal)
throws OrmException, IOException, BadRequestException, ResourceConflictException {
- PatchSet currentPatchSet = psUtil.current(notes);
+ PatchSet currentPatchSet = notes.getCurrentPatchSet();
if (currentPatchSet == null) {
throw new ResourceConflictException("current revision is missing");
}
-
- if (claimedOriginal == null) {
- if (notes.getChange().getRevertOf() == null) {
- throw new BadRequestException("no ID was provided and change isn't a revert");
- }
- PatchSet ps =
- psUtil.current(
- notesFactory.createChecked(notes.getProjectName(), notes.getChange().getRevertOf()));
- claimedOriginal = ps.getRevision().get();
+ if (!claimedOriginal.isPresent()) {
+ return pureRevertCache.isPureRevert(notes);
}
- try (Repository repo = repoManager.openRepository(notes.getProjectName());
- ObjectInserter oi = repo.newObjectInserter();
- RevWalk rw = new RevWalk(repo)) {
- RevCommit claimedOriginalCommit;
- try {
- claimedOriginalCommit = rw.parseCommit(ObjectId.fromString(claimedOriginal));
- } catch (InvalidObjectIdException | MissingObjectException e) {
- throw new BadRequestException("invalid object ID");
- }
- if (claimedOriginalCommit.getParentCount() == 0) {
- throw new BadRequestException("can't check against initial commit");
- }
- RevCommit claimedRevertCommit =
- rw.parseCommit(ObjectId.fromString(currentPatchSet.getRevision().get()));
- if (claimedRevertCommit.getParentCount() == 0) {
- throw new BadRequestException("claimed revert has no parents");
- }
- // Rebase claimed revert onto claimed original
- ThreeWayMerger merger =
- mergeUtilFactory
- .create(projectCache.checkedGet(notes.getProjectName()))
- .newThreeWayMerger(oi, repo.getConfig());
- merger.setBase(claimedRevertCommit.getParent(0));
- boolean success = merger.merge(claimedRevertCommit, claimedOriginalCommit);
- if (!success || merger.getResultTreeId() == null) {
- // Merge conflict during rebase
- return new PureRevertInfo(false);
- }
-
- // Any differences between claimed original's parent and the rebase result indicate that the
- // claimedRevert is not a pure revert but made content changes
- try (DiffFormatter df = new DiffFormatter(new ByteArrayOutputStream())) {
- df.setReader(oi.newReader(), repo.getConfig());
- List<DiffEntry> entries =
- df.scan(claimedOriginalCommit.getParent(0), merger.getResultTreeId());
- return new PureRevertInfo(entries.isEmpty());
- }
+ ObjectId claimedOriginalObjectId;
+ try {
+ claimedOriginalObjectId = ObjectId.fromString(claimedOriginal.get());
+ } catch (InvalidObjectIdException e) {
+ throw new BadRequestException("invalid object ID");
}
+
+ return pureRevertCache.isPureRevert(
+ notes.getProjectName(),
+ ObjectId.fromString(notes.getCurrentPatchSet().getRevision().get()),
+ claimedOriginalObjectId);
}
}
diff --git a/java/com/google/gerrit/server/config/GerritGlobalModule.java b/java/com/google/gerrit/server/config/GerritGlobalModule.java
index e7baa55..f168ef9 100644
--- a/java/com/google/gerrit/server/config/GerritGlobalModule.java
+++ b/java/com/google/gerrit/server/config/GerritGlobalModule.java
@@ -117,6 +117,7 @@
import com.google.gerrit.server.git.MergeUtil;
import com.google.gerrit.server.git.MergedByPushOp;
import com.google.gerrit.server.git.NotesBranchUtil;
+import com.google.gerrit.server.git.PureRevertCache;
import com.google.gerrit.server.git.ReceivePackInitializer;
import com.google.gerrit.server.git.TagCache;
import com.google.gerrit.server.git.TransferConfig;
@@ -237,6 +238,7 @@
install(SubmitStrategy.module());
install(TagCache.module());
install(OAuthTokenCache.module());
+ install(PureRevertCache.module());
install(new AccessControlModule());
install(new CmdLineParserModule());
diff --git a/java/com/google/gerrit/server/git/PureRevertCache.java b/java/com/google/gerrit/server/git/PureRevertCache.java
new file mode 100644
index 0000000..53f004f
--- /dev/null
+++ b/java/com/google/gerrit/server/git/PureRevertCache.java
@@ -0,0 +1,203 @@
+// Copyright (C) 2019 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.git;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Throwables;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.gerrit.extensions.restapi.BadRequestException;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.cache.CacheModule;
+import com.google.gerrit.server.cache.proto.Cache;
+import com.google.gerrit.server.cache.proto.Cache.PureRevertKeyProto;
+import com.google.gerrit.server.cache.serialize.BooleanCacheSerializer;
+import com.google.gerrit.server.cache.serialize.ObjectIdConverter;
+import com.google.gerrit.server.cache.serialize.ProtobufSerializer;
+import com.google.gerrit.server.logging.TraceContext;
+import com.google.gerrit.server.notedb.ChangeNotes;
+import com.google.gerrit.server.project.ProjectCache;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+import com.google.inject.Module;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
+import com.google.protobuf.ByteString;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import org.eclipse.jgit.diff.DiffEntry;
+import org.eclipse.jgit.diff.DiffFormatter;
+import org.eclipse.jgit.errors.InvalidObjectIdException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.merge.ThreeWayMerger;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+
+/** Computes and caches if a change is a pure revert of another change. */
+@Singleton
+public class PureRevertCache {
+ private static final String ID_CACHE = "pure_revert";
+
+ public static Module module() {
+ return new CacheModule() {
+ @Override
+ protected void configure() {
+ persist(ID_CACHE, Cache.PureRevertKeyProto.class, Boolean.class)
+ .maximumWeight(100)
+ .loader(Loader.class)
+ .version(1)
+ .keySerializer(new ProtobufSerializer<>(Cache.PureRevertKeyProto.parser()))
+ .valueSerializer(BooleanCacheSerializer.INSTANCE);
+ }
+ };
+ }
+
+ private final LoadingCache<PureRevertKeyProto, Boolean> cache;
+ private final ChangeNotes.Factory notesFactory;
+
+ @Inject
+ PureRevertCache(
+ @Named(ID_CACHE) LoadingCache<PureRevertKeyProto, Boolean> cache,
+ ChangeNotes.Factory notesFactory) {
+ this.cache = cache;
+ this.notesFactory = notesFactory;
+ }
+
+ /**
+ * Returns {@code true} if {@code claimedRevert} is a pure (clean) revert of the change that is
+ * referenced in {@link Change#getRevertOf()}.
+ *
+ * @return {@code true} if {@code claimedRevert} is a pure (clean) revert.
+ * @throws IOException if there was a problem with the storage layer
+ * @throws OrmException if there was a problem with the storage layer
+ * @throws BadRequestException if there is a problem with the provided {@link ChangeNotes}
+ */
+ public boolean isPureRevert(ChangeNotes claimedRevert)
+ throws OrmException, IOException, BadRequestException {
+ if (claimedRevert.getChange().getRevertOf() == null) {
+ throw new BadRequestException("revertOf not set");
+ }
+ ChangeNotes claimedOriginal =
+ notesFactory.createChecked(
+ claimedRevert.getProjectName(), claimedRevert.getChange().getRevertOf());
+ return isPureRevert(
+ claimedRevert.getProjectName(),
+ ObjectId.fromString(claimedRevert.getCurrentPatchSet().getRevision().get()),
+ ObjectId.fromString(claimedOriginal.getCurrentPatchSet().getRevision().get()));
+ }
+
+ /**
+ * Returns {@code true} if {@code claimedRevert} is a pure (clean) revert of {@code
+ * claimedOriginal}.
+ *
+ * @return {@code true} if {@code claimedRevert} is a pure (clean) revert of {@code
+ * claimedOriginal}.
+ * @throws IOException if there was a problem with the storage layer
+ * @throws BadRequestException if there is a problem with the provided {@link ObjectId}s
+ */
+ public boolean isPureRevert(
+ Project.NameKey project, ObjectId claimedRevert, ObjectId claimedOriginal)
+ throws IOException, BadRequestException {
+ try {
+ return cache.get(key(project, claimedRevert, claimedOriginal));
+ } catch (ExecutionException e) {
+ Throwables.throwIfInstanceOf(e.getCause(), BadRequestException.class);
+ throw new IOException(e);
+ }
+ }
+
+ @VisibleForTesting
+ static PureRevertKeyProto key(
+ Project.NameKey project, ObjectId claimedRevert, ObjectId claimedOriginal) {
+ ByteString original = ObjectIdConverter.create().toByteString(claimedOriginal);
+ ByteString revert = ObjectIdConverter.create().toByteString(claimedRevert);
+ return PureRevertKeyProto.newBuilder()
+ .setProject(project.get())
+ .setClaimedOriginal(original)
+ .setClaimedRevert(revert)
+ .build();
+ }
+
+ static class Loader extends CacheLoader<PureRevertKeyProto, Boolean> {
+ private final GitRepositoryManager repoManager;
+ private final MergeUtil.Factory mergeUtilFactory;
+ private final ProjectCache projectCache;
+
+ @Inject
+ Loader(
+ GitRepositoryManager repoManager,
+ MergeUtil.Factory mergeUtilFactory,
+ ProjectCache projectCache) {
+ this.repoManager = repoManager;
+ this.mergeUtilFactory = mergeUtilFactory;
+ this.projectCache = projectCache;
+ }
+
+ @Override
+ public Boolean load(PureRevertKeyProto key) throws BadRequestException, IOException {
+ try (TraceContext.TraceTimer ignored =
+ TraceContext.newTimer("Loading pure revert for %s", key)) {
+ ObjectId original = ObjectIdConverter.create().fromByteString(key.getClaimedOriginal());
+ ObjectId revert = ObjectIdConverter.create().fromByteString(key.getClaimedRevert());
+ Project.NameKey project = new Project.NameKey(key.getProject());
+
+ try (Repository repo = repoManager.openRepository(project);
+ ObjectInserter oi = repo.newObjectInserter();
+ RevWalk rw = new RevWalk(repo)) {
+ RevCommit claimedOriginalCommit;
+ try {
+ claimedOriginalCommit = rw.parseCommit(original);
+ } catch (InvalidObjectIdException | MissingObjectException e) {
+ throw new BadRequestException("invalid object ID");
+ }
+ if (claimedOriginalCommit.getParentCount() == 0) {
+ throw new BadRequestException("can't check against initial commit");
+ }
+ RevCommit claimedRevertCommit = rw.parseCommit(revert);
+ if (claimedRevertCommit.getParentCount() == 0) {
+ return false;
+ }
+ // Rebase claimed revert onto claimed original
+ ThreeWayMerger merger =
+ mergeUtilFactory
+ .create(projectCache.checkedGet(project))
+ .newThreeWayMerger(oi, repo.getConfig());
+ merger.setBase(claimedRevertCommit.getParent(0));
+ boolean success = merger.merge(claimedRevertCommit, claimedOriginalCommit);
+ if (!success || merger.getResultTreeId() == null) {
+ // Merge conflict during rebase
+ return false;
+ }
+
+ // Any differences between claimed original's parent and the rebase result indicate that
+ // the
+ // claimedRevert is not a pure revert but made content changes
+ try (DiffFormatter df = new DiffFormatter(new ByteArrayOutputStream())) {
+ df.setReader(oi.newReader(), repo.getConfig());
+ List<DiffEntry> entries =
+ df.scan(claimedOriginalCommit.getParent(0), merger.getResultTreeId());
+ return entries.isEmpty();
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/java/com/google/gerrit/server/query/change/ChangeData.java b/java/com/google/gerrit/server/query/change/ChangeData.java
index b058166..5a300b4 100644
--- a/java/com/google/gerrit/server/query/change/ChangeData.java
+++ b/java/com/google/gerrit/server/query/change/ChangeData.java
@@ -1111,7 +1111,7 @@
return null;
}
try {
- return pureRevert.get(notes(), null).isPureRevert;
+ return pureRevert.get(notes(), Optional.empty());
} catch (IOException | BadRequestException | ResourceConflictException e) {
throw new OrmException("could not compute pure revert", e);
}
diff --git a/java/com/google/gerrit/server/restapi/change/GetPureRevert.java b/java/com/google/gerrit/server/restapi/change/GetPureRevert.java
index 75019af..dcafe56 100644
--- a/java/com/google/gerrit/server/restapi/change/GetPureRevert.java
+++ b/java/com/google/gerrit/server/restapi/change/GetPureRevert.java
@@ -25,6 +25,7 @@
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import java.io.IOException;
+import java.util.Optional;
import org.kohsuke.args4j.Option;
public class GetPureRevert implements RestReadView<ChangeResource> {
@@ -49,6 +50,7 @@
public PureRevertInfo apply(ChangeResource rsrc)
throws ResourceConflictException, IOException, BadRequestException, OrmException,
AuthException {
- return pureRevert.get(rsrc.getNotes(), claimedOriginal);
+ boolean isPureRevert = pureRevert.get(rsrc.getNotes(), Optional.ofNullable(claimedOriginal));
+ return new PureRevertInfo(isPureRevert);
}
}
diff --git a/java/com/google/gerrit/testing/TestTimeUtil.java b/java/com/google/gerrit/testing/TestTimeUtil.java
index 9228123..2020e5d 100644
--- a/java/com/google/gerrit/testing/TestTimeUtil.java
+++ b/java/com/google/gerrit/testing/TestTimeUtil.java
@@ -118,6 +118,15 @@
clockMs.addAndGet(clockStepUnit.toMillis(clockStep));
}
+ /**
+ * Returns the current timestamp.
+ *
+ * @return current timestamp
+ */
+ public static synchronized Timestamp getCurrentTimestamp() {
+ return new Timestamp(clockMs.get());
+ }
+
/** Reset the clock to use the actual system clock. */
public static synchronized void useSystemTime() {
clockMs = null;
diff --git a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
index 9cc277f..5aed312 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -3695,7 +3695,7 @@
@Test
public void pureRevertThrowsExceptionWhenChangeIsNotARevertAndNoIdProvided() throws Exception {
exception.expect(BadRequestException.class);
- exception.expectMessage("no ID was provided and change isn't a revert");
+ exception.expectMessage("revertOf not set");
gApi.changes().id(createChange().getChangeId()).pureRevert();
}
diff --git a/javatests/com/google/gerrit/acceptance/api/change/PluginFieldsIT.java b/javatests/com/google/gerrit/acceptance/api/change/PluginFieldsIT.java
index 9ab730c..d5089ff 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/PluginFieldsIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/PluginFieldsIT.java
@@ -26,31 +26,31 @@
// No tests for /detail via the extension API, since the extension API doesn't have that method.
@Test
- public void queryChangeApiWithNullAttribute() throws Exception {
+ public void queryChangeWithNullAttribute() throws Exception {
getChangeWithNullAttribute(
id -> pluginInfoFromSingletonList(gApi.changes().query(id.toString()).get()));
}
@Test
- public void getChangeApiWithNullAttribute() throws Exception {
+ public void getChangeWithNullAttribute() throws Exception {
getChangeWithNullAttribute(
id -> pluginInfoFromChangeInfo(gApi.changes().id(id.toString()).get()));
}
@Test
- public void queryChangeApiWithSimpleAttribute() throws Exception {
+ public void queryChangeWithSimpleAttribute() throws Exception {
getChangeWithSimpleAttribute(
id -> pluginInfoFromSingletonList(gApi.changes().query(id.toString()).get()));
}
@Test
- public void getChangeApiWithSimpleAttribute() throws Exception {
+ public void getChangeWithSimpleAttribute() throws Exception {
getChangeWithSimpleAttribute(
id -> pluginInfoFromChangeInfo(gApi.changes().id(id.toString()).get()));
}
@Test
- public void queryChangeApiWithOption() throws Exception {
+ public void queryChangeWithOption() throws Exception {
getChangeWithOption(
id -> pluginInfoFromSingletonList(gApi.changes().query(id.toString()).get()),
(id, opts) ->
@@ -59,7 +59,7 @@
}
@Test
- public void getChangeApiWithOption() throws Exception {
+ public void getChangeWithOption() throws Exception {
getChangeWithOption(
id -> pluginInfoFromChangeInfo(gApi.changes().id(id.get()).get()),
(id, opts) -> pluginInfoFromChangeInfo(gApi.changes().id(id.get()).get(opts)));
@@ -75,7 +75,7 @@
}
@Test
- public void getChangeApiWithSimpleAttributeWithExplicitExport() throws Exception {
+ public void getChangeWithSimpleAttributeWithExplicitExport() throws Exception {
// For backwards compatibility with old plugins, allow modules to bind into the
// DynamicSet<ChangeAttributeFactory> as if it were a DynamicMap. We only need one variant of
// this test to prove that the mapping works.
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/PluginFieldsIT.java b/javatests/com/google/gerrit/acceptance/rest/change/PluginFieldsIT.java
index 6388fe9..649c7ae 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/PluginFieldsIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/PluginFieldsIT.java
@@ -33,62 +33,59 @@
private static final Gson GSON = OutputFormat.JSON.newGson();
@Test
- public void queryChangeRestWithNullAttribute() throws Exception {
+ public void queryChangeWithNullAttribute() throws Exception {
getChangeWithNullAttribute(
- id -> pluginInfoFromSingletonListRest(adminRestSession.get(changeQueryUrl(id))));
+ id -> pluginInfoFromSingletonList(adminRestSession.get(changeQueryUrl(id))));
}
@Test
- public void getChangeRestWithNullAttribute() throws Exception {
+ public void getChangeWithNullAttribute() throws Exception {
+ getChangeWithNullAttribute(id -> pluginInfoFromChangeInfo(adminRestSession.get(changeUrl(id))));
+ }
+
+ @Test
+ public void getChangeDetailWithNullAttribute() throws Exception {
getChangeWithNullAttribute(
- id -> pluginInfoFromChangeInfoRest(adminRestSession.get(changeUrl(id))));
+ id -> pluginInfoFromChangeInfo(adminRestSession.get(changeDetailUrl(id))));
}
@Test
- public void getChangeDetailRestWithNullAttribute() throws Exception {
- getChangeWithNullAttribute(
- id -> pluginInfoFromChangeInfoRest(adminRestSession.get(changeDetailUrl(id))));
- }
-
- @Test
- public void queryChangeRestWithSimpleAttribute() throws Exception {
+ public void queryChangeWithSimpleAttribute() throws Exception {
getChangeWithSimpleAttribute(
- id -> pluginInfoFromSingletonListRest(adminRestSession.get(changeQueryUrl(id))));
+ id -> pluginInfoFromSingletonList(adminRestSession.get(changeQueryUrl(id))));
}
@Test
- public void getChangeRestWithSimpleAttribute() throws Exception {
+ public void getChangeWithSimpleAttribute() throws Exception {
getChangeWithSimpleAttribute(
- id -> pluginInfoFromChangeInfoRest(adminRestSession.get(changeUrl(id))));
+ id -> pluginInfoFromChangeInfo(adminRestSession.get(changeUrl(id))));
}
@Test
- public void getChangeDetailRestWithSimpleAttribute() throws Exception {
+ public void getChangeDetailWithSimpleAttribute() throws Exception {
getChangeWithSimpleAttribute(
- id -> pluginInfoFromChangeInfoRest(adminRestSession.get(changeDetailUrl(id))));
+ id -> pluginInfoFromChangeInfo(adminRestSession.get(changeDetailUrl(id))));
}
@Test
- public void queryChangeRestWithOption() throws Exception {
+ public void queryChangeWithOption() throws Exception {
getChangeWithOption(
- id -> pluginInfoFromSingletonListRest(adminRestSession.get(changeQueryUrl(id))),
- (id, opts) ->
- pluginInfoFromSingletonListRest(adminRestSession.get(changeQueryUrl(id, opts))));
+ id -> pluginInfoFromSingletonList(adminRestSession.get(changeQueryUrl(id))),
+ (id, opts) -> pluginInfoFromSingletonList(adminRestSession.get(changeQueryUrl(id, opts))));
}
@Test
- public void getChangeRestWithOption() throws Exception {
+ public void getChangeWithOption() throws Exception {
getChangeWithOption(
- id -> pluginInfoFromChangeInfoRest(adminRestSession.get(changeUrl(id))),
- (id, opts) -> pluginInfoFromChangeInfoRest(adminRestSession.get(changeUrl(id, opts))));
+ id -> pluginInfoFromChangeInfo(adminRestSession.get(changeUrl(id))),
+ (id, opts) -> pluginInfoFromChangeInfo(adminRestSession.get(changeUrl(id, opts))));
}
@Test
- public void getChangeDetailRestWithOption() throws Exception {
+ public void getChangeDetailWithOption() throws Exception {
getChangeWithOption(
- id -> pluginInfoFromChangeInfoRest(adminRestSession.get(changeDetailUrl(id))),
- (id, opts) ->
- pluginInfoFromChangeInfoRest(adminRestSession.get(changeDetailUrl(id, opts))));
+ id -> pluginInfoFromChangeInfo(adminRestSession.get(changeDetailUrl(id))),
+ (id, opts) -> pluginInfoFromChangeInfo(adminRestSession.get(changeDetailUrl(id, opts))));
}
private String changeQueryUrl(Change.Id id) {
@@ -136,32 +133,19 @@
}
@Nullable
- private static List<MyInfo> pluginInfoFromSingletonListRest(RestResponse res) throws Exception {
+ private static List<MyInfo> pluginInfoFromSingletonList(RestResponse res) throws Exception {
res.assertOK();
-
- // Don't deserialize to ChangeInfo directly, since that would treat the plugins field as
- // List<PluginDefinedInfo> and ignore the unknown keys found in MyInfo.
List<Map<String, Object>> changeInfos =
GSON.fromJson(res.getReader(), new TypeToken<List<Map<String, Object>>>() {}.getType());
assertThat(changeInfos).hasSize(1);
- return myInfo(changeInfos.get(0));
+ return decodeRawPluginsList(GSON, changeInfos.get(0).get("plugins"));
}
@Nullable
- private List<MyInfo> pluginInfoFromChangeInfoRest(RestResponse res) throws Exception {
+ private List<MyInfo> pluginInfoFromChangeInfo(RestResponse res) throws Exception {
res.assertOK();
-
- // Don't deserialize to ChangeInfo directly, since that would treat the plugins field as
- // List<PluginDefinedInfo> and ignore the unknown keys found in MyInfo.
- return myInfo(
- GSON.fromJson(res.getReader(), new TypeToken<Map<String, Object>>() {}.getType()));
- }
-
- private static List<MyInfo> myInfo(Map<String, Object> changeInfo) {
- Object plugins = changeInfo.get("plugins");
- if (plugins == null) {
- return null;
- }
- return GSON.fromJson(GSON.toJson(plugins), new TypeToken<List<MyInfo>>() {}.getType());
+ Map<String, Object> changeInfo =
+ GSON.fromJson(res.getReader(), new TypeToken<Map<String, Object>>() {}.getType());
+ return decodeRawPluginsList(GSON, changeInfo.get("plugins"));
}
}
diff --git a/javatests/com/google/gerrit/acceptance/ssh/PluginChangeFieldsIT.java b/javatests/com/google/gerrit/acceptance/ssh/PluginChangeFieldsIT.java
index d196c5a..e61e2cc 100644
--- a/javatests/com/google/gerrit/acceptance/ssh/PluginChangeFieldsIT.java
+++ b/javatests/com/google/gerrit/acceptance/ssh/PluginChangeFieldsIT.java
@@ -40,23 +40,22 @@
private static final Gson GSON = OutputStreamQuery.GSON;
@Test
- public void queryChangeSshWithNullAttribute() throws Exception {
+ public void queryChangeWithNullAttribute() throws Exception {
getChangeWithNullAttribute(
- id -> pluginInfoFromSingletonListSsh(adminSshSession.exec(changeQueryCmd(id))));
+ id -> pluginInfoFromSingletonList(adminSshSession.exec(changeQueryCmd(id))));
}
@Test
- public void queryChangeSshWithSimpleAttribute() throws Exception {
+ public void queryChangeWithSimpleAttribute() throws Exception {
getChangeWithSimpleAttribute(
- id -> pluginInfoFromSingletonListSsh(adminSshSession.exec(changeQueryCmd(id))));
+ id -> pluginInfoFromSingletonList(adminSshSession.exec(changeQueryCmd(id))));
}
@Test
- public void queryChangeSshWithOption() throws Exception {
+ public void queryChangeWithOption() throws Exception {
getChangeWithOption(
- id -> pluginInfoFromSingletonListSsh(adminSshSession.exec(changeQueryCmd(id))),
- (id, opts) ->
- pluginInfoFromSingletonListSsh(adminSshSession.exec(changeQueryCmd(id, opts))));
+ id -> pluginInfoFromSingletonList(adminSshSession.exec(changeQueryCmd(id))),
+ (id, opts) -> pluginInfoFromSingletonList(adminSshSession.exec(changeQueryCmd(id, opts))));
}
private String changeQueryCmd(Change.Id id) {
@@ -73,11 +72,9 @@
}
@Nullable
- private static List<MyInfo> pluginInfoFromSingletonListSsh(String sshOutput) throws Exception {
+ private static List<MyInfo> pluginInfoFromSingletonList(String sshOutput) throws Exception {
List<Map<String, Object>> changeAttrs = new ArrayList<>();
for (String line : CharStreams.readLines(new StringReader(sshOutput))) {
- // Don't deserialize to ChangeAttribute directly, since that would treat the plugins field as
- // List<PluginDefinedInfo> and ignore the unknown keys found in MyInfo.
Map<String, Object> changeAttr =
GSON.fromJson(line, new TypeToken<Map<String, Object>>() {}.getType());
if (!"stats".equals(changeAttr.get("type"))) {
@@ -86,11 +83,6 @@
}
assertThat(changeAttrs).hasSize(1);
-
- Object plugins = changeAttrs.get(0).get("plugins");
- if (plugins == null) {
- return null;
- }
- return GSON.fromJson(GSON.toJson(plugins), new TypeToken<List<MyInfo>>() {}.getType());
+ return decodeRawPluginsList(GSON, changeAttrs.get(0).get("plugins"));
}
}
diff --git a/javatests/com/google/gerrit/elasticsearch/ElasticContainer.java b/javatests/com/google/gerrit/elasticsearch/ElasticContainer.java
index 79170c4..504ec46 100644
--- a/javatests/com/google/gerrit/elasticsearch/ElasticContainer.java
+++ b/javatests/com/google/gerrit/elasticsearch/ElasticContainer.java
@@ -47,7 +47,7 @@
case V6_5:
return "docker.elastic.co/elasticsearch/elasticsearch-oss:6.5.4";
case V6_6:
- return "docker.elastic.co/elasticsearch/elasticsearch-oss:6.6.1";
+ return "docker.elastic.co/elasticsearch/elasticsearch-oss:6.6.2";
case V7_0:
return "docker.elastic.co/elasticsearch/elasticsearch-oss:7.0.0-beta1";
}
diff --git a/javatests/com/google/gerrit/server/cache/serialize/BUILD b/javatests/com/google/gerrit/server/cache/serialize/BUILD
index ddad4b9..92f33ad 100644
--- a/javatests/com/google/gerrit/server/cache/serialize/BUILD
+++ b/javatests/com/google/gerrit/server/cache/serialize/BUILD
@@ -17,5 +17,6 @@
"//lib/truth",
"//lib/truth:truth-proto-extension",
"//proto:cache_java_proto",
+ "//proto/testing:test_java_proto",
],
)
diff --git a/javatests/com/google/gerrit/server/cache/serialize/ProtobufSerializerTest.java b/javatests/com/google/gerrit/server/cache/serialize/ProtobufSerializerTest.java
new file mode 100644
index 0000000..845da9b
--- /dev/null
+++ b/javatests/com/google/gerrit/server/cache/serialize/ProtobufSerializerTest.java
@@ -0,0 +1,43 @@
+// Copyright (C) 2019 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.cache.serialize;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.gerrit.proto.testing.Test.SerializableProto;
+import com.google.gerrit.testing.GerritBaseTests;
+import org.junit.Test;
+
+public class ProtobufSerializerTest extends GerritBaseTests {
+ @Test
+ public void requiredAndOptionalTypes() {
+ assertRoundTrip(SerializableProto.newBuilder().setId(123));
+ assertRoundTrip(SerializableProto.newBuilder().setId(123).setText("foo bar"));
+ }
+
+ @Test
+ public void exactByteSequence() {
+ ProtobufSerializer<SerializableProto> s = new ProtobufSerializer<>(SerializableProto.parser());
+ SerializableProto proto = SerializableProto.newBuilder().setId(123).setText("foo bar").build();
+ byte[] serialized = s.serialize(proto);
+ // Hard-code byte sequence to detect library changes
+ assertThat(serialized).isEqualTo(new byte[] {8, 123, 18, 7, 102, 111, 111, 32, 98, 97, 114});
+ }
+
+ private static void assertRoundTrip(SerializableProto.Builder input) {
+ ProtobufSerializer<SerializableProto> s = new ProtobufSerializer<>(SerializableProto.parser());
+ assertThat(s.deserialize(s.serialize(input.build()))).isEqualTo(input.build());
+ }
+}
diff --git a/javatests/com/google/gerrit/server/git/PureRevertCacheKeyTest.java b/javatests/com/google/gerrit/server/git/PureRevertCacheKeyTest.java
new file mode 100644
index 0000000..8c17075
--- /dev/null
+++ b/javatests/com/google/gerrit/server/git/PureRevertCacheKeyTest.java
@@ -0,0 +1,49 @@
+// Copyright (C) 2019 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.git;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.server.cache.testing.CacheSerializerTestUtil.byteArray;
+
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.cache.proto.Cache;
+import com.google.protobuf.ByteString;
+import org.eclipse.jgit.lib.ObjectId;
+import org.junit.Test;
+
+public class PureRevertCacheKeyTest {
+ @Test
+ public void serialization() {
+ ObjectId revert = ObjectId.zeroId();
+ ObjectId original = ObjectId.fromString("aabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
+
+ byte[] serializedRevert =
+ new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ byte[] serializedOriginal =
+ byteArray(
+ 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
+ 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb);
+
+ Cache.PureRevertKeyProto key =
+ PureRevertCache.key(new Project.NameKey("test"), revert, original);
+ assertThat(key)
+ .isEqualTo(
+ Cache.PureRevertKeyProto.newBuilder()
+ .setProject("test")
+ .setClaimedRevert(ByteString.copyFrom(serializedRevert))
+ .setClaimedOriginal(ByteString.copyFrom(serializedOriginal))
+ .build());
+ }
+}
diff --git a/plugins/delete-project b/plugins/delete-project
index 53311c0..9eee6bb 160000
--- a/plugins/delete-project
+++ b/plugins/delete-project
@@ -1 +1 @@
-Subproject commit 53311c006635e83faaa7a1b68039edebe0fe8e43
+Subproject commit 9eee6bb4de393cf5bf94a2861320f5e1bf618329
diff --git a/plugins/replication b/plugins/replication
index a4bae3f..ff75ac8 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit a4bae3f491bb3f693e2407d353d3a81ce2a5c8be
+Subproject commit ff75ac8a4c806e5f627cb755f49e08962fa6e6b0
diff --git a/plugins/webhooks b/plugins/webhooks
index 064ae07..ed81825 160000
--- a/plugins/webhooks
+++ b/plugins/webhooks
@@ -1 +1 @@
-Subproject commit 064ae07f55710034062ef2a36cd030abeee93265
+Subproject commit ed818254ca32196c0e0acf4090b7b44a918f25ee
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 1c018de..2146d9d 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
@@ -139,7 +139,10 @@
},
/** @type {?} */
patchRange: Object,
- path: String,
+ path: {
+ type: String,
+ observer: '_pathObserver',
+ },
prefs: {
type: Object,
observer: '_prefsObserver',
@@ -636,6 +639,11 @@
}
},
+ _pathObserver() {
+ // Call _prefsChanged(), because line-limit style value depends on path.
+ this._prefsChanged(this.prefs);
+ },
+
_viewModeObserver() {
this._prefsChanged(this.prefs);
},
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.html b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.html
index 412b73e..21bf649 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.html
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.html
@@ -384,10 +384,12 @@
disabled="[[!_computeAddEmailButtonEnabled(_newEmail, _addingEmail)]]"
on-tap="_handleAddEmailButton">Send verification</gr-button>
</fieldset>
- <h2 id="HTTPCredentials">HTTP Credentials</h2>
- <fieldset>
- <gr-http-password id="httpPass"></gr-http-password>
- </fieldset>
+ <div hidden$="[[!_showHttpAuth(_serverConfig)]]">
+ <h2 id="HTTPCredentials">HTTP Credentials</h2>
+ <fieldset>
+ <gr-http-password id="httpPass"></gr-http-password>
+ </fieldset>
+ </div>
<div hidden$="[[!_serverConfig.sshd]]">
<h2
id="SSHKeys"
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.js b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.js
index 706b1ac..f523034 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.js
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.js
@@ -40,6 +40,11 @@
const RELOAD_MESSAGE = 'Reloading...';
+ const HTTP_AUTH = [
+ 'HTTP',
+ 'HTTP_LDAP',
+ ];
+
Polymer({
is: 'gr-settings-view',
@@ -413,5 +418,15 @@
window.location.reload();
}, 1);
},
+
+ _showHttpAuth(config) {
+ if (config && config.auth &&
+ config.auth.git_basic_auth_policy) {
+ return HTTP_AUTH.includes(
+ config.auth.git_basic_auth_policy.toUpperCase());
+ }
+
+ return false;
+ },
});
})();
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.html b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.html
index a51d310..506c6af 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.html
@@ -407,6 +407,46 @@
assert.isTrue(overlayOpen.called);
});
+ test('_showHttpAuth', () => {
+ let serverConfig;
+
+ serverConfig = {
+ auth: {
+ git_basic_auth_policy: 'HTTP',
+ },
+ };
+
+ assert.isTrue(element._showHttpAuth(serverConfig));
+
+ serverConfig = {
+ auth: {
+ git_basic_auth_policy: 'HTTP_LDAP',
+ },
+ };
+
+ assert.isTrue(element._showHttpAuth(serverConfig));
+
+ serverConfig = {
+ auth: {
+ git_basic_auth_policy: 'LDAP',
+ },
+ };
+
+ assert.isFalse(element._showHttpAuth(serverConfig));
+
+ serverConfig = {
+ auth: {
+ git_basic_auth_policy: 'OAUTH',
+ },
+ };
+
+ assert.isFalse(element._showHttpAuth(serverConfig));
+
+ serverConfig = {};
+
+ assert.isFalse(element._showHttpAuth(serverConfig));
+ });
+
suite('_getFilterDocsLink', () => {
test('with http: docs base URL', () => {
const base = 'http://example.com/';
diff --git a/proto/cache.proto b/proto/cache.proto
index c978069..b34dbf3 100644
--- a/proto/cache.proto
+++ b/proto/cache.proto
@@ -234,3 +234,11 @@
}
repeated ExternalIdProto external_id = 1;
}
+
+// Key for com.google.gerrit.server.git.PureRevertCache.
+// Next ID: 4
+message PureRevertKeyProto {
+ string project = 1;
+ bytes claimed_original = 2;
+ bytes claimed_revert = 3;
+}
diff --git a/proto/testing/BUILD b/proto/testing/BUILD
new file mode 100644
index 0000000..b9032cf
--- /dev/null
+++ b/proto/testing/BUILD
@@ -0,0 +1,12 @@
+proto_library(
+ name = "test_proto",
+ testonly = 1,
+ srcs = ["test.proto"],
+)
+
+java_proto_library(
+ name = "test_java_proto",
+ testonly = 1,
+ visibility = ["//visibility:public"],
+ deps = [":test_proto"],
+)
diff --git a/proto/testing/test.proto b/proto/testing/test.proto
new file mode 100644
index 0000000..e28c9ff
--- /dev/null
+++ b/proto/testing/test.proto
@@ -0,0 +1,26 @@
+// Copyright (C) 2019 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.
+
+syntax = "proto2";
+
+package devtools.gerritcodereview.testing;
+
+option java_package = "com.google.gerrit.proto.testing";
+
+// Test type for ProtobufSerializerTest
+// Next ID: 3
+message SerializableProto {
+ required int32 id = 1;
+ optional string text = 2;
+}
diff --git a/tools/bzl/js.bzl b/tools/bzl/js.bzl
index a7714a1..0245c50 100644
--- a/tools/bzl/js.bzl
+++ b/tools/bzl/js.bzl
@@ -425,7 +425,7 @@
"""Combine html, js, css files and optionally split into js and html bundles."""
_bundle_rule(pkg = native.package_name(), *args, **kwargs)
-def polygerrit_plugin(name, app, srcs = [], assets = None, plugin_name = None, **kwargs):
+def polygerrit_plugin(name, app, srcs = [], deps = [], assets = None, plugin_name = None, **kwargs):
"""Bundles plugin dependencies for deployment.
This rule bundles all Polymer elements and JS dependencies into .html and .js files.
@@ -450,6 +450,7 @@
name = name + "_combined",
app = app,
srcs = srcs,
+ deps = deps,
pkg = native.package_name(),
**kwargs
)