Enable creating new branch and push local new commits in one step.

Direct push local commits to create a new branch is rejected,
even when user group can
 - 'Read',
 - 'Create Reference',
 - 'Push'
on 'refs/heads/*'. User have to firstly create new branch with
a commit which exists on server side, then push other local new
commits.

The reason is that Gerrit take it for granted that the commits
used to create new branch exist on server side already, so Gerrit
only check the commits are reachable or not on the server side.
According to the same reason if user group can 'Read' on 'refs/*'
or have Global Capabilities 'Administrate Server', Gerrit will
think the commits sure will be reachable for user and stop do
further checking.

So Gerrit does not work in the cases where creating new branch with
local new commits, e.g. the commits come from outer partners and need
not review, and the user group is not of Admin group and should not
be able to see every thing for some business rules reason.

Taking local new commits into account, also including the related
permission checking, now it can be finished in one step to create
new branch and push local new commits.

Bug: Issue 2441
Change-Id: I4e580e2fe0b40b8d0fbb06c5c8d1efd61127a842
This commit is contained in:
Bruce Zu 2014-02-25 19:04:41 +08:00
parent 82fc620c31
commit 9fd0c50a8a
3 changed files with 6 additions and 5 deletions
gerrit-server/src/main/java/com/google/gerrit/server

@ -877,7 +877,7 @@ public class ReceiveCommits {
}
RefControl ctl = projectControl.controlForRef(cmd.getRefName());
if (ctl.canCreate(rp.getRevWalk(), obj)) {
if (ctl.canCreate(rp.getRevWalk(), obj, allRefs.values().contains(obj))) {
validateNewCommits(ctl, cmd);
batch.addCommand(cmd);
} else {

@ -127,7 +127,7 @@ public class CreateBranch implements RestModifyView<ProjectResource, Input> {
}
}
if (!refControl.canCreate(rw, object)) {
if (!refControl.canCreate(rw, object, true)) {
throw new AuthException("Cannot create \"" + ref + "\"");
}

@ -229,9 +229,10 @@ public class RefControl {
*
* @param rw revision pool {@code object} was parsed in.
* @param object the object the user will start the reference with.
* @param existsOnServer the object exists on server or not.
* @return {@code true} if the user specified can create a new Git ref
*/
public boolean canCreate(RevWalk rw, RevObject object) {
public boolean canCreate(RevWalk rw, RevObject object, boolean existsOnServer) {
if (!canWrite()) {
return false;
}
@ -249,8 +250,8 @@ public class RefControl {
if (object instanceof RevCommit) {
return getCurrentUser().getCapabilities().canAdministrateServer()
|| (owner && !isBlocked(Permission.CREATE))
|| (canPerform(Permission.CREATE) && projectControl.canReadCommit(rw,
(RevCommit) object));
|| (canPerform(Permission.CREATE) && (!existsOnServer && canUpdate() || projectControl
.canReadCommit(rw, (RevCommit) object)));
} else if (object instanceof RevTag) {
final RevTag tag = (RevTag) object;
try {