Merge "Add missing JavaDoc to validators package"
diff --git a/WORKSPACE b/WORKSPACE
index 0804bec..e7317af 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -919,48 +919,48 @@
sha1 = "7e060dd5b19431e6d198e91ff670644372f60fbd",
)
-JETTY_VERS = "9.4.18.v20190429"
+JETTY_VERS = "9.4.24.v20191120"
maven_jar(
name = "jetty-servlet",
artifact = "org.eclipse.jetty:jetty-servlet:" + JETTY_VERS,
- sha1 = "290f7a88f351950d51ebc9fb4a794752c62d7de5",
+ sha1 = "ca1803fde51b795c0a8346ca8bc6277d9d04d01d",
)
maven_jar(
name = "jetty-security",
artifact = "org.eclipse.jetty:jetty-security:" + JETTY_VERS,
- sha1 = "01aceff3608ca1b223bfd275a497797cfe675ef4",
+ sha1 = "9fa640d36c088cf55843900043d28aef830ade4d",
)
maven_jar(
name = "jetty-server",
artifact = "org.eclipse.jetty:jetty-server:" + JETTY_VERS,
- sha1 = "b76ef50e04635f11d4d43bc6ccb7c4482a8384f0",
+ sha1 = "7885cc3d5d7701a444acada7ab97f89846514875",
)
maven_jar(
name = "jetty-jmx",
artifact = "org.eclipse.jetty:jetty-jmx:" + JETTY_VERS,
- sha1 = "f4c2654db1a55f0780acdfcee8bb98550f56ca70",
+ sha1 = "22be18a055850a6cf3b0efd56c789c3929c87e98",
)
maven_jar(
name = "jetty-http",
artifact = "org.eclipse.jetty:jetty-http:" + JETTY_VERS,
- sha1 = "c2e73db2db5c369326b717da71b6587b3da11e0e",
+ sha1 = "d3f0b0fb016ef8d35ffb199d928ffbcbfa121c86",
)
maven_jar(
name = "jetty-io",
artifact = "org.eclipse.jetty:jetty-io:" + JETTY_VERS,
- sha1 = "844af5efe58ab23fd0166a796efef123f4cb06b0",
+ sha1 = "dcb6d4d505ef74898e3a64a38c40195c01e97119",
)
maven_jar(
name = "jetty-util",
artifact = "org.eclipse.jetty:jetty-util:" + JETTY_VERS,
- sha1 = "13e6148bfda7ae511f69ae7e5e3ea898bc9b0e33",
+ sha1 = "3095acb088f4ff9e3fd9aedf98db73e3c18ea849",
)
maven_jar(
diff --git a/java/com/google/gerrit/common/data/GarbageCollectionResult.java b/java/com/google/gerrit/common/data/GarbageCollectionResult.java
index 5ed0158..5e3601e 100644
--- a/java/com/google/gerrit/common/data/GarbageCollectionResult.java
+++ b/java/com/google/gerrit/common/data/GarbageCollectionResult.java
@@ -18,6 +18,7 @@
import java.util.ArrayList;
import java.util.List;
+/** A list of errors occurred during GC. */
public class GarbageCollectionResult {
protected List<Error> errors;
diff --git a/java/com/google/gerrit/common/data/GlobalCapability.java b/java/com/google/gerrit/common/data/GlobalCapability.java
index fbe1deb..10a66cc 100644
--- a/java/com/google/gerrit/common/data/GlobalCapability.java
+++ b/java/com/google/gerrit/common/data/GlobalCapability.java
@@ -20,7 +20,12 @@
import java.util.Collections;
import java.util.List;
-/** Server wide capabilities. Represented as {@link Permission} objects. */
+/**
+ * Server wide capabilities. Represented as {@link Permission} objects.
+ *
+ * <p>Contrary to {@link Permission}, global capabilities do not need a resource to check
+ * permissions on.
+ */
public class GlobalCapability {
/** Ability to view code review metadata refs in repositories. */
public static final String ACCESS_DATABASE = "accessDatabase";
diff --git a/java/com/google/gerrit/extensions/api/projects/BanCommitInput.java b/java/com/google/gerrit/extensions/api/projects/BanCommitInput.java
index b0f674f..b24eca0 100644
--- a/java/com/google/gerrit/extensions/api/projects/BanCommitInput.java
+++ b/java/com/google/gerrit/extensions/api/projects/BanCommitInput.java
@@ -17,6 +17,7 @@
import com.google.common.collect.Lists;
import java.util.List;
+/** Commits that will forbidden to be uploaded. */
public class BanCommitInput {
public List<String> commits;
public String reason;
diff --git a/java/com/google/gerrit/server/account/Realm.java b/java/com/google/gerrit/server/account/Realm.java
index 798b4e8..d56ed07 100644
--- a/java/com/google/gerrit/server/account/Realm.java
+++ b/java/com/google/gerrit/server/account/Realm.java
@@ -24,6 +24,12 @@
import javax.naming.NamingException;
import javax.security.auth.login.LoginException;
+/**
+ * Interface between Gerrit and an account system.
+ *
+ * <p>This interface provides the glue layer between the Gerrit and external account/authentication
+ * systems (eg. LDAP, OpenID).
+ */
public interface Realm {
/** Can the end-user modify this field of their own account? */
boolean allowsEdit(AccountFieldName field);
diff --git a/java/com/google/gerrit/server/account/SetInactiveFlag.java b/java/com/google/gerrit/server/account/SetInactiveFlag.java
index a6c5d5c..32ed694 100644
--- a/java/com/google/gerrit/server/account/SetInactiveFlag.java
+++ b/java/com/google/gerrit/server/account/SetInactiveFlag.java
@@ -32,6 +32,7 @@
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.jgit.errors.ConfigInvalidException;
+/** Toggler for account active state. */
@Singleton
public class SetInactiveFlag {
private final PluginSetContext<AccountActivationValidationListener>
diff --git a/java/com/google/gerrit/server/git/BanCommit.java b/java/com/google/gerrit/server/git/BanCommit.java
index 4473ab7..242c11b 100644
--- a/java/com/google/gerrit/server/git/BanCommit.java
+++ b/java/com/google/gerrit/server/git/BanCommit.java
@@ -20,7 +20,6 @@
import com.google.gerrit.entities.Project;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.extensions.restapi.AuthException;
-import com.google.gerrit.git.LockFailureException;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.IdentifiedUser;
@@ -47,6 +46,12 @@
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
+/**
+ * Logic for banning commits from being uploaded.
+ *
+ * <p>Gerrit has a per-project list of commits that are forbidden to be pushed. This class reads and
+ * writes the banned commits list in {@code refs/meta/reject-commits}.
+ */
@Singleton
public class BanCommit {
/**
@@ -91,9 +96,14 @@
this.tz = gerritIdent.getTimeZone();
}
+ /**
+ * Bans a list of commits from the given project.
+ *
+ * <p>The user must be specified, so it can be checked for the {@code BAN_COMMIT} permission.
+ */
public BanCommitResult ban(
Project.NameKey project, CurrentUser user, List<ObjectId> commitsToBan, String reason)
- throws AuthException, LockFailureException, IOException, PermissionBackendException {
+ throws AuthException, IOException, PermissionBackendException {
permissionBackend.user(user).project(project).check(ProjectPermission.BAN_COMMIT);
final BanCommitResult result = new BanCommitResult();
diff --git a/java/com/google/gerrit/server/git/BanCommitResult.java b/java/com/google/gerrit/server/git/BanCommitResult.java
index 9fadae2..c78123e 100644
--- a/java/com/google/gerrit/server/git/BanCommitResult.java
+++ b/java/com/google/gerrit/server/git/BanCommitResult.java
@@ -18,6 +18,7 @@
import java.util.List;
import org.eclipse.jgit.lib.ObjectId;
+/** The outcome of the {@link com.google.gerrit.server.git.BanCommit} operation. */
public class BanCommitResult {
private final List<ObjectId> newlyBannedCommits = new ArrayList<>(4);
private final List<ObjectId> alreadyBannedCommits = new ArrayList<>(4);
diff --git a/java/com/google/gerrit/server/git/BranchOrderSection.java b/java/com/google/gerrit/server/git/BranchOrderSection.java
index 4c77b61..0266655 100644
--- a/java/com/google/gerrit/server/git/BranchOrderSection.java
+++ b/java/com/google/gerrit/server/git/BranchOrderSection.java
@@ -18,6 +18,13 @@
import com.google.gerrit.entities.RefNames;
import java.util.List;
+/**
+ * An ordering of branches by stability.
+ *
+ * <p>The REST API supports automatically checking if changes on development branches can be merged
+ * into stable branches. This is configured by the {@code branchOrder.branch} project setting. This
+ * class represents the ordered list of branches, by increasing stability.
+ */
public class BranchOrderSection {
/**
diff --git a/java/com/google/gerrit/server/git/ChangeReportFormatter.java b/java/com/google/gerrit/server/git/ChangeReportFormatter.java
index f897a1d..e0efaef 100644
--- a/java/com/google/gerrit/server/git/ChangeReportFormatter.java
+++ b/java/com/google/gerrit/server/git/ChangeReportFormatter.java
@@ -18,6 +18,7 @@
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.Change;
+/** Formatter for git command-line progress messages. */
public interface ChangeReportFormatter {
@AutoValue
public abstract static class Input {
diff --git a/java/com/google/gerrit/server/git/DefaultChangeReportFormatter.java b/java/com/google/gerrit/server/git/DefaultChangeReportFormatter.java
index 5866c57..4f6094e 100644
--- a/java/com/google/gerrit/server/git/DefaultChangeReportFormatter.java
+++ b/java/com/google/gerrit/server/git/DefaultChangeReportFormatter.java
@@ -22,7 +22,7 @@
import com.google.inject.Inject;
import java.util.Optional;
-/** Print a change description for use in git command-line progress. */
+/** Default formatter for change descriptions for use in git command-line progress. */
public class DefaultChangeReportFormatter implements ChangeReportFormatter {
private static final int SUBJECT_MAX_LENGTH = 80;
private static final String SUBJECT_CROP_APPENDIX = "...";
diff --git a/java/com/google/gerrit/server/git/DefaultQueueOp.java b/java/com/google/gerrit/server/git/DefaultQueueOp.java
index b30acfa..9fb1a9b 100644
--- a/java/com/google/gerrit/server/git/DefaultQueueOp.java
+++ b/java/com/google/gerrit/server/git/DefaultQueueOp.java
@@ -17,6 +17,10 @@
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
+/**
+ * Wrapper class so a Runnable can schedule itself onto the Gerrit Workqueue. Subclasses must
+ * implement the {@code run} method.
+ */
public abstract class DefaultQueueOp implements Runnable {
private final WorkQueue workQueue;
diff --git a/java/com/google/gerrit/server/git/GarbageCollection.java b/java/com/google/gerrit/server/git/GarbageCollection.java
index 090d439..9b52f48 100644
--- a/java/com/google/gerrit/server/git/GarbageCollection.java
+++ b/java/com/google/gerrit/server/git/GarbageCollection.java
@@ -16,6 +16,7 @@
import com.google.common.collect.Sets;
import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.data.GarbageCollectionResult;
import com.google.gerrit.entities.Project;
import com.google.gerrit.extensions.events.GarbageCollectorListener;
@@ -37,6 +38,7 @@
import org.eclipse.jgit.lib.TextProgressMonitor;
import org.eclipse.jgit.storage.pack.PackConfig;
+/** Serial execution of GC on a list of repositories. */
public class GarbageCollection {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@@ -69,8 +71,9 @@
return run(projectNames, gcConfig.isAggressive(), writer);
}
+ /** Runs GC on the given projects, serially. Progress is written to writer if non-null. */
public GarbageCollectionResult run(
- List<Project.NameKey> projectNames, boolean aggressive, PrintWriter writer) {
+ List<Project.NameKey> projectNames, boolean aggressive, @Nullable PrintWriter writer) {
GarbageCollectionResult result = new GarbageCollectionResult();
Set<Project.NameKey> projectsToGc = gcQueue.addAll(projectNames);
for (Project.NameKey projectName :
diff --git a/java/com/google/gerrit/server/git/GarbageCollectionQueue.java b/java/com/google/gerrit/server/git/GarbageCollectionQueue.java
index e3a923b..5df9ab5 100644
--- a/java/com/google/gerrit/server/git/GarbageCollectionQueue.java
+++ b/java/com/google/gerrit/server/git/GarbageCollectionQueue.java
@@ -21,6 +21,7 @@
import java.util.HashSet;
import java.util.Set;
+/** A thread-safe list of projects scheduled for GC. */
@Singleton
public class GarbageCollectionQueue {
private final Set<Project.NameKey> projectsScheduledForGc = new HashSet<>();
diff --git a/java/com/google/gerrit/server/git/MergedByPushOp.java b/java/com/google/gerrit/server/git/MergedByPushOp.java
index 01d5380..b272cba 100644
--- a/java/com/google/gerrit/server/git/MergedByPushOp.java
+++ b/java/com/google/gerrit/server/git/MergedByPushOp.java
@@ -45,6 +45,12 @@
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
+/**
+ * Operation to close a change on push.
+ *
+ * <p>When we find a change corresponding to a commit that is pushed to a branch directly, we close
+ * the change. This class marks the change as merged, and sends out the email notification.
+ */
public class MergedByPushOp implements BatchUpdateOp {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
diff --git a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
index 5f6d4fd..e03e0fc 100644
--- a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
@@ -1428,7 +1428,6 @@
private final ProjectState projectState;
private final boolean defaultPublishComments;
- boolean deprecatedTopicSeen;
final ReceiveCommand cmd;
final LabelTypes labelTypes;
/**
@@ -1590,7 +1589,6 @@
IdentifiedUser user, ProjectState projectState, ReceiveCommand cmd, LabelTypes labelTypes) {
this.user = user;
this.projectState = projectState;
- this.deprecatedTopicSeen = false;
this.cmd = cmd;
this.labelTypes = labelTypes;
GeneralPreferencesInfo prefs = user.state().generalPreferences();
@@ -1654,9 +1652,7 @@
/**
* returns the destination ref of the magic branch, and populates options in the cmdLineParser.
*/
- String parse(
- Repository repo, ReceivePackRefCache refCache, ListMultimap<String, String> pushOptions)
- throws CmdLineException, IOException {
+ String parse(ListMultimap<String, String> pushOptions) throws CmdLineException {
String ref = RefNames.fullName(MagicBranch.getDestBranchName(cmd.getRefName()));
ListMultimap<String, String> options = LinkedListMultimap.create(pushOptions);
@@ -1678,28 +1674,7 @@
if (!options.isEmpty()) {
cmdLineParser.parseOptionMap(options);
}
-
- // We accept refs/for/BRANCHNAME/TOPIC. Since we don't know
- // for sure where the branch ends and the topic starts, look
- // backward for a split that works. This behavior is deprecated.
- String head = readHEAD(repo);
- int split = ref.length();
- for (; ; ) {
- String name = ref.substring(0, split);
- if (refCache.exactRef(name) != null || name.equals(head)) {
- break;
- }
-
- split = name.lastIndexOf('/', split - 1);
- if (split <= Constants.R_REFS.length()) {
- return ref;
- }
- }
- if (split < ref.length()) {
- topic = Strings.emptyToNull(ref.substring(split + 1));
- deprecatedTopicSeen = true;
- }
- return ref.substring(0, split);
+ return ref;
}
public boolean shouldSetWorkInProgressOnNewChanges() {
@@ -1754,7 +1729,7 @@
magicBranch.cmdLineParser = optionParserFactory.create(magicBranch);
try {
- ref = magicBranch.parse(repo, receivePackRefCache, pushOptions);
+ ref = magicBranch.parse(pushOptions);
} catch (CmdLineException e) {
if (!magicBranch.cmdLineParser.wasHelpRequestedByOption()) {
logger.atFine().log("Invalid branch syntax");
@@ -1929,13 +1904,6 @@
return;
}
- if (magicBranch.deprecatedTopicSeen) {
- messages.add(
- new ValidationMessage(
- "WARNING: deprecated topic syntax. Use -o topic=TOPIC instead", false));
- logger.atInfo().log("deprecated topic push seen for project %s", project.getName());
- }
-
if (validateConnected(magicBranch.cmd, magicBranch.dest, tip)) {
this.magicBranch = magicBranch;
this.resultChangeIds.setMagicPush(true);
diff --git a/java/com/google/gerrit/server/mail/send/DeleteKeySender.java b/java/com/google/gerrit/server/mail/send/DeleteKeySender.java
index c9bb1e4..defacd84 100644
--- a/java/com/google/gerrit/server/mail/send/DeleteKeySender.java
+++ b/java/com/google/gerrit/server/mail/send/DeleteKeySender.java
@@ -25,6 +25,9 @@
import java.util.Collections;
import java.util.List;
+/**
+ * Sender that informs a user by email about the removal of an SSH or GPG key from their account.
+ */
public class DeleteKeySender extends OutgoingEmail {
public interface Factory {
DeleteKeySender create(IdentifiedUser user, AccountSshKey sshKey);
diff --git a/java/com/google/gerrit/server/mail/send/HttpPasswordUpdateSender.java b/java/com/google/gerrit/server/mail/send/HttpPasswordUpdateSender.java
index 2db2d6d..f24ad7a 100644
--- a/java/com/google/gerrit/server/mail/send/HttpPasswordUpdateSender.java
+++ b/java/com/google/gerrit/server/mail/send/HttpPasswordUpdateSender.java
@@ -21,6 +21,7 @@
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
+/** Sender that informs a user by email that the HTTP password of their account was updated. */
public class HttpPasswordUpdateSender extends OutgoingEmail {
public interface Factory {
HttpPasswordUpdateSender create(IdentifiedUser user, String operation);
diff --git a/java/com/google/gerrit/server/project/DefaultProjectNameLockManager.java b/java/com/google/gerrit/server/project/DefaultProjectNameLockManager.java
index 000fb09..ab347e5 100644
--- a/java/com/google/gerrit/server/project/DefaultProjectNameLockManager.java
+++ b/java/com/google/gerrit/server/project/DefaultProjectNameLockManager.java
@@ -21,6 +21,7 @@
import com.google.inject.Singleton;
import java.util.concurrent.locks.Lock;
+/** In-memory lock for project names. */
@Singleton
public class DefaultProjectNameLockManager implements ProjectNameLockManager {
diff --git a/java/com/google/gerrit/server/project/ProjectCreator.java b/java/com/google/gerrit/server/project/ProjectCreator.java
index 04d0859..ba44142 100644
--- a/java/com/google/gerrit/server/project/ProjectCreator.java
+++ b/java/com/google/gerrit/server/project/ProjectCreator.java
@@ -55,6 +55,12 @@
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.ReceiveCommand;
+/**
+ * Business logic for creating projects.
+ *
+ * <p>This creates the repository, the underlying configuration in {@code refs/meta/config} and
+ * initializes a first commit if necessary.
+ */
public class ProjectCreator {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
diff --git a/java/com/google/gerrit/server/project/ProjectJson.java b/java/com/google/gerrit/server/project/ProjectJson.java
index cd67fbd..f2254d6 100644
--- a/java/com/google/gerrit/server/project/ProjectJson.java
+++ b/java/com/google/gerrit/server/project/ProjectJson.java
@@ -31,6 +31,7 @@
import com.google.inject.Singleton;
import java.util.HashMap;
+/** Collection of routines to populate {@link ProjectInfo}. */
@Singleton
public class ProjectJson {
diff --git a/java/com/google/gerrit/server/project/ProjectNameLockManager.java b/java/com/google/gerrit/server/project/ProjectNameLockManager.java
index 72036a7..f67dd04 100644
--- a/java/com/google/gerrit/server/project/ProjectNameLockManager.java
+++ b/java/com/google/gerrit/server/project/ProjectNameLockManager.java
@@ -17,6 +17,14 @@
import com.google.gerrit.entities.Project;
import java.util.concurrent.locks.Lock;
+/**
+ * A per-repo lock mechanism.
+ *
+ * <p>This ensures that project creation (repo creation, config creation, first commit) is atomic,
+ * and can be used to separate creation and deletion in the delete-project plugin.
+ *
+ * <p>This is an interface because distributed setup may need something beyond an in-memory lock.
+ */
public interface ProjectNameLockManager {
public Lock getLock(Project.NameKey name);
}
diff --git a/java/com/google/gerrit/server/restapi/project/BanCommit.java b/java/com/google/gerrit/server/restapi/project/BanCommit.java
index a20d462..eb5473d 100644
--- a/java/com/google/gerrit/server/restapi/project/BanCommit.java
+++ b/java/com/google/gerrit/server/restapi/project/BanCommit.java
@@ -31,6 +31,7 @@
import java.util.List;
import org.eclipse.jgit.lib.ObjectId;
+/** The REST endpoint that marks commits as banned in a project. */
@Singleton
public class BanCommit implements RestModifyView<ProjectResource, BanCommitInput> {
private final com.google.gerrit.server.git.BanCommit banCommit;
diff --git a/java/com/google/gerrit/server/restapi/project/GarbageCollect.java b/java/com/google/gerrit/server/restapi/project/GarbageCollect.java
index 25a2c90..c5423e6 100644
--- a/java/com/google/gerrit/server/restapi/project/GarbageCollect.java
+++ b/java/com/google/gerrit/server/restapi/project/GarbageCollect.java
@@ -43,6 +43,7 @@
import java.util.Collections;
import java.util.Optional;
+/** REST endpoint that executes GC on a project. */
@RequiresCapability(GlobalCapability.RUN_GC)
@Singleton
public class GarbageCollect
diff --git a/java/com/google/gerrit/server/update/RetryableAction.java b/java/com/google/gerrit/server/update/RetryableAction.java
index 9a2807a..75ebeb37 100644
--- a/java/com/google/gerrit/server/update/RetryableAction.java
+++ b/java/com/google/gerrit/server/update/RetryableAction.java
@@ -37,6 +37,17 @@
* retry via {@link #retryOn(Predicate)}.
*/
public class RetryableAction<T> {
+ /**
+ * Type of an retryable action.
+ *
+ * <p>The action type is used for two purposes:
+ *
+ * <ul>
+ * <li>to determine the default timeout for executing the action (see {@link
+ * RetryHelper#getDefaultTimeout(String)})
+ * <li>as bucket for all retry metrics (see {@link RetryHelper.Metrics})
+ * </ul>
+ */
public enum ActionType {
ACCOUNT_UPDATE,
CHANGE_UPDATE,
diff --git a/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java b/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
index 60cf4f1..4258009 100644
--- a/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
+++ b/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
@@ -485,15 +485,9 @@
@Test
public void pushForMasterWithTopic() throws Exception {
- // specify topic in ref
String topic = "my/topic";
- PushOneCommit.Result r = pushTo("refs/for/master/" + topic);
- r.assertOkStatus();
- r.assertChange(Change.Status.NEW, topic);
- r.assertMessage("deprecated topic syntax");
-
// specify topic as option
- r = pushTo("refs/for/master%topic=" + topic);
+ PushOneCommit.Result r = pushTo("refs/for/master%topic=" + topic);
r.assertOkStatus();
r.assertChange(Change.Status.NEW, topic);
}
@@ -514,14 +508,7 @@
}
@Test
- public void pushForMasterWithTopicInRefExceedLimitFails() throws Exception {
- String topic = Stream.generate(() -> "t").limit(2049).collect(joining());
- PushOneCommit.Result r = pushTo("refs/for/master/" + topic);
- r.assertErrorStatus("topic length exceeds the limit (2048)");
- }
-
- @Test
- public void pushForMasterWithTopicAsOptionExceedLimitFails() throws Exception {
+ public void pushForMasterWithTopicExceedLimitFails() throws Exception {
String topic = Stream.generate(() -> "t").limit(2049).collect(joining());
PushOneCommit.Result r = pushTo("refs/for/master%topic=" + topic);
r.assertErrorStatus("topic length exceeds the limit (2048)");
@@ -605,16 +592,16 @@
public void pushForMasterWithCc() throws Exception {
// cc one user
String topic = "my/topic";
- PushOneCommit.Result r = pushTo("refs/for/master/" + topic + "%cc=" + user.email());
+ PushOneCommit.Result r = pushTo("refs/for/master%topic=" + topic + ",cc=" + user.email());
r.assertOkStatus();
r.assertChange(Change.Status.NEW, topic, ImmutableList.of(), ImmutableList.of(user));
// cc several users
r =
pushTo(
- "refs/for/master/"
+ "refs/for/master%topic="
+ topic
- + "%cc="
+ + ",cc="
+ admin.email()
+ ",cc="
+ user.email()
@@ -632,9 +619,9 @@
String nonExistingEmail = "non.existing@example.com";
r =
pushTo(
- "refs/for/master/"
+ "refs/for/master%topic="
+ topic
- + "%cc="
+ + ",cc="
+ admin.email()
+ ",cc="
+ nonExistingEmail
@@ -684,7 +671,7 @@
public void pushForMasterWithReviewer() throws Exception {
// add one reviewer
String topic = "my/topic";
- PushOneCommit.Result r = pushTo("refs/for/master/" + topic + "%r=" + user.email());
+ PushOneCommit.Result r = pushTo("refs/for/master%topic=" + topic + ",r=" + user.email());
r.assertOkStatus();
r.assertChange(Change.Status.NEW, topic, user);
@@ -693,9 +680,9 @@
accountCreator.create("another-user", "another.user@example.com", "Another User");
r =
pushTo(
- "refs/for/master/"
+ "refs/for/master%topic="
+ topic
- + "%r="
+ + ",r="
+ admin.email()
+ ",r="
+ user.email()
@@ -709,9 +696,9 @@
String nonExistingEmail = "non.existing@example.com";
r =
pushTo(
- "refs/for/master/"
+ "refs/for/master%topic="
+ topic
- + "%r="
+ + ",r="
+ admin.email()
+ ",r="
+ nonExistingEmail
@@ -942,7 +929,7 @@
@Test
public void pushForMasterWithMessage() throws Exception {
- PushOneCommit.Result r = pushTo("refs/for/master/%m=my_test_message");
+ PushOneCommit.Result r = pushTo("refs/for/master%m=my_test_message");
r.assertOkStatus();
r.assertChange(Change.Status.NEW, null);
ChangeInfo ci = get(r.getChangeId(), MESSAGES, ALL_REVISIONS);
@@ -966,7 +953,7 @@
pushFactory.create(admin.newIdent(), testRepo, PushOneCommit.SUBJECT, "a.txt", "content");
// %2C is comma; the value below tests that percent decoding happens after splitting.
// All three ways of representing space ("%20", "+", and "_" are also exercised.
- PushOneCommit.Result r = push.to("refs/for/master/%m=my_test%20+_message%2Cm=");
+ PushOneCommit.Result r = push.to("refs/for/master%m=my_test%20+_message%2Cm=");
r.assertOkStatus();
push =
@@ -977,7 +964,7 @@
"b.txt",
"anotherContent",
r.getChangeId());
- r = push.to("refs/for/master/%m=new_test_message");
+ r = push.to("refs/for/master%m=new_test_message");
r.assertOkStatus();
ChangeInfo ci = get(r.getChangeId(), ALL_REVISIONS);
@@ -997,7 +984,7 @@
// Exercise percent-encoding of UTF-8, underscores, and patterns reserved by git-rev-parse.
PushOneCommit.Result r =
pushTo(
- "refs/for/master/%m="
+ "refs/for/master%m="
+ "Punctu%2E%2e%2Eation%7E%2D%40%7Bu%7D%20%7C%20%28%E2%95%AF%C2%B0%E2%96%A1%C2%B0"
+ "%EF%BC%89%E2%95%AF%EF%B8%B5%20%E2%94%BB%E2%94%81%E2%94%BB%20%5E%5F%5E");
r.assertOkStatus();
@@ -1018,7 +1005,7 @@
@Test
public void pushForMasterWithInvalidPercentEncodedMessage() throws Exception {
- PushOneCommit.Result r = pushTo("refs/for/master/%m=not_percent_decodable_%%oops%20");
+ PushOneCommit.Result r = pushTo("refs/for/master%m=not_percent_decodable_%%oops%20");
r.assertOkStatus();
r.assertChange(Change.Status.NEW, null);
ChangeInfo ci = get(r.getChangeId(), MESSAGES, ALL_REVISIONS);
@@ -1036,7 +1023,7 @@
@Test
public void pushForMasterWithApprovals() throws Exception {
- PushOneCommit.Result r = pushTo("refs/for/master/%l=Code-Review");
+ PushOneCommit.Result r = pushTo("refs/for/master%l=Code-Review");
r.assertOkStatus();
ChangeInfo ci = get(r.getChangeId(), DETAILED_LABELS, MESSAGES, DETAILED_ACCOUNTS);
LabelInfo cr = ci.labels.get("Code-Review");
@@ -1054,7 +1041,7 @@
"b.txt",
"anotherContent",
r.getChangeId());
- r = push.to("refs/for/master/%l=Code-Review+2");
+ r = push.to("refs/for/master%l=Code-Review+2");
ci = get(r.getChangeId(), DETAILED_LABELS, MESSAGES, DETAILED_ACCOUNTS);
cr = ci.labels.get("Code-Review");
@@ -1075,7 +1062,7 @@
"c.txt",
"moreContent",
r.getChangeId());
- r = push.to("refs/for/master/%l=Code-Review+2");
+ r = push.to("refs/for/master%l=Code-Review+2");
ci = get(r.getChangeId(), MESSAGES);
assertThat(Iterables.getLast(ci.messages).message).isEqualTo("Uploaded patch set 3.");
}
@@ -1093,7 +1080,7 @@
"b.txt",
"anotherContent",
r.getChangeId());
- r = push.to("refs/for/master/%l=Code-Review+2");
+ r = push.to("refs/for/master%l=Code-Review+2");
ChangeInfo ci = get(r.getChangeId(), DETAILED_LABELS, MESSAGES, DETAILED_ACCOUNTS);
LabelInfo cr = ci.labels.get("Code-Review");
@@ -1180,7 +1167,7 @@
.create();
// Push this commit as "Administrator" (requires Forge Committer Identity)
- pushHead(testRepo, "refs/for/master/%l=Code-Review+1", false);
+ pushHead(testRepo, "refs/for/master%l=Code-Review+1", false);
// Expected Code-Review votes:
// 1. 0 from User (committer):
@@ -1228,7 +1215,7 @@
.message(PushOneCommit.SUBJECT)
.create();
- pushHead(testRepo, "refs/for/master/%l=Code-Review+1,l=Custom-Label-1", false);
+ pushHead(testRepo, "refs/for/master%l=Code-Review+1,l=Custom-Label-1", false);
ChangeInfo ci = get(GitUtil.getChangeId(testRepo, c).get(), DETAILED_LABELS, DETAILED_ACCOUNTS);
LabelInfo cr = ci.labels.get("Code-Review");
@@ -1258,13 +1245,13 @@
@Test
public void pushForMasterWithApprovals_MissingLabel() throws Exception {
- PushOneCommit.Result r = pushTo("refs/for/master/%l=Verify");
+ PushOneCommit.Result r = pushTo("refs/for/master%l=Verify");
r.assertErrorStatus("label \"Verify\" is not a configured label");
}
@Test
public void pushForMasterWithApprovals_ValueOutOfRange() throws Exception {
- PushOneCommit.Result r = pushTo("refs/for/master/%l=Code-Review-3");
+ PushOneCommit.Result r = pushTo("refs/for/master%l=Code-Review-3");
r.assertErrorStatus("label \"Code-Review\": -3 is not a valid value");
}
@@ -1297,7 +1284,7 @@
"b.txt",
"anotherContent",
r.getChangeId());
- r = push.to("refs/for/master/%hashtag=" + hashtag2);
+ r = push.to("refs/for/master%hashtag=" + hashtag2);
r.assertOkStatus();
expected = ImmutableSet.of(hashtag1, hashtag2);
hashtags = gApi.changes().id(r.getChangeId()).getHashtags();
diff --git a/javatests/com/google/gerrit/acceptance/git/AbstractSubmoduleSubscription.java b/javatests/com/google/gerrit/acceptance/git/AbstractSubmoduleSubscription.java
index 01323a0..a0725c3 100644
--- a/javatests/com/google/gerrit/acceptance/git/AbstractSubmoduleSubscription.java
+++ b/javatests/com/google/gerrit/acceptance/git/AbstractSubmoduleSubscription.java
@@ -139,7 +139,7 @@
String pushedRef = ref;
if (!topic.isEmpty()) {
- pushedRef += "/" + name(topic);
+ pushedRef += "%topic=" + name(topic);
}
String refspec = "HEAD:" + pushedRef;
diff --git a/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsIT.java b/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsIT.java
index 329723b7..0efc4f9 100644
--- a/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsIT.java
+++ b/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsIT.java
@@ -565,7 +565,7 @@
// Create change as user.
PushOneCommit push =
pushFactory.create(user.newIdent(), repo2, "Change 2", "b.txt", "other content");
- PushOneCommit.Result pushResult2 = push.to("refs/for/master/" + name(topic));
+ PushOneCommit.Result pushResult2 = push.to("refs/for/master%topic=" + name(topic));
approve(pushResult2.getChangeId());
// Submit the topic, 2 changes with the different author.
diff --git a/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java b/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java
index 283c95f..0715b7e 100644
--- a/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java
+++ b/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java
@@ -109,7 +109,7 @@
.git()
.push()
.setRemote("origin")
- .setRefSpecs(new RefSpec("HEAD:refs/for/master/" + name("topic-foo")))
+ .setRefSpecs(new RefSpec("HEAD:refs/for/master%topic=" + name("topic-foo")))
.call();
subRepo.reset(c.getId());
@@ -134,7 +134,7 @@
.git()
.push()
.setRemote("origin")
- .setRefSpecs(new RefSpec("HEAD:refs/for/master/" + name("topic-foo")))
+ .setRefSpecs(new RefSpec("HEAD:refs/for/master%topic=" + name("topic-foo")))
.call();
String id1 = getChangeId(subRepo, c1).get();
@@ -212,7 +212,7 @@
.git()
.push()
.setRemote("origin")
- .setRefSpecs(new RefSpec("HEAD:refs/for/master/" + name("topic-foo")))
+ .setRefSpecs(new RefSpec("HEAD:refs/for/master%topic=" + name("topic-foo")))
.call();
subRepo.reset(c.getId());
@@ -237,7 +237,7 @@
.git()
.push()
.setRemote("origin")
- .setRefSpecs(new RefSpec("HEAD:refs/for/master/" + name("topic-foo")))
+ .setRefSpecs(new RefSpec("HEAD:refs/for/master%topic=" + name("topic-foo")))
.call();
RevCommit c4 =
@@ -252,7 +252,7 @@
.git()
.push()
.setRemote("origin")
- .setRefSpecs(new RefSpec("HEAD:refs/for/master/" + name("topic-foo")))
+ .setRefSpecs(new RefSpec("HEAD:refs/for/master%topic=" + name("topic-foo")))
.call();
String id1 = getChangeId(subRepo, c1).get();
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java b/javatests/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java
index eff98b3..0c0a8ed 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java
@@ -614,11 +614,11 @@
@Test
public void submitWithHiddenBranchInSameTopic() throws Throwable {
assume().that(isSubmitWholeTopicEnabled()).isTrue();
- PushOneCommit.Result visible = createChange("refs/for/master/" + name("topic"));
+ PushOneCommit.Result visible = createChange("refs/for/master%topic=" + name("topic"));
Change.Id num = visible.getChange().getId();
createBranch(BranchNameKey.create(project, "hidden"));
- PushOneCommit.Result hidden = createChange("refs/for/hidden/" + name("topic"));
+ PushOneCommit.Result hidden = createChange("refs/for/hidden%topic=" + name("topic"));
approve(hidden.getChangeId());
projectOperations
.project(project)
@@ -789,8 +789,8 @@
// create and submit 2 changes with the same topic
String topic = name("topic");
- PushOneCommit.Result change1 = createChange("refs/for/master/" + topic);
- PushOneCommit.Result change2 = createChange("refs/for/master/" + topic);
+ PushOneCommit.Result change1 = createChange("refs/for/master%topic=" + topic);
+ PushOneCommit.Result change2 = createChange("refs/for/master%topic=" + topic);
approve(change1.getChangeId());
submit(change2.getChangeId());
assertMerged(change1.getChangeId());
@@ -938,7 +938,7 @@
testRepo
.git()
.push()
- .setRefSpecs(new RefSpec("refs/heads/stable:refs/for/stable/" + name("topic")))
+ .setRefSpecs(new RefSpec("refs/heads/stable:refs/for/stable%topic=" + name("topic")))
.call();
// Merge the fix into master.
@@ -955,7 +955,7 @@
testRepo
.git()
.push()
- .setRefSpecs(new RefSpec("refs/heads/master:refs/for/master/" + name("topic")))
+ .setRefSpecs(new RefSpec("refs/heads/master:refs/for/master%topic=" + name("topic")))
.call();
// Submit together.
@@ -1475,6 +1475,6 @@
protected PushOneCommit.Result createChange(
String subject, String fileName, String content, String topic) throws Throwable {
PushOneCommit push = pushFactory.create(admin.newIdent(), testRepo, subject, fileName, content);
- return push.to("refs/for/master/" + name(topic));
+ return push.to("refs/for/master%topic=" + name(topic));
}
}
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/AbstractSubmitByMerge.java b/javatests/com/google/gerrit/acceptance/rest/change/AbstractSubmitByMerge.java
index a4fa84b..f77552d 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/AbstractSubmitByMerge.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/AbstractSubmitByMerge.java
@@ -102,11 +102,11 @@
PushOneCommit.Result change1 =
pushFactory
.create(admin.newIdent(), testRepo, "Change 1", "a", "a")
- .to("refs/for/master/" + name("topic"));
+ .to("refs/for/master%topic=" + name("topic"));
PushOneCommit push2 = pushFactory.create(admin.newIdent(), testRepo, "Change 2", "b", "b");
push2.noParents();
- PushOneCommit.Result change2 = push2.to("refs/for/master/" + name("topic"));
+ PushOneCommit.Result change2 = push2.to("refs/for/master%topic=" + name("topic"));
change2.assertOkStatus();
approve(change1.getChangeId());
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/SubmitResolvingMergeCommitIT.java b/javatests/com/google/gerrit/acceptance/rest/change/SubmitResolvingMergeCommitIT.java
index 73f10e5..a63d60a 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/SubmitResolvingMergeCommitIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/SubmitResolvingMergeCommitIT.java
@@ -217,7 +217,7 @@
"new.txt",
"Conflicting line #2",
ImmutableList.of(f.getCommit()),
- "refs/for/master/" + name("topic1"));
+ "refs/for/master%topic=" + name("topic1"));
PushOneCommit.Result h = createChange(project2, "H");
PushOneCommit.Result i =
@@ -231,7 +231,7 @@
"new.txt",
"Sadly conflicting topic-wise",
ImmutableList.of(i.getCommit(), j.getCommit()),
- "refs/for/master/" + name("topic1"));
+ "refs/for/master%topic=" + name("topic1"));
approve(h.getChangeId());
approve(i.getChangeId());
@@ -253,7 +253,7 @@
"new.txt",
"Resolving conflicts again",
ImmutableList.of(c.getCommit(), g.getCommit()),
- "refs/for/master/" + name("topic1"));
+ "refs/for/master%topic=" + name("topic1"));
approve(l.getChangeId());
assertChangeSetMergeable(l.getChange(), true);
diff --git a/javatests/com/google/gerrit/acceptance/server/change/SubmittedTogetherIT.java b/javatests/com/google/gerrit/acceptance/server/change/SubmittedTogetherIT.java
index 445f787..a97fb49 100644
--- a/javatests/com/google/gerrit/acceptance/server/change/SubmittedTogetherIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/change/SubmittedTogetherIT.java
@@ -117,12 +117,12 @@
// Create two independent commits and push.
RevCommit c1_1 = commitBuilder().add("a.txt", "1").message("subject: 1").create();
String id1 = getChangeId(c1_1);
- pushHead(testRepo, "refs/for/master/" + name("connectingTopic"), false);
+ pushHead(testRepo, "refs/for/master%topic=" + name("connectingTopic"), false);
testRepo.reset(initialHead);
RevCommit c2_1 = commitBuilder().add("b.txt", "2").message("subject: 2").create();
String id2 = getChangeId(c2_1);
- pushHead(testRepo, "refs/for/master/" + name("connectingTopic"), false);
+ pushHead(testRepo, "refs/for/master%topic=" + name("connectingTopic"), false);
if (isSubmitWholeTopicEnabled()) {
assertSubmittedTogether(id1, id2, id1);
@@ -137,12 +137,12 @@
public void anonymousWholeTopic() throws Exception {
RevCommit initialHead = projectOperations.project(project).getHead("master");
RevCommit a = commitBuilder().add("a", "1").message("change 1").create();
- pushHead(testRepo, "refs/for/master/" + name("topic"), false);
+ pushHead(testRepo, "refs/for/master%topic=" + name("topic"), false);
String id1 = getChangeId(a);
testRepo.reset(initialHead);
RevCommit b = commitBuilder().add("b", "1").message("change 2").create();
- pushHead(testRepo, "refs/for/master/" + name("topic"), false);
+ pushHead(testRepo, "refs/for/master%topic=" + name("topic"), false);
String id2 = getChangeId(b);
requestScopeOperations.setApiUserAnonymous();
@@ -161,16 +161,16 @@
RevCommit c1_1 = commitBuilder().add("a.txt", "1").message("subject: 1").create();
String id1 = getChangeId(c1_1);
- pushHead(testRepo, "refs/for/master/" + name("connectingTopic"), false);
+ pushHead(testRepo, "refs/for/master%topic=" + name("connectingTopic"), false);
testRepo.reset(initialHead);
RevCommit c2_1 = commitBuilder().add("b.txt", "2").message("subject: 2").create();
String id2 = getChangeId(c2_1);
- pushHead(testRepo, "refs/for/master/" + name("connectingTopic"), false);
+ pushHead(testRepo, "refs/for/master%topic=" + name("connectingTopic"), false);
RevCommit c3_1 = commitBuilder().add("b.txt", "3").message("subject: 3").create();
String id3 = getChangeId(c3_1);
- pushHead(testRepo, "refs/for/master/" + name("unrelated-topic"), false);
+ pushHead(testRepo, "refs/for/master%topic=" + name("unrelated-topic"), false);
if (isSubmitWholeTopicEnabled()) {
assertSubmittedTogether(id1, id2, id1);
@@ -189,16 +189,16 @@
RevCommit c1_1 = commitBuilder().add("a.txt", "1").message("subject: 1").create();
String id1 = getChangeId(c1_1);
- pushHead(testRepo, "refs/for/master/" + name("connectingTopic"), false);
+ pushHead(testRepo, "refs/for/master%topic=" + name("connectingTopic"), false);
testRepo.reset(initialHead);
RevCommit c2_1 = commitBuilder().add("b.txt", "2").message("subject: 2").create();
String id2 = getChangeId(c2_1);
- pushHead(testRepo, "refs/for/master/" + name("otherConnectingTopic"), false);
+ pushHead(testRepo, "refs/for/master%topic=" + name("otherConnectingTopic"), false);
RevCommit c3_1 = commitBuilder().add("b.txt", "3").message("subject: 3").create();
String id3 = getChangeId(c3_1);
- pushHead(testRepo, "refs/for/master/" + name("connectingTopic"), false);
+ pushHead(testRepo, "refs/for/master%topic=" + name("connectingTopic"), false);
RevCommit c4_1 = commitBuilder().add("b.txt", "4").message("subject: 4").create();
String id4 = getChangeId(c4_1);
@@ -211,7 +211,7 @@
RevCommit c6_1 = commitBuilder().add("c.txt", "6").message("subject: 6").create();
String id6 = getChangeId(c6_1);
- pushHead(testRepo, "refs/for/master/" + name("otherConnectingTopic"), false);
+ pushHead(testRepo, "refs/for/master%topic=" + name("otherConnectingTopic"), false);
if (isSubmitWholeTopicEnabled()) {
assertSubmittedTogether(id1, id6, id5, id3, id2, id1);
diff --git a/package.json b/package.json
index 95edf0b..2656f74 100644
--- a/package.json
+++ b/package.json
@@ -15,7 +15,7 @@
"scripts": {
"start": "polygerrit-ui/run-server.sh",
"test": "WCT_HEADLESS_MODE=1 WCT_ARGS='--verbose -l chrome' ./polygerrit-ui/app/run_test.sh",
- "eslint": "./node_modules/eslint/bin/eslint.js --ignore-pattern 'bower_components/' --ignore-pattern 'gr-linked-text' --ignore-pattern 'scripts/vendor' --ext .html,.js polygerrit-ui/app",
+ "eslint": "./node_modules/eslint/bin/eslint.js --ext .html,.js polygerrit-ui/app",
"eslintfix": "npm run eslint -- --fix",
"test-template": "./polygerrit-ui/app/run_template_test.sh",
"polylint": "bazel test polygerrit-ui/app:polylint_test"
diff --git a/polygerrit-ui/app/lint_test.sh b/polygerrit-ui/app/lint_test.sh
index 35939ba..bcd94ba 100755
--- a/polygerrit-ui/app/lint_test.sh
+++ b/polygerrit-ui/app/lint_test.sh
@@ -19,4 +19,4 @@
exit 1
fi
-${eslint_bin} --ignore-pattern 'bower_components/' --ignore-pattern 'gr-linked-text' --ignore-pattern 'scripts/vendor' --ext .html,.js .
+${eslint_bin} --ext .html,.js .
diff --git a/tools/dev-hooks/pre-commit b/tools/dev-hooks/pre-commit
new file mode 100755
index 0000000..b77f382
--- /dev/null
+++ b/tools/dev-hooks/pre-commit
@@ -0,0 +1,47 @@
+#!/bin/sh
+#
+# Part of Gerrit Code Review (https://www.gerritcodereview.com/)
+#
+# 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.
+
+
+# To enable this hook:
+# - copy this file or content to ".git/hooks/pre-commit"
+# - (optional if you copied this file) make it executable: `chmod +x .git/hooks/pre-commit`
+
+set -ue
+
+# gitroot, default to .
+gitroot=$(git rev-parse --show-cdup)
+gitroot=${gitroot:-.};
+
+# eslint
+eslint=${gitroot}/node_modules/eslint/bin/eslint.js
+
+# Run eslint over changed frontend code
+CHANGED_UI_FILES=$(git diff --cached --name-only -- '*.js' '*.html' | grep 'polygerrit-ui') && true
+if [ "${CHANGED_UI_FILES}" ]; then
+ if $eslint --fix ${CHANGED_UI_FILES}; then
+ # Add again in case lint fix modified some files
+ git add ${CHANGED_UI_FILES}
+ exit 0
+ else
+ echo "Failed to fix all linter issues.";
+ exit 1
+ fi
+else
+ echo "No UI files changed"
+ exit 0
+fi
\ No newline at end of file