Merge "Also mention that MySQL can support replication, not just Postgres"
diff --git a/.gitignore b/.gitignore
index f318b65..465893d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,5 @@
/.settings/org.eclipse.jdt.core.prefs
/.settings/org.maven.ide.eclipse.prefs
/test_site
+/.idea
+/gerrit-parent.iml
diff --git a/Documentation/cmd-ban-commit.txt b/Documentation/cmd-ban-commit.txt
new file mode 100644
index 0000000..fb4a2ac9
--- /dev/null
+++ b/Documentation/cmd-ban-commit.txt
@@ -0,0 +1,60 @@
+gerrit ban-commit
+=================
+
+NAME
+----
+gerrit ban-commit - Bans a commit from a project's repository.
+
+SYNOPSIS
+--------
+[verse]
+'ssh' -p <port> <host> 'gerrit ban-commit'
+ [--reason <REASON>]
+ <PROJECT>
+ <COMMIT> ...
+
+DESCRIPTION
+-----------
+Marks a commit as banned for the specified repository. If a commit is
+banned Gerrit rejects every push that includes this commit with
+link:error-contains-banned-commit.html[contains banned commit ...].
+
+[NOTE]
+This command just marks the commit as banned, but it does not remove
+the commit from the history of any central branch. This needs to be
+done manually.
+
+ACCESS
+------
+Caller must be owner of the project or be a member of the privileged
+'Administrators' group.
+
+SCRIPTING
+---------
+This command is intended to be used in scripts.
+
+OPTIONS
+-------
+<PROJECT>::
+ Required; name of the project for which the commit should be
+ banned.
+
+<COMMIT>::
+ Required; commit(s) that should be banned.
+
+--reason::
+ Reason for banning the commit.
+
+EXAMPLES
+--------
+Ban commit `421919d015c062fd28901fe144a78a555d0b5984` from project
+`myproject`:
+
+====
+ $ ssh -p 29418 review.example.com gerrit ban-commit myproject \
+ 421919d015c062fd28901fe144a78a555d0b5984
+====
+
+GERRIT
+------
+Part of link:index.html[Gerrit Code Review]
diff --git a/Documentation/cmd-index.txt b/Documentation/cmd-index.txt
index b09c3b3..e7d59fb 100644
--- a/Documentation/cmd-index.txt
+++ b/Documentation/cmd-index.txt
@@ -54,6 +54,9 @@
'gerrit approve'::
'Deprecated alias for `gerrit review`.'
+link:cmd-ban-commit.html[gerrit ban-commit]::
+ Bans a commit from a project's repository.
+
link:cmd-ls-groups.html[gerrit ls-groups]::
List groups visible to the caller.
diff --git a/gerrit-antlr/.gitignore b/gerrit-antlr/.gitignore
index 194bedc..fb047af 100644
--- a/gerrit-antlr/.gitignore
+++ b/gerrit-antlr/.gitignore
@@ -2,4 +2,5 @@
/.classpath
/.project
/.settings/org.maven.ide.eclipse.prefs
-/.settings/org.eclipse.m2e.core.prefs
\ No newline at end of file
+/.settings/org.eclipse.m2e.core.prefs
+/gerrit-antlr.iml
\ No newline at end of file
diff --git a/gerrit-antlr/pom.xml b/gerrit-antlr/pom.xml
index aa0d7fd..34cb46f 100644
--- a/gerrit-antlr/pom.xml
+++ b/gerrit-antlr/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-parent</artifactId>
- <version>2.4-SNAPSHOT</version>
+ <version>2.5-SNAPSHOT</version>
</parent>
<artifactId>gerrit-antlr</artifactId>
diff --git a/gerrit-common/.gitignore b/gerrit-common/.gitignore
index 194bedc..759f12c 100644
--- a/gerrit-common/.gitignore
+++ b/gerrit-common/.gitignore
@@ -2,4 +2,5 @@
/.classpath
/.project
/.settings/org.maven.ide.eclipse.prefs
-/.settings/org.eclipse.m2e.core.prefs
\ No newline at end of file
+/.settings/org.eclipse.m2e.core.prefs
+/gerrit-common.iml
\ No newline at end of file
diff --git a/gerrit-common/pom.xml b/gerrit-common/pom.xml
index e7933ea..9b3fe5f 100644
--- a/gerrit-common/pom.xml
+++ b/gerrit-common/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-parent</artifactId>
- <version>2.4-SNAPSHOT</version>
+ <version>2.5-SNAPSHOT</version>
</parent>
<artifactId>gerrit-common</artifactId>
diff --git a/gerrit-ehcache/.gitignore b/gerrit-ehcache/.gitignore
index 20251d4..fe190c9 100644
--- a/gerrit-ehcache/.gitignore
+++ b/gerrit-ehcache/.gitignore
@@ -3,3 +3,4 @@
/.project
/.settings/org.eclipse.m2e.core.prefs
/.settings/org.maven.ide.eclipse.prefs
+/gerrit-ehcache.iml
\ No newline at end of file
diff --git a/gerrit-ehcache/pom.xml b/gerrit-ehcache/pom.xml
index 839c52b..f9117b9 100644
--- a/gerrit-ehcache/pom.xml
+++ b/gerrit-ehcache/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-parent</artifactId>
- <version>2.4-SNAPSHOT</version>
+ <version>2.5-SNAPSHOT</version>
</parent>
<artifactId>gerrit-ehcache</artifactId>
diff --git a/gerrit-gwtdebug/.gitignore b/gerrit-gwtdebug/.gitignore
index 194bedc..4207862 100644
--- a/gerrit-gwtdebug/.gitignore
+++ b/gerrit-gwtdebug/.gitignore
@@ -2,4 +2,5 @@
/.classpath
/.project
/.settings/org.maven.ide.eclipse.prefs
-/.settings/org.eclipse.m2e.core.prefs
\ No newline at end of file
+/.settings/org.eclipse.m2e.core.prefs
+/gerrit-gwtdebug.iml
\ No newline at end of file
diff --git a/gerrit-gwtdebug/pom.xml b/gerrit-gwtdebug/pom.xml
index 734f645..01b93a6 100644
--- a/gerrit-gwtdebug/pom.xml
+++ b/gerrit-gwtdebug/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-parent</artifactId>
- <version>2.4-SNAPSHOT</version>
+ <version>2.5-SNAPSHOT</version>
</parent>
<artifactId>gerrit-gwtdebug</artifactId>
diff --git a/gerrit-gwtui/.gitignore b/gerrit-gwtui/.gitignore
index 194bedc..53d46b3 100644
--- a/gerrit-gwtui/.gitignore
+++ b/gerrit-gwtui/.gitignore
@@ -2,4 +2,5 @@
/.classpath
/.project
/.settings/org.maven.ide.eclipse.prefs
-/.settings/org.eclipse.m2e.core.prefs
\ No newline at end of file
+/.settings/org.eclipse.m2e.core.prefs
+/gerrit-gwtui.iml
\ No newline at end of file
diff --git a/gerrit-gwtui/pom.xml b/gerrit-gwtui/pom.xml
index d6ac743..b3291d1 100644
--- a/gerrit-gwtui/pom.xml
+++ b/gerrit-gwtui/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-parent</artifactId>
- <version>2.4-SNAPSHOT</version>
+ <version>2.5-SNAPSHOT</version>
</parent>
<artifactId>gerrit-gwtui</artifactId>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ErrorDialog.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ErrorDialog.java
index 74a2678..13bba12 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ErrorDialog.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ErrorDialog.java
@@ -25,6 +25,7 @@
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.Widget;
import com.google.gwtexpui.safehtml.client.SafeHtml;
import com.google.gwtexpui.user.client.PluginSafePopupPanel;
import com.google.gwtjsonrpc.client.RemoteJsonException;
@@ -94,6 +95,11 @@
body.add(message.toBlockWidget());
}
+ public ErrorDialog(final Widget w) {
+ this();
+ body.add(w);
+ }
+
/** Create a dialog box to nicely format an exception. */
public ErrorDialog(final Throwable what) {
this();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java
index a8315d8..574f58e 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java
@@ -104,6 +104,7 @@
String errorDialogTitle();
String errorDialogButtons();
String errorDialogErrorType();
+ String errorDialogText();
String fileColumnHeader();
String fileLine();
String fileLineCONTEXT();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java
index 9250ca3..d049ff6 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java
@@ -89,6 +89,7 @@
String initialRevision();
String buttonAddBranch();
String buttonDeleteBranch();
+ String branchDeletionOpenChanges();
String groupListPrev();
String groupListNext();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
index 389ed2c..7e0edec 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
@@ -68,6 +68,8 @@
initialRevision = Initial Revision
buttonAddBranch = Create Branch
buttonDeleteBranch = Delete
+branchDeletionOpenChanges = The following branches were not deleted \
+because they have open changes:
groupListPrev = Previous group
groupListNext = Next group
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectBranchesScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectBranchesScreen.java
index f3ecbb3..56d9417 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectBranchesScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectBranchesScreen.java
@@ -16,16 +16,19 @@
import com.google.gerrit.client.ConfirmationCallback;
import com.google.gerrit.client.ConfirmationDialog;
+import com.google.gerrit.client.ErrorDialog;
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.GitwebLink;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.rpc.ScreenLoadCallback;
+import com.google.gerrit.client.ui.BranchLink;
import com.google.gerrit.client.ui.FancyFlexTable;
import com.google.gerrit.client.ui.HintTextBox;
import com.google.gerrit.common.data.ListBranchesResult;
import com.google.gerrit.common.errors.InvalidNameException;
import com.google.gerrit.common.errors.InvalidRevisionException;
import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
@@ -41,6 +44,7 @@
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
import com.google.gwtjsonrpc.client.RemoteJsonException;
@@ -260,24 +264,52 @@
b.toSafeHtml(), new ConfirmationCallback() {
@Override
public void onOk() {
- Util.PROJECT_SVC.deleteBranch(getProjectKey(), ids,
- new GerritCallback<Set<Branch.NameKey>>() {
- public void onSuccess(final Set<Branch.NameKey> deleted) {
- for (int row = 1; row < table.getRowCount();) {
- final Branch k = getRowItem(row);
- if (k != null && deleted.contains(k.getNameKey())) {
- table.removeRow(row);
- } else {
- row++;
- }
- }
- }
- });
+ deleteBranches(ids);
}
});
confirmationDialog.center();
}
+ private void deleteBranches(final Set<Branch.NameKey> branchIds) {
+ Util.PROJECT_SVC.deleteBranch(getProjectKey(), branchIds,
+ new GerritCallback<Set<Branch.NameKey>>() {
+ public void onSuccess(final Set<Branch.NameKey> deleted) {
+ if (!deleted.isEmpty()) {
+ for (int row = 1; row < table.getRowCount();) {
+ final Branch k = getRowItem(row);
+ if (k != null && deleted.contains(k.getNameKey())) {
+ table.removeRow(row);
+ } else {
+ row++;
+ }
+ }
+ }
+
+ branchIds.removeAll(deleted);
+ if (!branchIds.isEmpty()) {
+ final VerticalPanel p = new VerticalPanel();
+ final ErrorDialog errorDialog = new ErrorDialog(p);
+ final Label l = new Label(Util.C.branchDeletionOpenChanges());
+ l.setStyleName(Gerrit.RESOURCES.css().errorDialogText());
+ p.add(l);
+ for (final Branch.NameKey branch : branchIds) {
+ final BranchLink link =
+ new BranchLink(branch.getParentKey(), Change.Status.NEW,
+ branch.get(), null) {
+ @Override
+ public void go() {
+ errorDialog.hide();
+ super.go();
+ };
+ };
+ p.add(link);
+ }
+ errorDialog.center();
+ }
+ }
+ });
+ }
+
void display(final List<Branch> result) {
canDelete = false;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css b/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
index 87208c6..52c37c3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
@@ -375,6 +375,18 @@
width: 100%;
margin-top: 15px;
}
+.errorDialogText {
+ font-size: 15px;
+ font-family: verdana;
+}
+.errorDialog a,
+.errorDialog a:visited,
+.errorDialog a:hover {
+ color: white;
+ font-weight: bold;
+ font-size: 15px;
+ font-family: verdana;
+}
/** Screen **/
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/SideBySideTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/SideBySideTable.java
index ef3faf8..964ba4b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/SideBySideTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/SideBySideTable.java
@@ -34,6 +34,7 @@
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
+import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.InlineLabel;
import com.google.gwtexpui.safehtml.client.SafeHtml;
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
@@ -382,7 +383,11 @@
CellFormatter fmt = table.getCellFormatter();
for (int i = 0 + offset; i < loopTo + offset; i++) {
- insertRow(row + i);
+ // The overridden version of insertRow adds some css classes we don't
+ // want.
+ super.insertRow(row + i);
+ table.getRowFormatter().setVerticalAlign(row + i,
+ HasVerticalAlignment.ALIGN_TOP);
int lineA = line.getStartA() + i;
int lineB = line.getStartB() + i;
if (numRows < 0) {
diff --git a/gerrit-httpd/.gitignore b/gerrit-httpd/.gitignore
index 194bedc..5bbeafd 100644
--- a/gerrit-httpd/.gitignore
+++ b/gerrit-httpd/.gitignore
@@ -2,4 +2,5 @@
/.classpath
/.project
/.settings/org.maven.ide.eclipse.prefs
-/.settings/org.eclipse.m2e.core.prefs
\ No newline at end of file
+/.settings/org.eclipse.m2e.core.prefs
+/gerrit-httpd.iml
\ No newline at end of file
diff --git a/gerrit-httpd/pom.xml b/gerrit-httpd/pom.xml
index a6374da..ceacb66 100644
--- a/gerrit-httpd/pom.xml
+++ b/gerrit-httpd/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-parent</artifactId>
- <version>2.4-SNAPSHOT</version>
+ <version>2.5-SNAPSHOT</version>
</parent>
<artifactId>gerrit-httpd</artifactId>
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailFactory.java
index 47a9395..ab266f3 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailFactory.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailFactory.java
@@ -134,7 +134,7 @@
detail.setCanEdit(control.getRefControl().canWrite());
if (detail.getChange().getStatus().isOpen()) {
- List<SubmitRecord> submitRecords = control.canSubmit(db, patch.getId());
+ List<SubmitRecord> submitRecords = control.canSubmit(db, patch);
for (SubmitRecord rec : submitRecords) {
if (rec.labels != null) {
for (SubmitRecord.Label lbl : rec.labels) {
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetPublishDetailFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetPublishDetailFactory.java
index 638bfe3..183b5f6 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetPublishDetailFactory.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetPublishDetailFactory.java
@@ -83,7 +83,8 @@
final Change.Id changeId = patchSetId.getParentKey();
final ChangeControl control = changeControlFactory.validateFor(changeId);
change = control.getChange();
- patchSetInfo = infoFactory.get(db, patchSetId);
+ PatchSet patchSet = db.patchSets().get(patchSetId);
+ patchSetInfo = infoFactory.get(change, patchSet);
drafts = db.patchComments().draftByPatchSetAuthor(patchSetId, user.getAccountId()).toList();
aic.want(change.getOwner());
@@ -119,7 +120,7 @@
.toList();
boolean couldSubmit = false;
- List<SubmitRecord> submitRecords = control.canSubmit(db, patchSetId);
+ List<SubmitRecord> submitRecords = control.canSubmit(db, patchSet);
for (SubmitRecord rec : submitRecords) {
if (rec.status == SubmitRecord.Status.OK) {
couldSubmit = true;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/DeleteBranches.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/DeleteBranches.java
index 073e2d7..a3a1c25 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/DeleteBranches.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/DeleteBranches.java
@@ -18,11 +18,13 @@
import com.google.gerrit.httpd.rpc.Handler;
import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.ReplicationQueue;
import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.project.ProjectControl;
+import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
@@ -34,6 +36,7 @@
import java.io.IOException;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.Set;
class DeleteBranches extends Handler<Set<Branch.NameKey>> {
@@ -50,6 +53,7 @@
private final ReplicationQueue replication;
private final IdentifiedUser identifiedUser;
private final ChangeHooks hooks;
+ private final ReviewDb db;
private final Project.NameKey projectName;
private final Set<Branch.NameKey> toRemove;
@@ -60,6 +64,7 @@
final ReplicationQueue replication,
final IdentifiedUser identifiedUser,
final ChangeHooks hooks,
+ final ReviewDb db,
@Assisted Project.NameKey name, @Assisted Set<Branch.NameKey> toRemove) {
this.projectControlFactory = projectControlFactory;
@@ -67,6 +72,7 @@
this.replication = replication;
this.identifiedUser = identifiedUser;
this.hooks = hooks;
+ this.db = db;
this.projectName = name;
this.toRemove = toRemove;
@@ -74,17 +80,23 @@
@Override
public Set<Branch.NameKey> call() throws NoSuchProjectException,
- RepositoryNotFoundException {
+ RepositoryNotFoundException, OrmException {
final ProjectControl projectControl =
projectControlFactory.controlFor(projectName);
- for (Branch.NameKey k : toRemove) {
+ final Iterator<Branch.NameKey> branchIt = toRemove.iterator();
+ while (branchIt.hasNext()) {
+ final Branch.NameKey k = branchIt.next();
if (!projectName.equals(k.getParentKey())) {
throw new IllegalArgumentException("All keys must be from same project");
}
if (!projectControl.controlForRef(k).canDelete()) {
throw new IllegalStateException("Cannot delete " + k.getShortName());
}
+
+ if (db.changes().byBranchOpenAll(k).iterator().hasNext()) {
+ branchIt.remove();
+ }
}
final Set<Branch.NameKey> deleted = new HashSet<Branch.NameKey>();
diff --git a/gerrit-launcher/.gitignore b/gerrit-launcher/.gitignore
index 194bedc..980a6b1 100644
--- a/gerrit-launcher/.gitignore
+++ b/gerrit-launcher/.gitignore
@@ -2,4 +2,5 @@
/.classpath
/.project
/.settings/org.maven.ide.eclipse.prefs
-/.settings/org.eclipse.m2e.core.prefs
\ No newline at end of file
+/.settings/org.eclipse.m2e.core.prefs
+/gerrit-launcher.iml
\ No newline at end of file
diff --git a/gerrit-launcher/pom.xml b/gerrit-launcher/pom.xml
index 7d07652..e700351 100644
--- a/gerrit-launcher/pom.xml
+++ b/gerrit-launcher/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-parent</artifactId>
- <version>2.4-SNAPSHOT</version>
+ <version>2.5-SNAPSHOT</version>
</parent>
<artifactId>gerrit-launcher</artifactId>
diff --git a/gerrit-main/.gitignore b/gerrit-main/.gitignore
index 194bedc..c847710 100644
--- a/gerrit-main/.gitignore
+++ b/gerrit-main/.gitignore
@@ -2,4 +2,5 @@
/.classpath
/.project
/.settings/org.maven.ide.eclipse.prefs
-/.settings/org.eclipse.m2e.core.prefs
\ No newline at end of file
+/.settings/org.eclipse.m2e.core.prefs
+/gerrit-main.iml
\ No newline at end of file
diff --git a/gerrit-main/pom.xml b/gerrit-main/pom.xml
index 9d8320c..bb2d763 100644
--- a/gerrit-main/pom.xml
+++ b/gerrit-main/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-parent</artifactId>
- <version>2.4-SNAPSHOT</version>
+ <version>2.5-SNAPSHOT</version>
</parent>
<artifactId>gerrit-main</artifactId>
diff --git a/gerrit-openid/.gitignore b/gerrit-openid/.gitignore
index 194bedc..158faf1 100644
--- a/gerrit-openid/.gitignore
+++ b/gerrit-openid/.gitignore
@@ -2,4 +2,5 @@
/.classpath
/.project
/.settings/org.maven.ide.eclipse.prefs
-/.settings/org.eclipse.m2e.core.prefs
\ No newline at end of file
+/.settings/org.eclipse.m2e.core.prefs
+/gerrit-openid.iml
\ No newline at end of file
diff --git a/gerrit-openid/pom.xml b/gerrit-openid/pom.xml
index ed2625e..fa4ab95 100644
--- a/gerrit-openid/pom.xml
+++ b/gerrit-openid/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-parent</artifactId>
- <version>2.4-SNAPSHOT</version>
+ <version>2.5-SNAPSHOT</version>
</parent>
<artifactId>gerrit-openid</artifactId>
diff --git a/gerrit-patch-commonsnet/.gitignore b/gerrit-patch-commonsnet/.gitignore
index 194bedc..121f8e90 100644
--- a/gerrit-patch-commonsnet/.gitignore
+++ b/gerrit-patch-commonsnet/.gitignore
@@ -2,4 +2,5 @@
/.classpath
/.project
/.settings/org.maven.ide.eclipse.prefs
-/.settings/org.eclipse.m2e.core.prefs
\ No newline at end of file
+/.settings/org.eclipse.m2e.core.prefs
+/gerrit-patch-commonsnet.iml
\ No newline at end of file
diff --git a/gerrit-patch-commonsnet/pom.xml b/gerrit-patch-commonsnet/pom.xml
index 75ee12e..f1a8b3e 100644
--- a/gerrit-patch-commonsnet/pom.xml
+++ b/gerrit-patch-commonsnet/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-parent</artifactId>
- <version>2.4-SNAPSHOT</version>
+ <version>2.5-SNAPSHOT</version>
</parent>
<artifactId>gerrit-patch-commonsnet</artifactId>
diff --git a/gerrit-patch-jgit/.gitignore b/gerrit-patch-jgit/.gitignore
index 194bedc..7c4c433 100644
--- a/gerrit-patch-jgit/.gitignore
+++ b/gerrit-patch-jgit/.gitignore
@@ -2,4 +2,5 @@
/.classpath
/.project
/.settings/org.maven.ide.eclipse.prefs
-/.settings/org.eclipse.m2e.core.prefs
\ No newline at end of file
+/.settings/org.eclipse.m2e.core.prefs
+/gerrit-patch-jgit.iml
\ No newline at end of file
diff --git a/gerrit-patch-jgit/pom.xml b/gerrit-patch-jgit/pom.xml
index f8190f5..65223fb 100644
--- a/gerrit-patch-jgit/pom.xml
+++ b/gerrit-patch-jgit/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-parent</artifactId>
- <version>2.4-SNAPSHOT</version>
+ <version>2.5-SNAPSHOT</version>
</parent>
<artifactId>gerrit-patch-jgit</artifactId>
diff --git a/gerrit-pgm/.gitignore b/gerrit-pgm/.gitignore
index 194bedc..dafe355 100644
--- a/gerrit-pgm/.gitignore
+++ b/gerrit-pgm/.gitignore
@@ -2,4 +2,5 @@
/.classpath
/.project
/.settings/org.maven.ide.eclipse.prefs
-/.settings/org.eclipse.m2e.core.prefs
\ No newline at end of file
+/.settings/org.eclipse.m2e.core.prefs
+/gerrit-pgm.iml
\ No newline at end of file
diff --git a/gerrit-pgm/pom.xml b/gerrit-pgm/pom.xml
index 1463d15..a015219 100644
--- a/gerrit-pgm/pom.xml
+++ b/gerrit-pgm/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-parent</artifactId>
- <version>2.4-SNAPSHOT</version>
+ <version>2.5-SNAPSHOT</version>
</parent>
<artifactId>gerrit-pgm</artifactId>
diff --git a/gerrit-prettify/.gitignore b/gerrit-prettify/.gitignore
index 194bedc..8cf95ef 100644
--- a/gerrit-prettify/.gitignore
+++ b/gerrit-prettify/.gitignore
@@ -2,4 +2,5 @@
/.classpath
/.project
/.settings/org.maven.ide.eclipse.prefs
-/.settings/org.eclipse.m2e.core.prefs
\ No newline at end of file
+/.settings/org.eclipse.m2e.core.prefs
+/gerrit-prettify.iml
\ No newline at end of file
diff --git a/gerrit-prettify/pom.xml b/gerrit-prettify/pom.xml
index f5bd3d6..9354274 100644
--- a/gerrit-prettify/pom.xml
+++ b/gerrit-prettify/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-parent</artifactId>
- <version>2.4-SNAPSHOT</version>
+ <version>2.5-SNAPSHOT</version>
</parent>
<artifactId>gerrit-prettify</artifactId>
diff --git a/gerrit-reviewdb/.gitignore b/gerrit-reviewdb/.gitignore
index 194bedc..812ddd0 100644
--- a/gerrit-reviewdb/.gitignore
+++ b/gerrit-reviewdb/.gitignore
@@ -2,4 +2,5 @@
/.classpath
/.project
/.settings/org.maven.ide.eclipse.prefs
-/.settings/org.eclipse.m2e.core.prefs
\ No newline at end of file
+/.settings/org.eclipse.m2e.core.prefs
+/gerrit-reviewdb.iml
\ No newline at end of file
diff --git a/gerrit-reviewdb/pom.xml b/gerrit-reviewdb/pom.xml
index 24d6a1b..f9fb49e 100644
--- a/gerrit-reviewdb/pom.xml
+++ b/gerrit-reviewdb/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-parent</artifactId>
- <version>2.4-SNAPSHOT</version>
+ <version>2.5-SNAPSHOT</version>
</parent>
<artifactId>gerrit-reviewdb</artifactId>
diff --git a/gerrit-server/.gitignore b/gerrit-server/.gitignore
index 194bedc..9324efe 100644
--- a/gerrit-server/.gitignore
+++ b/gerrit-server/.gitignore
@@ -2,4 +2,5 @@
/.classpath
/.project
/.settings/org.maven.ide.eclipse.prefs
-/.settings/org.eclipse.m2e.core.prefs
\ No newline at end of file
+/.settings/org.eclipse.m2e.core.prefs
+/gerrit-server.iml
\ No newline at end of file
diff --git a/gerrit-server/pom.xml b/gerrit-server/pom.xml
index 58e43cf..f35608c 100644
--- a/gerrit-server/pom.xml
+++ b/gerrit-server/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-parent</artifactId>
- <version>2.4-SNAPSHOT</version>
+ <version>2.5-SNAPSHOT</version>
</parent>
<artifactId>gerrit-server</artifactId>
diff --git a/gerrit-server/src/main/java/com/google/gerrit/rules/StoredValues.java b/gerrit-server/src/main/java/com/google/gerrit/rules/StoredValues.java
index 8ab9471..b9f476b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/rules/StoredValues.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/rules/StoredValues.java
@@ -16,12 +16,16 @@
import static com.google.gerrit.rules.StoredValue.create;
+import com.google.common.collect.Maps;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.PatchSetInfo;
import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.AnonymousUser;
+import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.patch.PatchList;
import com.google.gerrit.server.patch.PatchListCache;
@@ -29,6 +33,7 @@
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
import com.google.gerrit.server.project.ChangeControl;
+import com.google.gerrit.server.query.change.ChangeData;
import com.googlecode.prolog_cafe.lang.Prolog;
import com.googlecode.prolog_cafe.lang.SystemException;
@@ -37,21 +42,25 @@
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
+import java.util.Map;
+
public final class StoredValues {
public static final StoredValue<ReviewDb> REVIEW_DB = create(ReviewDb.class);
public static final StoredValue<Change> CHANGE = create(Change.class);
- public static final StoredValue<PatchSet.Id> PATCH_SET_ID = create(PatchSet.Id.class);
+ public static final StoredValue<ChangeData> CHANGE_DATA = create(ChangeData.class);
+ public static final StoredValue<PatchSet> PATCH_SET = create(PatchSet.class);
public static final StoredValue<ChangeControl> CHANGE_CONTROL = create(ChangeControl.class);
public static final StoredValue<PatchSetInfo> PATCH_SET_INFO = new StoredValue<PatchSetInfo>() {
@Override
public PatchSetInfo createValue(Prolog engine) {
- PatchSet.Id patchSetId = StoredValues.PATCH_SET_ID.get(engine);
+ Change change = StoredValues.CHANGE.get(engine);
+ PatchSet ps = StoredValues.PATCH_SET.get(engine);
PrologEnvironment env = (PrologEnvironment) engine.control;
PatchSetInfoFactory patchInfoFactory =
env.getInjector().getInstance(PatchSetInfoFactory.class);
try {
- return patchInfoFactory.get(REVIEW_DB.get(engine), patchSetId);
+ return patchInfoFactory.get(change, ps);
} catch (PatchSetInfoNotAvailableException e) {
throw new SystemException(e.getMessage());
}
@@ -102,6 +111,23 @@
}
};
+ public static final StoredValue<AnonymousUser> ANONYMOUS_USER =
+ new StoredValue<AnonymousUser>() {
+ @Override
+ protected AnonymousUser createValue(Prolog engine) {
+ PrologEnvironment env = (PrologEnvironment) engine.control;
+ return env.getInjector().getInstance(AnonymousUser.class);
+ }
+ };
+
+ public static final StoredValue<Map<Account.Id, IdentifiedUser>> USERS =
+ new StoredValue<Map<Account.Id, IdentifiedUser>>() {
+ @Override
+ protected Map<Account.Id, IdentifiedUser> createValue(Prolog engine) {
+ return Maps.newHashMap();
+ }
+ };
+
private StoredValues() {
}
}
\ No newline at end of file
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java
index 6c216a8..e469c34 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java
@@ -426,6 +426,56 @@
}
}
+ /**
+ * Unlink an authentication identity from an existing account.
+ *
+ * @param from account to unlink the identity from.
+ * @param who the identity to delete
+ * @return the result of unlinking the identity from the user.
+ * @throws AccountException the identity belongs to a different account, or it
+ * cannot be unlinked at this time.
+ */
+ public AuthResult unlink(final Account.Id from, AuthRequest who)
+ throws AccountException {
+ try {
+ final ReviewDb db = schema.open();
+ try {
+ who = realm.unlink(db, from, who);
+
+ final AccountExternalId.Key key = id(who);
+ AccountExternalId extId = db.accountExternalIds().get(key);
+ if (extId != null) {
+ if (!extId.getAccountId().equals(from)) {
+ throw new AccountException("Identity in use by another account");
+ }
+ db.accountExternalIds().delete(Collections.singleton(extId));
+
+ if (who.getEmailAddress() != null) {
+ final Account a = db.accounts().get(from);
+ if (a.getPreferredEmail() != null
+ && a.getPreferredEmail().equals(who.getEmailAddress())) {
+ a.setPreferredEmail(null);
+ db.accounts().update(Collections.singleton(a));
+ }
+ byEmailCache.evict(who.getEmailAddress());
+ byIdCache.evict(from);
+ }
+
+ } else {
+ throw new AccountException("Identity not found");
+ }
+
+ return new AuthResult(from, key, false);
+
+ } finally {
+ db.close();
+ }
+ } catch (OrmException e) {
+ throw new AccountException("Cannot unlink identity", e);
+ }
+ }
+
+
private static AccountExternalId.Key id(final AuthRequest who) {
return new AccountExternalId.Key(who.getExternalId());
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/DefaultRealm.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/DefaultRealm.java
index 4f3392c..844e604 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/DefaultRealm.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/DefaultRealm.java
@@ -56,6 +56,11 @@
}
@Override
+ public AuthRequest unlink(ReviewDb db, Account.Id from, AuthRequest who) {
+ return who;
+ }
+
+ @Override
public void onCreateAccount(final AuthRequest who, final Account account) {
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/Realm.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/Realm.java
index fc7c0be..2ebd0e5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/Realm.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/Realm.java
@@ -29,6 +29,9 @@
public AuthRequest link(ReviewDb db, Account.Id to, AuthRequest who)
throws AccountException;
+ public AuthRequest unlink(ReviewDb db, Account.Id to, AuthRequest who)
+ throws AccountException;
+
public void onCreateAccount(AuthRequest who, Account account);
public GroupMembership groups(AccountState who);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapRealm.java b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapRealm.java
index e085d1e..910bf06 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapRealm.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapRealm.java
@@ -255,6 +255,11 @@
}
@Override
+ public AuthRequest unlink(ReviewDb db, Account.Id from, AuthRequest who) {
+ return who;
+ }
+
+ @Override
public void onCreateAccount(final AuthRequest who, final Account account) {
usernameCache.put(who.getLocalUser(), account.getId());
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/Submit.java b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/Submit.java
index abd3582..6648c7b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/Submit.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/Submit.java
@@ -80,7 +80,7 @@
throw new NoSuchChangeException(changeId);
}
- List<SubmitRecord> submitResult = control.canSubmit(db, patchSetId);
+ List<SubmitRecord> submitResult = control.canSubmit(db, patch);
if (submitResult.isEmpty()) {
throw new IllegalStateException(
"ChangeControl.canSubmit returned empty list");
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigUtil.java
index e76249a..6068c50 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigUtil.java
@@ -16,27 +16,10 @@
import static org.eclipse.jgit.util.StringUtils.equalsIgnoreCase;
-import com.google.common.base.Function;
-import com.google.common.base.Predicates;
-import com.google.common.collect.Iterables;
-import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gerrit.reviewdb.client.AccountGroupName;
-import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gwtorm.server.OrmException;
-import com.google.gwtorm.server.OrmRuntimeException;
-import com.google.gwtorm.server.SchemaFactory;
-
import org.eclipse.jgit.lib.Config;
-import org.slf4j.Logger;
-
import java.lang.reflect.InvocationTargetException;
-import java.text.MessageFormat;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
-import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -303,83 +286,6 @@
}
}
- /**
- * Resolve groups from group names, via the database. Group names not found in
- * the database will be skipped.
- *
- * @param dbfactory database to resolve from.
- * @param groupNames group names to resolve.
- * @param log log for any warnings and errors.
- * @param groupNotFoundWarning formatted message to output to the log for each
- * group name which is not found in the database. <code>{0}</code> will
- * be replaced with the group name.
- * @return the actual groups resolved from the database. If no groups are
- * found, returns an empty {@code Set}, never {@code null}.
- */
- public static Set<AccountGroup.UUID> groupsFor(
- SchemaFactory<ReviewDb> dbfactory, String[] groupNames, Logger log,
- String groupNotFoundWarning) {
- final Set<AccountGroup.UUID> result = new HashSet<AccountGroup.UUID>();
- try {
- final ReviewDb db = dbfactory.open();
- try {
- List<AccountGroupName> groups = db.accountGroupNames().get(
- Iterables.transform(Arrays.asList(groupNames),
- new Function<String, AccountGroup.NameKey>() {
- @Override
- public AccountGroup.NameKey apply(String name) {
- return new AccountGroup.NameKey(name);
- }
- })).toList();
-
- Iterator<AccountGroup> ags = db.accountGroups().get(
- Iterables.transform(Iterables.filter(groups, Predicates.notNull()),
- new Function<AccountGroupName, AccountGroup.Id>() {
- @Override
- public AccountGroup.Id apply(AccountGroupName group) {
- return group.getId();
- }
- })).iterator();
-
- for (int i = 0; i < groupNames.length; i++) {
- if (groups.get(i) == null) {
- log.warn(MessageFormat.format(groupNotFoundWarning, groupNames[i]));
- continue;
- }
- AccountGroup ag = ags.next();
- if (ag == null) {
- log.warn(MessageFormat.format(groupNotFoundWarning, groupNames[i]));
- } else {
- result.add(ag.getGroupUUID());
- }
- }
- } finally {
- db.close();
- }
- } catch (OrmRuntimeException e) {
- log.error("Database error, cannot load groups", e);
- } catch (OrmException e) {
- log.error("Database error, cannot load groups", e);
- }
- return result;
- }
-
- /**
- * Resolve groups from group names, via the database. Group names not found in
- * the database will be skipped.
- *
- * @param dbfactory database to resolve from.
- * @param groupNames group names to resolve.
- * @param log log for any warnings and errors.
- * @return the actual groups resolved from the database. If no groups are
- * found, returns an empty {@code Set}, never {@code null}.
- */
- public static Set<AccountGroup.UUID> groupsFor(
- SchemaFactory<ReviewDb> dbfactory, String[] groupNames, Logger log) {
- return groupsFor(dbfactory, groupNames, log,
- "Group \"{0}\" not in database, skipping.");
- }
-
private static boolean match(final String a, final String... cases) {
for (final String b : cases) {
if (equalsIgnoreCase(a, b)) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritRequestModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritRequestModule.java
index 944bbeb..f581adc 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritRequestModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritRequestModule.java
@@ -35,6 +35,7 @@
import com.google.gerrit.server.changedetail.RestoreChange;
import com.google.gerrit.server.changedetail.Submit;
import com.google.gerrit.server.git.AsyncReceiveCommits;
+import com.google.gerrit.server.git.BanCommit;
import com.google.gerrit.server.git.CreateCodeReviewNotes;
import com.google.gerrit.server.git.MergeOp;
import com.google.gerrit.server.git.MetaDataUpdate;
@@ -117,5 +118,6 @@
factory(CreateProject.Factory.class);
factory(Submit.Factory.class);
factory(SuggestParentCandidates.Factory.class);
+ factory(BanCommit.Factory.class);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitReceivePackGroupsProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitReceivePackGroupsProvider.java
index 9992f18..c89f025 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitReceivePackGroupsProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitReceivePackGroupsProvider.java
@@ -15,8 +15,7 @@
package com.google.gerrit.server.config;
import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gwtorm.server.SchemaFactory;
+import com.google.gerrit.server.account.GroupCache;
import com.google.inject.Inject;
import org.eclipse.jgit.lib.Config;
@@ -25,9 +24,9 @@
public class GitReceivePackGroupsProvider extends GroupSetProvider {
@Inject
- public GitReceivePackGroupsProvider(@GerritServerConfig Config config,
- SchemaFactory<ReviewDb> db) {
- super(config, db, "receive", null, "allowGroup");
+ public GitReceivePackGroupsProvider(GroupCache gc,
+ @GerritServerConfig Config config) {
+ super(gc, config, "receive", null, "allowGroup");
// If no group was set, default to "registered users"
//
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitUploadPackGroupsProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitUploadPackGroupsProvider.java
index 76d8844..b5de742 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitUploadPackGroupsProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitUploadPackGroupsProvider.java
@@ -15,8 +15,7 @@
package com.google.gerrit.server.config;
import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gwtorm.server.SchemaFactory;
+import com.google.gerrit.server.account.GroupCache;
import com.google.inject.Inject;
import org.eclipse.jgit.lib.Config;
@@ -26,9 +25,9 @@
public class GitUploadPackGroupsProvider extends GroupSetProvider {
@Inject
- public GitUploadPackGroupsProvider(@GerritServerConfig Config config,
- SchemaFactory<ReviewDb> db) {
- super(config, db, "upload", null, "allowGroup");
+ public GitUploadPackGroupsProvider(GroupCache gc,
+ @GerritServerConfig Config config) {
+ super(gc, config, "upload", null, "allowGroup");
// If no group was set, default to "registered users" and "anonymous"
//
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GroupSetProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GroupSetProvider.java
index 15711af..3619cda 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GroupSetProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GroupSetProvider.java
@@ -14,12 +14,9 @@
package com.google.gerrit.server.config;
-import static com.google.gerrit.server.config.ConfigUtil.groupsFor;
-import static java.util.Collections.unmodifiableSet;
-
+import com.google.common.collect.ImmutableSet;
import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gwtorm.server.SchemaFactory;
+import com.google.gerrit.server.account.GroupCache;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -37,10 +34,20 @@
protected Set<AccountGroup.UUID> groupIds;
@Inject
- protected GroupSetProvider(@GerritServerConfig Config config,
- SchemaFactory<ReviewDb> db, String section, String subsection, String name) {
+ protected GroupSetProvider(GroupCache groupCache,
+ @GerritServerConfig Config config, String section,
+ String subsection, String name) {
String[] groupNames = config.getStringList(section, subsection, name);
- groupIds = unmodifiableSet(groupsFor(db, groupNames, log));
+ ImmutableSet.Builder<AccountGroup.UUID> builder = ImmutableSet.builder();
+ for (String n : groupNames) {
+ AccountGroup g = groupCache.get(new AccountGroup.NameKey(n));
+ if (g != null) {
+ builder.add(g.getGroupUUID());
+ } else {
+ log.warn("Group \"{0}\" not in database, skipping.", n);
+ }
+ }
+ groupIds = builder.build();
}
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroupsProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroupsProvider.java
index b279086..7172b6f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroupsProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroupsProvider.java
@@ -14,8 +14,7 @@
package com.google.gerrit.server.config;
-import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gwtorm.server.SchemaFactory;
+import com.google.gerrit.server.account.GroupCache;
import com.google.inject.Inject;
import org.eclipse.jgit.lib.Config;
@@ -33,8 +32,8 @@
*/
public class ProjectOwnerGroupsProvider extends GroupSetProvider {
@Inject
- public ProjectOwnerGroupsProvider(
- @GerritServerConfig final Config config, final SchemaFactory<ReviewDb> db) {
- super(config, db, "repository", "*", "ownerGroup");
+ public ProjectOwnerGroupsProvider(GroupCache gc,
+ @GerritServerConfig final Config config) {
+ super(gc, config, "repository", "*", "ownerGroup");
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/BanCommit.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/BanCommit.java
new file mode 100644
index 0000000..c9c9753
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/BanCommit.java
@@ -0,0 +1,273 @@
+// Copyright (C) 2012 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.gerrit.server.git.GitRepositoryManager.REF_REJECT_COMMITS;
+
+import com.google.gerrit.common.errors.PermissionDeniedException;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.GerritPersonIdent;
+import com.google.gerrit.server.account.AccountCache;
+import com.google.gerrit.server.project.ProjectControl;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+import org.eclipse.jgit.errors.CorruptObjectException;
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.RefUpdate.Result;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.notes.Note;
+import org.eclipse.jgit.notes.NoteMap;
+import org.eclipse.jgit.notes.NoteMapMerger;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+
+import java.io.IOException;
+import java.util.List;
+
+public class BanCommit {
+
+ private static final int MAX_LOCK_FAILURE_CALLS = 10;
+ private static final int SLEEP_ON_LOCK_FAILURE_MS = 25;
+
+ public interface Factory {
+ BanCommit create();
+ }
+
+ private final Provider<CurrentUser> currentUser;
+ private final GitRepositoryManager repoManager;
+ private final AccountCache accountCache;
+ private final PersonIdent gerritIdent;
+
+ @Inject
+ BanCommit(final Provider<CurrentUser> currentUser,
+ final GitRepositoryManager repoManager, final AccountCache accountCache,
+ @GerritPersonIdent final PersonIdent gerritIdent) {
+ this.currentUser = currentUser;
+ this.repoManager = repoManager;
+ this.accountCache = accountCache;
+ this.gerritIdent = gerritIdent;
+ }
+
+ public BanCommitResult ban(final ProjectControl projectControl,
+ final List<ObjectId> commitsToBan, final String reason)
+ throws PermissionDeniedException, IOException,
+ IncompleteUserInfoException, InterruptedException, MergeException {
+ if (!projectControl.isOwner()) {
+ throw new PermissionDeniedException(
+ "No project owner: not permitted to ban commits");
+ }
+
+ final BanCommitResult result = new BanCommitResult();
+
+ final PersonIdent currentUserIdent = createPersonIdent();
+ final Repository repo =
+ repoManager.openRepository(projectControl.getProject().getNameKey());
+ try {
+ final RevWalk revWalk = new RevWalk(repo);
+ final ObjectInserter inserter = repo.newObjectInserter();
+ try {
+ NoteMap baseNoteMap = null;
+ RevCommit baseCommit = null;
+ final Ref notesBranch = repo.getRef(REF_REJECT_COMMITS);
+ if (notesBranch != null) {
+ baseCommit = revWalk.parseCommit(notesBranch.getObjectId());
+ baseNoteMap = NoteMap.read(revWalk.getObjectReader(), baseCommit);
+ }
+
+ final NoteMap ourNoteMap;
+ if (baseCommit != null) {
+ ourNoteMap = NoteMap.read(repo.newObjectReader(), baseCommit);
+ } else {
+ ourNoteMap = NoteMap.newEmptyMap();
+ }
+
+ for (final ObjectId commitToBan : commitsToBan) {
+ try {
+ revWalk.parseCommit(commitToBan);
+ } catch (MissingObjectException e) {
+ // ignore exception, also not existing commits can be banned
+ } catch (IncorrectObjectTypeException e) {
+ result.notACommit(commitToBan, e.getMessage());
+ continue;
+ }
+
+ final Note note = ourNoteMap.getNote(commitToBan);
+ if (note != null) {
+ result.commitAlreadyBanned(commitToBan);
+ continue;
+ }
+
+ final String noteContent = reason != null ? reason : "";
+ final ObjectId noteContentId =
+ inserter
+ .insert(Constants.OBJ_BLOB, noteContent.getBytes("UTF-8"));
+ ourNoteMap.set(commitToBan, noteContentId);
+ result.commitBanned(commitToBan);
+ }
+
+ if (result.getNewlyBannedCommits().isEmpty()) {
+ return result;
+ }
+
+ final ObjectId ourCommit =
+ commit(ourNoteMap, inserter, currentUserIdent, baseCommit, result,
+ reason);
+
+ updateRef(repo, revWalk, inserter, ourNoteMap, ourCommit, baseNoteMap,
+ baseCommit);
+ } finally {
+ revWalk.release();
+ inserter.release();
+ }
+ } finally {
+ repo.close();
+ }
+
+ return result;
+ }
+
+ private PersonIdent createPersonIdent() throws IncompleteUserInfoException {
+ final String userName = currentUser.get().getUserName();
+ final Account account = accountCache.getByUsername(userName).getAccount();
+ if (account.getFullName() == null) {
+ throw new IncompleteUserInfoException(userName, "full name");
+ }
+ if (account.getPreferredEmail() == null) {
+ throw new IncompleteUserInfoException(userName, "preferred email");
+ }
+ return new PersonIdent(account.getFullName(), account.getPreferredEmail());
+ }
+
+ private static ObjectId commit(final NoteMap noteMap,
+ final ObjectInserter inserter, final PersonIdent personIdent,
+ final ObjectId baseCommit, final BanCommitResult result,
+ final String reason) throws IOException {
+ final String commitMsg =
+ buildCommitMessage(result.getNewlyBannedCommits(), reason);
+ if (baseCommit != null) {
+ return createCommit(noteMap, inserter, personIdent, commitMsg, baseCommit);
+ } else {
+ return createCommit(noteMap, inserter, personIdent, commitMsg);
+ }
+ }
+
+ private static ObjectId createCommit(final NoteMap noteMap,
+ final ObjectInserter inserter, final PersonIdent personIdent,
+ final String message, final ObjectId... parents) throws IOException {
+ final CommitBuilder b = new CommitBuilder();
+ b.setTreeId(noteMap.writeTree(inserter));
+ b.setAuthor(personIdent);
+ b.setCommitter(personIdent);
+ if (parents.length > 0) {
+ b.setParentIds(parents);
+ }
+ b.setMessage(message);
+ final ObjectId commitId = inserter.insert(b);
+ inserter.flush();
+ return commitId;
+ }
+
+ private static String buildCommitMessage(final List<ObjectId> bannedCommits,
+ final String reason) {
+ final StringBuilder commitMsg = new StringBuilder();
+ commitMsg.append("Banning ");
+ commitMsg.append(bannedCommits.size());
+ commitMsg.append(" ");
+ commitMsg.append(bannedCommits.size() == 1 ? "commit" : "commits");
+ commitMsg.append("\n\n");
+ if (reason != null) {
+ commitMsg.append("Reason: ");
+ commitMsg.append(reason);
+ commitMsg.append("\n\n");
+ }
+ commitMsg.append("The following commits are banned:\n");
+ final StringBuilder commitList = new StringBuilder();
+ for (final ObjectId c : bannedCommits) {
+ if (commitList.length() > 0) {
+ commitList.append(",\n");
+ }
+ commitList.append(c.getName());
+ }
+ commitMsg.append(commitList);
+ return commitMsg.toString();
+ }
+
+ public void updateRef(final Repository repo, final RevWalk revWalk,
+ final ObjectInserter inserter, final NoteMap ourNoteMap,
+ final ObjectId oursCommit, final NoteMap baseNoteMap,
+ final ObjectId baseCommit) throws IOException, InterruptedException,
+ MissingObjectException, IncorrectObjectTypeException,
+ CorruptObjectException, MergeException {
+
+ int remainingLockFailureCalls = MAX_LOCK_FAILURE_CALLS;
+ RefUpdate refUpdate = createRefUpdate(repo, oursCommit, baseCommit);
+
+ for (;;) {
+ final Result result = refUpdate.update();
+
+ if (result == Result.LOCK_FAILURE) {
+ if (--remainingLockFailureCalls > 0) {
+ Thread.sleep(SLEEP_ON_LOCK_FAILURE_MS);
+ } else {
+ throw new MergeException("Failed to lock the ref: "
+ + REF_REJECT_COMMITS);
+ }
+
+ } else if (result == Result.REJECTED) {
+ final RevCommit theirsCommit =
+ revWalk.parseCommit(refUpdate.getOldObjectId());
+ final NoteMap theirNoteMap =
+ NoteMap.read(revWalk.getObjectReader(), theirsCommit);
+ final NoteMapMerger merger = new NoteMapMerger(repo);
+ final NoteMap merged =
+ merger.merge(baseNoteMap, ourNoteMap, theirNoteMap);
+ final ObjectId mergeCommit =
+ createCommit(merged, inserter, gerritIdent,
+ "Merged note commits\n", oursCommit, theirsCommit);
+ refUpdate = createRefUpdate(repo, mergeCommit, theirsCommit);
+ remainingLockFailureCalls = MAX_LOCK_FAILURE_CALLS;
+
+ } else if (result == Result.IO_FAILURE) {
+ throw new IOException(
+ "Couldn't create commit reject notes because of IO_FAILURE");
+ } else {
+ break;
+ }
+ }
+ }
+
+ private static RefUpdate createRefUpdate(final Repository repo,
+ final ObjectId newObjectId, final ObjectId expectedOldObjectId)
+ throws IOException {
+ RefUpdate refUpdate = repo.updateRef(REF_REJECT_COMMITS);
+ refUpdate.setNewObjectId(newObjectId);
+ if (expectedOldObjectId == null) {
+ refUpdate.setExpectedOldObjectId(ObjectId.zeroId());
+ } else {
+ refUpdate.setExpectedOldObjectId(expectedOldObjectId);
+ }
+ return refUpdate;
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/BanCommitResult.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/BanCommitResult.java
new file mode 100644
index 0000000..1b48455
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/BanCommitResult.java
@@ -0,0 +1,54 @@
+// Copyright (C) 2012 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 org.eclipse.jgit.lib.ObjectId;
+
+import java.util.LinkedList;
+import java.util.List;
+
+public class BanCommitResult {
+
+ private final List<ObjectId> newlyBannedCommits = new LinkedList<ObjectId>();
+ private final List<ObjectId> alreadyBannedCommits = new LinkedList<ObjectId>();
+ private final List<ObjectId> ignoredObjectIds = new LinkedList<ObjectId>();
+
+ public BanCommitResult() {
+ }
+
+ public void commitBanned(final ObjectId commitId) {
+ newlyBannedCommits.add(commitId);
+ }
+
+ public void commitAlreadyBanned(final ObjectId commitId) {
+ alreadyBannedCommits.add(commitId);
+ }
+
+ public void notACommit(final ObjectId id, final String message) {
+ ignoredObjectIds.add(id);
+ }
+
+ public List<ObjectId> getNewlyBannedCommits() {
+ return newlyBannedCommits;
+ }
+
+ public List<ObjectId> getAlreadyBannedCommits() {
+ return alreadyBannedCommits;
+ }
+
+ public List<ObjectId> getIgnoredObjectIds() {
+ return ignoredObjectIds;
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/IncompleteUserInfoException.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/IncompleteUserInfoException.java
new file mode 100644
index 0000000..204d777
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/IncompleteUserInfoException.java
@@ -0,0 +1,23 @@
+// Copyright (C) 2012 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;
+
+public class IncompleteUserInfoException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public IncompleteUserInfoException(final String userName, final String missingInfo) {
+ super("For the user \"" + userName + "\" " + missingInfo + " is not set.");
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeException.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeException.java
index 44becb5..1997c13 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeException.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeException.java
@@ -15,7 +15,7 @@
package com.google.gerrit.server.git;
/** Indicates the current branch's queue cannot be processed at this time. */
-class MergeException extends Exception {
+public class MergeException extends Exception {
private static final long serialVersionUID = 1L;
MergeException(final String msg) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/PushOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/PushOp.java
index 5c6cd25..0868749 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/PushOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/PushOp.java
@@ -343,10 +343,6 @@
if (config.isMirror()) {
for (final Ref ref : remote.values()) {
- if (noPerms && GitRepositoryManager.REF_CONFIG.equals(ref.getName())) {
- continue;
- }
-
if (!Constants.HEAD.equals(ref.getName())) {
final RefSpec spec = matchDst(ref.getName());
if (spec != null && !local.containsKey(spec.getSource())) {
@@ -360,16 +356,13 @@
} else {
for (final String src : delta) {
- if (noPerms && GitRepositoryManager.REF_CONFIG.equals(src)) {
- continue;
- }
-
final RefSpec spec = matchSrc(src);
if (spec != null) {
// If the ref still exists locally, send it, otherwise delete it.
//
Ref srcRef = local.get(src);
- if (srcRef != null) {
+ if (srcRef != null &&
+ !(noPerms && GitRepositoryManager.REF_CONFIG.equals(src))) {
send(cmds, spec, srcRef);
} else if (config.isMirror()) {
delete(cmds, spec);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/PushReplication.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/PushReplication.java
index 5cf5f7a..5bff0ad 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/PushReplication.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/PushReplication.java
@@ -14,13 +14,15 @@
package com.google.gerrit.server.git;
+import com.google.common.collect.ImmutableSet;
+import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.ReplicationUser;
+import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.account.GroupMembership;
import com.google.gerrit.server.account.ListGroupMembership;
-import com.google.gerrit.server.config.ConfigUtil;
import com.google.gerrit.server.config.FactoryModule;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.project.NoSuchProjectException;
@@ -99,11 +101,12 @@
private final SchemaFactory<ReviewDb> database;
private final ReplicationUser.Factory replicationUserFactory;
private final GitRepositoryManager gitRepositoryManager;
+ private final GroupCache groupCache;
@Inject
PushReplication(final Injector i, final WorkQueue wq, final SitePaths site,
final ReplicationUser.Factory ruf, final SchemaFactory<ReviewDb> db,
- final GitRepositoryManager grm)
+ final GitRepositoryManager grm, GroupCache gc)
throws ConfigInvalidException, IOException {
injector = i;
workQueue = wq;
@@ -111,6 +114,7 @@
replicationUserFactory = ruf;
gitRepositoryManager = grm;
configs = allConfigs(site);
+ groupCache = gc;
}
@Override
@@ -195,7 +199,6 @@
}
}
-
if (c.getPushRefSpecs().isEmpty()) {
RefSpec spec = new RefSpec();
spec = spec.setSourceDestination("refs/*", "refs/*");
@@ -204,7 +207,7 @@
}
r.add(new ReplicationConfig(injector, workQueue, c, cfg, database,
- replicationUserFactory, gitRepositoryManager));
+ replicationUserFactory, gitRepositoryManager, groupCache));
}
return Collections.unmodifiableList(r);
}
@@ -392,7 +395,8 @@
ReplicationConfig(final Injector injector, final WorkQueue workQueue,
final RemoteConfig rc, final Config cfg, SchemaFactory<ReviewDb> db,
final ReplicationUser.Factory replicationUserFactory,
- final GitRepositoryManager gitRepositoryManager) {
+ final GitRepositoryManager gitRepositoryManager,
+ GroupCache groupCache) {
remote = rc;
delay = Math.max(0, getInt(rc, cfg, "replicationdelay", 15));
@@ -406,8 +410,16 @@
cfg.getStringList("remote", rc.getName(), "authGroup");
final GroupMembership authGroups;
if (authGroupNames.length > 0) {
- authGroups = new ListGroupMembership(ConfigUtil.groupsFor(db, authGroupNames, //
- log, "Group \"{0}\" not in database, removing from authGroup"));
+ ImmutableSet.Builder<AccountGroup.UUID> builder = ImmutableSet.builder();
+ for (String name : authGroupNames) {
+ AccountGroup g = groupCache.get(new AccountGroup.NameKey(name));
+ if (g != null) {
+ builder.add(g.getGroupUUID());
+ } else {
+ log.warn("Group \"{0}\" not in database, removing from authGroup", name);
+ }
+ }
+ authGroups = new ListGroupMembership(builder.build());
} else {
authGroups = ReplicationUser.EVERYTHING_VISIBLE;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
index 290b162..83877d0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
@@ -16,6 +16,8 @@
import static com.google.gerrit.server.git.MultiProgressMonitor.UNKNOWN;
+import com.google.common.collect.LinkedListMultimap;
+import com.google.common.collect.ListMultimap;
import com.google.gerrit.common.ChangeHooks;
import com.google.gerrit.common.PageLinks;
import com.google.gerrit.common.data.ApprovalType;
@@ -112,6 +114,34 @@
private static final FooterKey TESTED_BY = new FooterKey("Tested-by");
private static final FooterKey CHANGE_ID = new FooterKey("Change-Id");
+ private static final String COMMAND_REJECTION_MESSAGE_FOOTER =
+ "Please read the documentation and contact an administrator\n"
+ + "if you feel the configuration is incorrect";
+
+ private enum Error {
+ CONFIG_UPDATE("You are not allowed to perform this operation.\n"
+ + "Configuration changes can only be pushed by project owners\n"
+ + "who also have 'Push' rights on " + GitRepositoryManager.REF_CONFIG),
+ UPDATE("You are not allowed to perform this operation.\n"
+ + "To push into this reference you need 'Push' rights."),
+ DELETE("You need 'Push' rights with the 'Force Push'\n"
+ + "flag set to delete references."),
+ CODE_REVIEW("You need 'Push' rights to upload code review requests.\n"
+ + "Verify that you are pushing to the right branch."),
+ CREATE("You are not allowed to perform this operation.\n"
+ + "To create new references you need 'Create Reference' rights.");
+
+ private final String value;
+
+ Error(String value) {
+ this.value = value;
+ }
+
+ public String get() {
+ return value;
+ }
+ }
+
interface Factory {
ReceiveCommits create(ProjectControl projectControl, Repository repository);
}
@@ -215,6 +245,7 @@
private final SubmoduleOp.Factory subOpFactory;
private final List<Message> messages = new ArrayList<Message>();
+ private ListMultimap<Error, String> errors = LinkedListMultimap.create();
private Task newProgress;
private Task replaceProgress;
private Task closeProgress;
@@ -438,6 +469,14 @@
doReplaces();
replaceProgress.end();
+ if (!errors.isEmpty()) {
+ for (Error error : errors.keySet()) {
+ rp.sendMessage(buildError(error, errors.get(error)));
+ }
+ rp.sendMessage(String.format("User: %s", displayName(currentUser)));
+ rp.sendMessage(COMMAND_REJECTION_MESSAGE_FOOTER);
+ }
+
for (final ReceiveCommand c : commands) {
if (c.getResult() == Result.OK) {
switch (c.getType()) {
@@ -502,6 +541,30 @@
}
}
+ private String buildError(Error error, List<String> branches) {
+ StringBuilder sb = new StringBuilder();
+ if (branches.size() == 1) {
+ sb.append("Branch ").append(branches.get(0)).append(":\n");
+ sb.append(error.get());
+ return sb.toString();
+ }
+ sb.append("Branches");
+ String delim = " ";
+ for (String branch : branches) {
+ sb.append(delim).append(branch);
+ delim = ", ";
+ }
+ return sb.append(":\n").append(error.get()).toString();
+ }
+
+ private static String displayName(IdentifiedUser user) {
+ String displayName = user.getUserName();
+ if (displayName == null) {
+ displayName = user.getAccount().getPreferredEmail();
+ }
+ return displayName;
+ }
+
private Account.Id toAccountId(final String nameOrEmail) throws OrmException,
NoSuchAccountException {
final Account a = accountResolver.findByNameOrEmail(nameOrEmail);
@@ -630,6 +693,7 @@
validateNewCommits(ctl, cmd);
cmd.execute(rp);
} else {
+ errors.put(Error.CREATE, ctl.getRefName());
reject(cmd, "can not create new references");
}
}
@@ -644,6 +708,11 @@
validateNewCommits(ctl, cmd);
cmd.execute(rp);
} else {
+ if (GitRepositoryManager.REF_CONFIG.equals(ctl.getRefName())) {
+ errors.put(Error.CONFIG_UPDATE, GitRepositoryManager.REF_CONFIG);
+ } else {
+ errors.put(Error.UPDATE, ctl.getRefName());
+ }
reject(cmd, "can not update the reference as a fast forward");
}
}
@@ -672,7 +741,12 @@
if (ctl.canDelete()) {
cmd.execute(rp);
} else {
- reject(cmd, "can not delete references");
+ if (GitRepositoryManager.REF_CONFIG.equals(ctl.getRefName())) {
+ reject(cmd, "cannot delete project configuration");
+ } else {
+ errors.put(Error.DELETE, ctl.getRefName());
+ reject(cmd, "can not delete references");
+ }
}
}
@@ -769,7 +843,8 @@
destBranchName.substring(0, split));
destBranchCtl = projectControl.controlForRef(destBranch);
if (!destBranchCtl.canUpload()) {
- reject(cmd, "can not upload a change to this reference");
+ errors.put(Error.CODE_REVIEW, cmd.getRefName());
+ reject(cmd, "can not upload review");
return;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchSetInfoFactory.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchSetInfoFactory.java
index f59dcc3..2619e00 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchSetInfoFactory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchSetInfoFactory.java
@@ -18,7 +18,6 @@
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.PatchSetInfo;
-import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RevId;
import com.google.gerrit.reviewdb.client.UserIdentity;
import com.google.gerrit.reviewdb.server.ReviewDb;
@@ -29,6 +28,7 @@
import com.google.inject.Singleton;
import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
@@ -68,31 +68,39 @@
}
public PatchSetInfo get(ReviewDb db, PatchSet.Id patchSetId)
- throws PatchSetInfoNotAvailableException {
- Repository repo = null;
+ throws PatchSetInfoNotAvailableException {
try {
final PatchSet patchSet = db.patchSets().get(patchSetId);
final Change change = db.changes().get(patchSet.getId().getParentKey());
- final Project.NameKey projectKey = change.getProject();
- repo = repoManager.openRepository(projectKey);
+ return get(change, patchSet);
+ } catch (OrmException e) {
+ throw new PatchSetInfoNotAvailableException(e);
+ }
+ }
+
+ public PatchSetInfo get(Change change, PatchSet patchSet)
+ throws PatchSetInfoNotAvailableException {
+ Repository repo;
+ try {
+ repo = repoManager.openRepository(change.getProject());
+ } catch (RepositoryNotFoundException e) {
+ throw new PatchSetInfoNotAvailableException(e);
+ }
+ try {
final RevWalk rw = new RevWalk(repo);
try {
final RevCommit src =
rw.parseCommit(ObjectId.fromString(patchSet.getRevision().get()));
- PatchSetInfo info = get(src, patchSetId);
+ PatchSetInfo info = get(src, patchSet.getId());
info.setParents(toParentInfos(src.getParents(), rw));
return info;
} finally {
rw.release();
}
- } catch (OrmException e) {
- throw new PatchSetInfoNotAvailableException(e);
} catch (IOException e) {
throw new PatchSetInfoNotAvailableException(e);
} finally {
- if (repo != null) {
- repo.close();
- }
+ repo.close();
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java
index 53301b9..7652bed 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java
@@ -26,10 +26,11 @@
import com.google.gerrit.rules.StoredValues;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.query.change.ChangeData;
import com.google.gwtorm.server.OrmException;
-import com.google.gwtorm.server.ResultSet;
import com.google.inject.Inject;
import com.google.inject.Provider;
+import com.google.inject.util.Providers;
import com.googlecode.prolog_cafe.compiler.CompileException;
import com.googlecode.prolog_cafe.lang.IntegerTerm;
@@ -49,6 +50,8 @@
import java.util.List;
import java.util.Set;
+import javax.annotation.Nullable;
+
/** Access control management for a user accessing a single change. */
public class ChangeControl {
@@ -161,7 +164,7 @@
/** Can this user see this change? */
public boolean isVisible(ReviewDb db) throws OrmException {
- if (change.getStatus() == Change.Status.DRAFT && !isDraftVisible(db)) {
+ if (change.getStatus() == Change.Status.DRAFT && !isDraftVisible(db, null)) {
return false;
}
return isRefVisible();
@@ -174,7 +177,7 @@
/** Can this user see the given patchset? */
public boolean isPatchVisible(PatchSet ps, ReviewDb db) throws OrmException {
- if (ps.isDraft() && !isDraftVisible(db)) {
+ if (ps.isDraft() && !isDraftVisible(db, null)) {
return false;
}
return isVisible(db);
@@ -235,10 +238,20 @@
/** Is this user a reviewer for the change? */
public boolean isReviewer(ReviewDb db) throws OrmException {
+ return isReviewer(db, null);
+ }
+
+ /** Is this user a reviewer for the change? */
+ public boolean isReviewer(ReviewDb db, @Nullable ChangeData cd)
+ throws OrmException {
if (getCurrentUser() instanceof IdentifiedUser) {
final IdentifiedUser user = (IdentifiedUser) getCurrentUser();
- ResultSet<PatchSetApproval> results =
- db.patchSetApprovals().byChange(change.getId());
+ Iterable<PatchSetApproval> results;
+ if (cd != null) {
+ results = cd.currentApprovals(Providers.of(db));
+ } else {
+ results = db.patchSetApprovals().byChange(change.getId());
+ }
for (PatchSetApproval approval : results) {
if (user.getAccountId().equals(approval.getAccountId())) {
return true;
@@ -278,34 +291,39 @@
return false;
}
- public List<SubmitRecord> canSubmit(ReviewDb db, PatchSet.Id patchSetId) {
+ public List<SubmitRecord> canSubmit(ReviewDb db, PatchSet patchSet) {
+ return canSubmit(db, patchSet, null, false);
+ }
+
+ public List<SubmitRecord> canSubmit(ReviewDb db, PatchSet patchSet,
+ @Nullable ChangeData cd, boolean fastEvalLabels) {
if (change.getStatus().isClosed()) {
SubmitRecord rec = new SubmitRecord();
rec.status = SubmitRecord.Status.CLOSED;
return Collections.singletonList(rec);
}
- if (!patchSetId.equals(change.currentPatchSetId())) {
- return ruleError("Patch set " + patchSetId + " is not current");
+ if (!patchSet.getId().equals(change.currentPatchSetId())) {
+ return ruleError("Patch set " + patchSet.getPatchSetId() + " is not current");
}
try {
- if (change.getStatus() == Change.Status.DRAFT){
- if (!isVisible(db)) {
- return ruleError("Patch set " + patchSetId + " not found");
+ if (change.getStatus() == Change.Status.DRAFT) {
+ if (!isDraftVisible(db, cd)) {
+ return ruleError("Patch set " + patchSet.getPatchSetId() + " not found");
} else {
return ruleError("Cannot submit draft changes");
}
}
- if (isDraftPatchSet(patchSetId, db)) {
- if (!isVisible(db)) {
- return ruleError("Patch set " + patchSetId + " not found");
+ if (patchSet.isDraft()) {
+ if (!isDraftVisible(db, cd)) {
+ return ruleError("Patch set " + patchSet.getPatchSetId() + " not found");
} else {
return ruleError("Cannot submit draft patch sets");
}
}
} catch (OrmException err) {
- return logRuleError("Cannot read patch set " + patchSetId, err);
+ return logRuleError("Cannot read patch set " + patchSet.getId(), err);
}
List<Term> results = new ArrayList<Term>();
@@ -323,7 +341,8 @@
try {
env.set(StoredValues.REVIEW_DB, db);
env.set(StoredValues.CHANGE, change);
- env.set(StoredValues.PATCH_SET_ID, patchSetId);
+ env.set(StoredValues.CHANGE_DATA, cd);
+ env.set(StoredValues.PATCH_SET, patchSet);
env.set(StoredValues.CHANGE_CONTROL, this);
submitRule = env.once(
@@ -334,6 +353,10 @@
+ getProject().getName());
}
+ if (fastEvalLabels) {
+ env.once("gerrit", "assume_range_from_label");
+ }
+
try {
for (Term[] template : env.all(
"gerrit", "can_submit",
@@ -372,6 +395,10 @@
parentEnv.once("gerrit", "locate_submit_filter", new VariableTerm());
if (filterRule != null) {
try {
+ if (fastEvalLabels) {
+ env.once("gerrit", "assume_range_from_label");
+ }
+
Term resultsTerm = toListTerm(results);
results.clear();
Term[] template = parentEnv.once(
@@ -515,16 +542,9 @@
}
}
- private boolean isDraftVisible(ReviewDb db) throws OrmException {
- return isOwner() || isReviewer(db);
- }
-
- private boolean isDraftPatchSet(PatchSet.Id id, ReviewDb db) throws OrmException {
- PatchSet ps = db.patchSets().get(id);
- if (ps == null) {
- throw new OrmException("Patch set " + id + " not found");
- }
- return ps.isDraft();
+ private boolean isDraftVisible(ReviewDb db, ChangeData cd)
+ throws OrmException {
+ return isOwner() || isReviewer(db, cd);
}
private static boolean isUser(Term who) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
index cb96cff..db3470e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
@@ -14,11 +14,14 @@
package com.google.gerrit.server.query.change;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.ChangeMessage;
import com.google.gerrit.reviewdb.client.Patch;
import com.google.gerrit.reviewdb.client.PatchLineComment;
import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSet.Id;
import com.google.gerrit.reviewdb.client.PatchSetApproval;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.TrackingId;
@@ -30,6 +33,7 @@
import com.google.gerrit.server.patch.PatchListEntry;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.ResultSet;
import com.google.inject.Provider;
import org.eclipse.jgit.lib.ObjectId;
@@ -47,9 +51,61 @@
import java.util.Map;
public class ChangeData {
+ public static void ensureChangeLoaded(
+ Provider<ReviewDb> db, List<ChangeData> changes) throws OrmException {
+ Map<Change.Id, ChangeData> missing = Maps.newHashMap();
+ for (ChangeData cd : changes) {
+ if (cd.change == null) {
+ missing.put(cd.getId(), cd);
+ }
+ }
+ if (!missing.isEmpty()) {
+ for (Change change : db.get().changes().get(missing.keySet())) {
+ missing.get(change.getId()).change = change;
+ }
+ }
+ }
+
+ public static void ensureCurrentPatchSetLoaded(
+ Provider<ReviewDb> db, List<ChangeData> changes) throws OrmException {
+ Map<PatchSet.Id, ChangeData> missing = Maps.newHashMap();
+ for (ChangeData cd : changes) {
+ if (cd.currentPatchSet == null && cd.patches == null) {
+ missing.put(cd.change(db).currentPatchSetId(), cd);
+ }
+ }
+ if (!missing.isEmpty()) {
+ for (PatchSet ps : db.get().patchSets().get(missing.keySet())) {
+ ChangeData cd = missing.get(ps.getId());
+ cd.currentPatchSet = ps;
+ cd.patches = Lists.newArrayList(ps);
+ }
+ }
+ }
+
+ public static void ensureCurrentApprovalsLoaded(
+ Provider<ReviewDb> db, List<ChangeData> changes) throws OrmException {
+ List<ResultSet<PatchSetApproval>> pending = Lists.newArrayList();
+ for (ChangeData cd : changes) {
+ if (cd.currentApprovals == null && cd.approvals == null) {
+ pending.add(db.get().patchSetApprovals()
+ .byPatchSet(cd.change(db).currentPatchSetId()));
+ }
+ }
+ if (!pending.isEmpty()) {
+ int idx = 0;
+ for (ChangeData cd : changes) {
+ if (cd.currentApprovals == null && cd.approvals == null) {
+ cd.currentApprovals = pending.get(idx++).toList();
+ }
+ }
+ }
+ }
+
private final Change.Id legacyId;
private Change change;
private String commitMessage;
+ private PatchSet currentPatchSet;
private Collection<PatchSet> patches;
private Collection<PatchSetApproval> approvals;
private Map<PatchSet.Id,Collection<PatchSetApproval>> approvalsMap;
@@ -144,16 +200,19 @@
}
public PatchSet currentPatchSet(Provider<ReviewDb> db) throws OrmException {
- Change c = change(db);
- if (c == null) {
- return null;
- }
- for (PatchSet p : patches(db)) {
- if (p.getId().equals(c.currentPatchSetId())) {
- return p;
+ if (currentPatchSet == null) {
+ Change c = change(db);
+ if (c == null) {
+ return null;
+ }
+ for (PatchSet p : patches(db)) {
+ if (p.getId().equals(c.currentPatchSetId())) {
+ currentPatchSet = p;
+ return p;
+ }
}
}
- return null;
+ return currentPatchSet;
}
public Collection<PatchSetApproval> currentApprovals(Provider<ReviewDb> db)
@@ -162,24 +221,21 @@
Change c = change(db);
if (c == null) {
currentApprovals = Collections.emptyList();
+ } else if (approvals != null) {
+ Map<Id, Collection<PatchSetApproval>> map = approvalsMap(db);
+ currentApprovals = map.get(c.currentPatchSetId());
+ if (currentApprovals == null) {
+ currentApprovals = Collections.emptyList();
+ map.put(c.currentPatchSetId(), currentApprovals);
+ }
} else {
- currentApprovals = approvalsFor(db, c.currentPatchSetId());
+ currentApprovals = db.get().patchSetApprovals()
+ .byPatchSet(c.currentPatchSetId()).toList();
}
}
return currentApprovals;
}
- public Collection<PatchSetApproval> approvalsFor(Provider<ReviewDb> db,
- PatchSet.Id psId) throws OrmException {
- List<PatchSetApproval> r = new ArrayList<PatchSetApproval>();
- for (PatchSetApproval p : approvals(db)) {
- if (p.getPatchSetId().equals(psId)) {
- r.add(p);
- }
- }
- return r;
- }
-
public String commitMessage(GitRepositoryManager repoManager,
Provider<ReviewDb> db) throws IOException, OrmException {
if (commitMessage == null) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ListChanges.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ListChanges.java
index ecfec96..6f9094a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ListChanges.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ListChanges.java
@@ -27,8 +27,6 @@
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.OutputFormat;
-import com.google.gerrit.server.account.AccountCache;
-import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.events.AccountAttribute;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.NoSuchChangeException;
@@ -43,6 +41,7 @@
import java.io.IOException;
import java.io.Writer;
import java.sql.Timestamp;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -50,7 +49,6 @@
public class ListChanges {
private final QueryProcessor imp;
private final Provider<ReviewDb> db;
- private final AccountCache accountCache;
private final ApprovalTypes approvalTypes;
private final CurrentUser user;
private final ChangeControl.Factory changeControlFactory;
@@ -88,13 +86,11 @@
@Inject
ListChanges(QueryProcessor qp,
Provider<ReviewDb> db,
- AccountCache ac,
ApprovalTypes at,
CurrentUser u,
ChangeControl.Factory cf) {
this.imp = qp;
this.db = db;
- this.accountCache = ac;
this.approvalTypes = at;
this.user = u;
this.changeControlFactory = cf;
@@ -135,6 +131,9 @@
changes = changes.subList(0, imp.getLimit());
}
}
+ ChangeData.ensureChangeLoaded(db, changes);
+ ChangeData.ensureCurrentPatchSetLoaded(db, changes);
+ ChangeData.ensureCurrentApprovalsLoaded(db, changes);
List<ChangeInfo> info = Lists.newArrayListWithCapacity(changes.size());
for (ChangeData cd : changes) {
@@ -150,6 +149,13 @@
res.add(info);
}
+ if (!accounts.isEmpty()) {
+ for (Account account : db.get().accounts().get(accounts.keySet())) {
+ AccountAttribute a = accounts.get(account.getId());
+ a.name = Strings.emptyToNull(account.getFullName());
+ }
+ }
+
if (format.isJson()) {
format.newGson().toJson(
res.size() == 1 ? res.get(0) : res,
@@ -199,22 +205,11 @@
}
private AccountAttribute asAccountAttribute(Account.Id user) {
- if (user == null) {
- return null;
- } else if (accounts.containsKey(user)) {
- return accounts.get(user);
+ AccountAttribute a = accounts.get(user);
+ if (a == null) {
+ a = new AccountAttribute();
+ accounts.put(user, a);
}
-
- AccountState state = accountCache.get(user);
- String name = state.getAccount().getFullName();
- if (Strings.isNullOrEmpty(name)) {
- accounts.put(user, null);
- return null;
- }
-
- AccountAttribute a = new AccountAttribute();
- a.name = name;
- accounts.put(user, a);
return a;
}
@@ -229,9 +224,9 @@
}
}
- PatchSet.Id ps = in.currentPatchSetId();
+ PatchSet ps = cd.currentPatchSet(db);
Map<String, LabelInfo> labels = Maps.newLinkedHashMap();
- for (SubmitRecord rec : ctl.canSubmit(db.get(), ps)) {
+ for (SubmitRecord rec : ctl.canSubmit(db.get(), ps, cd, true)) {
if (rec.labels == null) {
continue;
}
@@ -253,7 +248,7 @@
}
}
- List<PatchSetApproval> approvals = null;
+ Collection<PatchSetApproval> approvals = null;
for (Map.Entry<String, LabelInfo> e : labels.entrySet()) {
if (e.getValue().approved != null || e.getValue().rejected != null) {
continue;
@@ -273,7 +268,7 @@
}
if (approvals == null) {
- approvals = db.get().patchSetApprovals().byPatchSet(ps).toList();
+ approvals = cd.currentApprovals(db);
}
for (PatchSetApproval psa : approvals) {
short val = psa.getValue();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java
index a5ac255..76945f4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java
@@ -279,7 +279,7 @@
if (current != null) {
c.currentPatchSet = eventFactory.asPatchSetAttribute(current);
eventFactory.addApprovals(c.currentPatchSet, //
- d.approvalsFor(db, current.getId()));
+ d.currentApprovals(db));
if (includeFiles) {
eventFactory.addPatchSetFileNames(c.currentPatchSet,
diff --git a/gerrit-server/src/main/java/gerrit/PRED__load_commit_labels_1.java b/gerrit-server/src/main/java/gerrit/PRED__load_commit_labels_1.java
index c760426..a0bb820 100644
--- a/gerrit-server/src/main/java/gerrit/PRED__load_commit_labels_1.java
+++ b/gerrit-server/src/main/java/gerrit/PRED__load_commit_labels_1.java
@@ -9,7 +9,9 @@
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.rules.PrologEnvironment;
import com.google.gerrit.rules.StoredValues;
+import com.google.gerrit.server.query.change.ChangeData;
import com.google.gwtorm.server.OrmException;
+import com.google.inject.util.Providers;
import com.googlecode.prolog_cafe.lang.IntegerTerm;
import com.googlecode.prolog_cafe.lang.JavaException;
@@ -44,10 +46,18 @@
try {
PrologEnvironment env = (PrologEnvironment) engine.control;
ReviewDb db = StoredValues.REVIEW_DB.get(engine);
- PatchSet.Id patchSetId = StoredValues.PATCH_SET_ID.get(engine);
+ PatchSet patchSet = StoredValues.PATCH_SET.get(engine);
+ ChangeData cd = StoredValues.CHANGE_DATA.getOrNull(engine);
ApprovalTypes types = env.getInjector().getInstance(ApprovalTypes.class);
- for (PatchSetApproval a : db.patchSetApprovals().byPatchSet(patchSetId)) {
+ Iterable<PatchSetApproval> approvals;
+ if (cd != null) {
+ approvals = cd.currentApprovals(Providers.of(db));
+ } else {
+ approvals = db.patchSetApprovals().byPatchSet(patchSet.getId());
+ }
+
+ for (PatchSetApproval a : approvals) {
if (a.getValue() == 0) {
continue;
}
diff --git a/gerrit-server/src/main/java/gerrit/PRED_current_user_2.java b/gerrit-server/src/main/java/gerrit/PRED_current_user_2.java
index 0a15608..1359de1 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_current_user_2.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_current_user_2.java
@@ -20,15 +20,12 @@
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.rules.PrologEnvironment;
import com.google.gerrit.rules.StoredValues;
-import com.google.gerrit.server.AnonymousUser;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
-import com.google.inject.Provider;
+import com.google.inject.util.Providers;
-import com.googlecode.prolog_cafe.lang.HashtableOfTerm;
import com.googlecode.prolog_cafe.lang.IllegalTypeException;
import com.googlecode.prolog_cafe.lang.IntegerTerm;
-import com.googlecode.prolog_cafe.lang.InternalException;
import com.googlecode.prolog_cafe.lang.JavaObjectTerm;
import com.googlecode.prolog_cafe.lang.Operation;
import com.googlecode.prolog_cafe.lang.PInstantiationException;
@@ -39,6 +36,8 @@
import com.googlecode.prolog_cafe.lang.SymbolTerm;
import com.googlecode.prolog_cafe.lang.Term;
+import java.util.Map;
+
/**
* Loads a CurrentUser object for a user identity.
* <p>
@@ -53,7 +52,6 @@
private static final long serialVersionUID = 1L;
private static final SymbolTerm user = intern("user", 1);
private static final SymbolTerm anonymous = intern("anonymous");
- private static final SymbolTerm current_user = intern("current_user");
PRED_current_user_2(Term a1, Term a2, Operation n) {
arg1 = a1;
@@ -71,24 +69,14 @@
throw new PInstantiationException(this, 1);
}
- HashtableOfTerm userHash = userHash(engine);
- Term userTerm = userHash.get(a1);
- if (userTerm != null && userTerm.isJavaObject()) {
- if (!(((JavaObjectTerm) userTerm).object() instanceof CurrentUser)) {
- userTerm = createUser(engine, a1, userHash);
- }
- } else {
- userTerm = createUser(engine, a1, userHash);
- }
-
- if (!a2.unify(userTerm, engine.trail)) {
+ if (!a2.unify(createUser(engine, a1), engine.trail)) {
return engine.fail();
}
return cont;
}
- public Term createUser(Prolog engine, Term key, HashtableOfTerm userHash) {
+ public Term createUser(Prolog engine, Term key) {
if (!key.isStructure()
|| key.arity() != 1
|| !((StructureTerm) key).functor().equals(user)) {
@@ -98,54 +86,30 @@
Term idTerm = key.arg(0);
CurrentUser user;
if (idTerm.isInteger()) {
+ Map<Account.Id, IdentifiedUser> cache = StoredValues.USERS.get(engine);
Account.Id accountId = new Account.Id(((IntegerTerm) idTerm).intValue());
-
- final ReviewDb db = StoredValues.REVIEW_DB.getOrNull(engine);
- IdentifiedUser.GenericFactory userFactory = userFactory(engine);
- if (db != null) {
- user = userFactory.create(new Provider<ReviewDb>() {
- public ReviewDb get() {
- return db;
- }
- }, accountId);
- } else {
- user = userFactory.create(accountId);
+ user = cache.get(accountId);
+ if (user == null) {
+ ReviewDb db = StoredValues.REVIEW_DB.getOrNull(engine);
+ IdentifiedUser.GenericFactory userFactory = userFactory(engine);
+ IdentifiedUser who;
+ if (db != null) {
+ who = userFactory.create(Providers.of(db), accountId);
+ } else {
+ who = userFactory.create(accountId);
+ }
+ cache.put(accountId, who);
+ user = who;
}
-
} else if (idTerm.equals(anonymous)) {
- user = anonymousUser(engine);
+ user = StoredValues.ANONYMOUS_USER.get(engine);
} else {
throw new IllegalTypeException(this, 1, "user(int)", key);
}
- Term userTerm = new JavaObjectTerm(user);
- userHash.put(key, userTerm);
- return userTerm;
- }
-
- private static HashtableOfTerm userHash(Prolog engine) {
- Term userHash = engine.getHashManager().get(current_user);
- if (userHash == null) {
- HashtableOfTerm users = new HashtableOfTerm();
- engine.getHashManager().put(current_user, new JavaObjectTerm(userHash));
- return users;
- }
-
- if (userHash.isJavaObject()) {
- Object obj = ((JavaObjectTerm) userHash).object();
- if (obj instanceof HashtableOfTerm) {
- return (HashtableOfTerm) obj;
- }
- }
-
- throw new InternalException(current_user + " is not HashtableOfTerm");
- }
-
- private static AnonymousUser anonymousUser(Prolog engine) {
- PrologEnvironment env = (PrologEnvironment) engine.control;
- return env.getInjector().getInstance(AnonymousUser.class);
+ return new JavaObjectTerm(user);
}
private static IdentifiedUser.GenericFactory userFactory(Prolog engine) {
diff --git a/gerrit-server/src/main/prolog/gerrit_common.pl b/gerrit-server/src/main/prolog/gerrit_common.pl
index 3313162..5acc831 100644
--- a/gerrit-server/src/main/prolog/gerrit_common.pl
+++ b/gerrit-server/src/main/prolog/gerrit_common.pl
@@ -25,8 +25,7 @@
%% predicate that needs to obtain it.
%%
init :-
- define_hash(commit_labels),
- define_hash(current_user).
+ define_hash(commit_labels).
define_hash(A) :- hash_exists(A), !, hash_clear(A).
define_hash(A) :- atom(A), !, new_hash(_, [alias(A)]).
@@ -98,6 +97,10 @@
%% Lookup the range allowed to be used.
%%
user_label_range(Label, Who, Min, Max) :-
+ hash_get(commit_labels, '$fast_range', true), !,
+ atom(Label),
+ assume_range_from_label(Label, Who, Min, Max).
+user_label_range(Label, Who, Min, Max) :-
Who = user(_), !,
atom(Label),
current_user(Who, User),
@@ -106,6 +109,14 @@
clause(user:test_grant(Label, test_user(Name), range(Min, Max)), _)
.
+assume_range_from_label :-
+ hash_put(commit_labels, '$fast_range', true).
+
+assume_range_from_label(Label, Who, Min, Max) :-
+ commit_label(label(Label, Value), Who), !,
+ Min = Value, Max = Value.
+assume_range_from_label(_, _, 0, 0).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
diff --git a/gerrit-server/src/main/resources/com/google/gerrit/server/mail/ChangeFooter.vm b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/ChangeFooter.vm
index f2f0fc76..1eb6842 100644
--- a/gerrit-server/src/main/resources/com/google/gerrit/server/mail/ChangeFooter.vm
+++ b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/ChangeFooter.vm
@@ -31,7 +31,8 @@
## The ChangeFooter.vm template will determine the contents of the footer
## text that will be appended to ALL emails related to changes.
##
---
+#set ($SPACE = " ")
+--$SPACE
#if ($email.changeUrl)
To view, visit $email.changeUrl
#set ($notblank = 1)
diff --git a/gerrit-sshd/.gitignore b/gerrit-sshd/.gitignore
index 194bedc..8deb9bd 100644
--- a/gerrit-sshd/.gitignore
+++ b/gerrit-sshd/.gitignore
@@ -2,4 +2,5 @@
/.classpath
/.project
/.settings/org.maven.ide.eclipse.prefs
-/.settings/org.eclipse.m2e.core.prefs
\ No newline at end of file
+/.settings/org.eclipse.m2e.core.prefs
+/gerrit-sshd.iml
\ No newline at end of file
diff --git a/gerrit-sshd/pom.xml b/gerrit-sshd/pom.xml
index 55e8725..1c197a0 100644
--- a/gerrit-sshd/pom.xml
+++ b/gerrit-sshd/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-parent</artifactId>
- <version>2.4-SNAPSHOT</version>
+ <version>2.5-SNAPSHOT</version>
</parent>
<artifactId>gerrit-sshd</artifactId>
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java
index 54b0bb5..558707b 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java
@@ -36,6 +36,7 @@
import com.google.gerrit.sshd.args4j.AccountGroupIdHandler;
import com.google.gerrit.sshd.args4j.AccountGroupUUIDHandler;
import com.google.gerrit.sshd.args4j.AccountIdHandler;
+import com.google.gerrit.sshd.args4j.ObjectIdHandler;
import com.google.gerrit.sshd.args4j.PatchSetIdHandler;
import com.google.gerrit.sshd.args4j.ProjectControlHandler;
import com.google.gerrit.sshd.args4j.SocketAddressHandler;
@@ -48,6 +49,7 @@
import org.apache.sshd.common.KeyPairProvider;
import org.apache.sshd.server.CommandFactory;
import org.apache.sshd.server.PublickeyAuthenticator;
+import org.eclipse.jgit.lib.ObjectId;
import org.kohsuke.args4j.spi.OptionHandler;
import java.net.SocketAddress;
@@ -118,6 +120,7 @@
registerOptionHandler(Account.Id.class, AccountIdHandler.class);
registerOptionHandler(AccountGroup.Id.class, AccountGroupIdHandler.class);
registerOptionHandler(AccountGroup.UUID.class, AccountGroupUUIDHandler.class);
+ registerOptionHandler(ObjectId.class, ObjectIdHandler.class);
registerOptionHandler(PatchSet.Id.class, PatchSetIdHandler.class);
registerOptionHandler(ProjectControl.class, ProjectControlHandler.class);
registerOptionHandler(SocketAddress.class, SocketAddressHandler.class);
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/ObjectIdHandler.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/ObjectIdHandler.java
new file mode 100644
index 0000000..adb5ad6
--- /dev/null
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/ObjectIdHandler.java
@@ -0,0 +1,47 @@
+// Copyright (C) 2012 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.sshd.args4j;
+
+import com.google.inject.Inject;
+import com.google.inject.assistedinject.Assisted;
+
+import org.eclipse.jgit.lib.ObjectId;
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.OptionDef;
+import org.kohsuke.args4j.spi.OptionHandler;
+import org.kohsuke.args4j.spi.Parameters;
+import org.kohsuke.args4j.spi.Setter;
+
+public class ObjectIdHandler extends OptionHandler<ObjectId> {
+
+ @Inject
+ public ObjectIdHandler(@Assisted final CmdLineParser parser,
+ @Assisted final OptionDef option, @Assisted final Setter<ObjectId> setter) {
+ super(parser, option, setter);
+ }
+
+ @Override
+ public int parseArguments(Parameters params) throws CmdLineException {
+ final String n = params.getParameter(0);
+ setter.addValue(ObjectId.fromString(n));
+ return 1;
+ }
+
+ @Override
+ public String getDefaultMetaVariable() {
+ return "COMMIT";
+ }
+}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/BanCommitCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/BanCommitCommand.java
new file mode 100644
index 0000000..fd58221
--- /dev/null
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/BanCommitCommand.java
@@ -0,0 +1,118 @@
+// Copyright (C) 2012 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.sshd.commands;
+
+import com.google.gerrit.common.errors.PermissionDeniedException;
+import com.google.gerrit.server.git.BanCommit;
+import com.google.gerrit.server.git.BanCommitResult;
+import com.google.gerrit.server.git.IncompleteUserInfoException;
+import com.google.gerrit.server.git.MergeException;
+import com.google.gerrit.server.project.ProjectControl;
+import com.google.gerrit.sshd.BaseCommand;
+import com.google.inject.Inject;
+
+import org.apache.sshd.server.Environment;
+import org.eclipse.jgit.lib.ObjectId;
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.Option;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+public class BanCommitCommand extends BaseCommand {
+
+ @Option(name = "--reason", aliases = {"-r"}, metaVar = "REASON", usage = "reason for banning the commit")
+ private String reason;
+
+ @Argument(index = 0, required = true, metaVar = "PROJECT",
+ usage = "name of the project for which the commit should be banned")
+ private ProjectControl projectControl;
+
+ @Argument(index = 1, required = true, multiValued = true, metaVar = "COMMIT",
+ usage = "commit(s) that should be banned")
+ private List<ObjectId> commitsToBan = new ArrayList<ObjectId>();
+
+ @Inject
+ private BanCommit.Factory banCommitFactory;
+
+ @Override
+ public void start(final Environment env) throws IOException {
+ startThread(new CommandRunnable() {
+ @Override
+ public void run() throws Exception {
+ parseCommandLine();
+ BanCommitCommand.this.display();
+ }
+ });
+ }
+
+ private void display() throws Failure {
+ try {
+ final BanCommitResult result =
+ banCommitFactory.create().ban(projectControl, commitsToBan, reason);
+
+ final PrintWriter stdout = toPrintWriter(out);
+ try {
+ final List<ObjectId> newlyBannedCommits =
+ result.getNewlyBannedCommits();
+ if (!newlyBannedCommits.isEmpty()) {
+ stdout.print("The following commits were banned:\n");
+ printCommits(stdout, newlyBannedCommits);
+ }
+
+ final List<ObjectId> alreadyBannedCommits =
+ result.getAlreadyBannedCommits();
+ if (!alreadyBannedCommits.isEmpty()) {
+ stdout.print("The following commits were already banned:\n");
+ printCommits(stdout, alreadyBannedCommits);
+ }
+
+ final List<ObjectId> ignoredIds = result.getIgnoredObjectIds();
+ if (!ignoredIds.isEmpty()) {
+ stdout.print("The following ids do not represent commits"
+ + " and were ignored:\n");
+ printCommits(stdout, ignoredIds);
+ }
+ } finally {
+ stdout.flush();
+ }
+ } catch (PermissionDeniedException e) {
+ throw die(e);
+ } catch (IOException e) {
+ throw die(e);
+ } catch (IncompleteUserInfoException e) {
+ throw die(e);
+ } catch (MergeException e) {
+ throw die(e);
+ } catch (InterruptedException e) {
+ throw die(e);
+ }
+ }
+
+ private static void printCommits(final PrintWriter stdout,
+ final List<ObjectId> commits) {
+ boolean first = true;
+ for (final ObjectId c : commits) {
+ if (!first) {
+ stdout.print(",\n");
+ }
+ stdout.print(c.getName());
+ first = false;
+ }
+ stdout.print("\n\n");
+ }
+}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/DefaultCommandModule.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/DefaultCommandModule.java
index 16461b6..4d7c93e 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/DefaultCommandModule.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/DefaultCommandModule.java
@@ -35,6 +35,7 @@
// SlaveCommandModule.
command(gerrit).toProvider(new DispatchCommandProvider(gerrit));
+ command(gerrit, "ban-commit").to(BanCommitCommand.class);
command(gerrit, "flush-caches").to(FlushCaches.class);
command(gerrit, "ls-projects").to(ListProjectsCommand.class);
command(gerrit, "ls-groups").to(ListGroupsCommand.class);
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Replicate.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Replicate.java
index bc4e0bb..d56d1cd 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Replicate.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Replicate.java
@@ -73,7 +73,7 @@
private void schedule() throws Failure {
if (all && projectNames.size() > 0) {
- throw new Failure(1, "error: cannot combine --all and PROJECT");
+ throw new UnloggedFailure(1, "error: cannot combine --all and PROJECT");
}
if (!replication.isEnabled()) {
@@ -89,7 +89,7 @@
if (projectCache.get(key) != null) {
replication.scheduleFullSync(key, urlMatch);
} else {
- throw new Failure(1, "error: '" + name + "': not a Gerrit project");
+ throw new UnloggedFailure(1, "error: '" + name + "': not a Gerrit project");
}
}
}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SlaveCommandModule.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SlaveCommandModule.java
index 32ab2db..0e1a1fe 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SlaveCommandModule.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SlaveCommandModule.java
@@ -27,11 +27,14 @@
command(gerrit, "approve").to(ErrorSlaveMode.class);
command(gerrit, "create-account").to(ErrorSlaveMode.class);
+ command(gerrit, "create-group").to(ErrorSlaveMode.class);
command(gerrit, "create-project").to(ErrorSlaveMode.class);
command(gerrit, "gsql").to(ErrorSlaveMode.class);
command(gerrit, "receive-pack").to(ErrorSlaveMode.class);
+ command(gerrit, "rename-group").to(ErrorSlaveMode.class);
command(gerrit, "replicate").to(ErrorSlaveMode.class);
command(gerrit, "review").to(ErrorSlaveMode.class);
command(gerrit, "set-project-parent").to(ErrorSlaveMode.class);
+ command(gerrit, "set-reviewers").to(ErrorSlaveMode.class);
}
}
diff --git a/gerrit-util-cli/.gitignore b/gerrit-util-cli/.gitignore
index 194bedc..35069e7 100644
--- a/gerrit-util-cli/.gitignore
+++ b/gerrit-util-cli/.gitignore
@@ -2,4 +2,5 @@
/.classpath
/.project
/.settings/org.maven.ide.eclipse.prefs
-/.settings/org.eclipse.m2e.core.prefs
\ No newline at end of file
+/.settings/org.eclipse.m2e.core.prefs
+/gerrit-util-cli.iml
\ No newline at end of file
diff --git a/gerrit-util-cli/pom.xml b/gerrit-util-cli/pom.xml
index 4ecbda4..4886d09 100644
--- a/gerrit-util-cli/pom.xml
+++ b/gerrit-util-cli/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-parent</artifactId>
- <version>2.4-SNAPSHOT</version>
+ <version>2.5-SNAPSHOT</version>
</parent>
<artifactId>gerrit-util-cli</artifactId>
diff --git a/gerrit-util-ssl/.gitignore b/gerrit-util-ssl/.gitignore
index 194bedc..e552ad5 100644
--- a/gerrit-util-ssl/.gitignore
+++ b/gerrit-util-ssl/.gitignore
@@ -2,4 +2,5 @@
/.classpath
/.project
/.settings/org.maven.ide.eclipse.prefs
-/.settings/org.eclipse.m2e.core.prefs
\ No newline at end of file
+/.settings/org.eclipse.m2e.core.prefs
+/gerrit-util-ssl.iml
\ No newline at end of file
diff --git a/gerrit-util-ssl/pom.xml b/gerrit-util-ssl/pom.xml
index 2e49d47..beedb8f 100644
--- a/gerrit-util-ssl/pom.xml
+++ b/gerrit-util-ssl/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-parent</artifactId>
- <version>2.4-SNAPSHOT</version>
+ <version>2.5-SNAPSHOT</version>
</parent>
<artifactId>gerrit-util-ssl</artifactId>
diff --git a/gerrit-war/.gitignore b/gerrit-war/.gitignore
index 194bedc..dc8c7ad 100644
--- a/gerrit-war/.gitignore
+++ b/gerrit-war/.gitignore
@@ -2,4 +2,5 @@
/.classpath
/.project
/.settings/org.maven.ide.eclipse.prefs
-/.settings/org.eclipse.m2e.core.prefs
\ No newline at end of file
+/.settings/org.eclipse.m2e.core.prefs
+/gerrit-war.iml
\ No newline at end of file
diff --git a/gerrit-war/pom.xml b/gerrit-war/pom.xml
index 733d976a..1f3750e 100644
--- a/gerrit-war/pom.xml
+++ b/gerrit-war/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-parent</artifactId>
- <version>2.4-SNAPSHOT</version>
+ <version>2.5-SNAPSHOT</version>
</parent>
<artifactId>gerrit-war</artifactId>
diff --git a/gerrit-war/src/main/webapp/WEB-INF/extra/jetty7/gerrit.xml b/gerrit-war/src/main/webapp/WEB-INF/extra/jetty7/gerrit.xml
index 117bf61..3ae9440 100644
--- a/gerrit-war/src/main/webapp/WEB-INF/extra/jetty7/gerrit.xml
+++ b/gerrit-war/src/main/webapp/WEB-INF/extra/jetty7/gerrit.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.eclipse.org/configure.dtd">
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<!--
Jetty configuration to place "gerrit.war" into the root context,
diff --git a/gerrit-war/src/main/webapp/WEB-INF/extra/jetty7/jetty_sslproxy.xml b/gerrit-war/src/main/webapp/WEB-INF/extra/jetty7/jetty_sslproxy.xml
index 652acad..59cc040 100644
--- a/gerrit-war/src/main/webapp/WEB-INF/extra/jetty7/jetty_sslproxy.xml
+++ b/gerrit-war/src/main/webapp/WEB-INF/extra/jetty7/jetty_sslproxy.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.eclipse.org/configure.dtd">
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<!--
Jetty configuration to correctly handle SSL/HTTPS traffic when
diff --git a/pom.xml b/pom.xml
index 377b212..8c14a87 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,7 +22,7 @@
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-parent</artifactId>
<packaging>pom</packaging>
- <version>2.4-SNAPSHOT</version>
+ <version>2.5-SNAPSHOT</version>
<name>Gerrit Code Review - Parent</name>
<url>http://code.google.com/p/gerrit/</url>