Support topic branch tags on changes
The topic tag can be attached to a change during upload by suffixing the 'refs/for/branch_name' with the topic label, treating the branch as though it were a directory. For example, to tag 'exp/nosql' onto a change headed for the 'sandbox/future-stuff' branch, git push can be used as: git push URL HEAD:refs/for/sandbox/future-stuff/exp-nosql If the topic is supplied, it is displayed in the branch column of a change, in parens. If no topic was set, only the branch is shown. Bug: issue 51 Change-Id: I07d6c137fc9aefa8c1ee1652bf1e7bcde9d33674 Signed-off-by: Shawn O. Pearce <sop@google.com>
This commit is contained in:
@@ -55,7 +55,6 @@ import com.google.gwtorm.client.OrmException;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
|
||||
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
|
||||
import org.eclipse.jgit.errors.MissingObjectException;
|
||||
import org.eclipse.jgit.lib.Constants;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
@@ -159,6 +158,8 @@ public class ReceiveCommits implements PreReceiveHook, PostReceiveHook {
|
||||
|
||||
private Map<ObjectId, Ref> refsById;
|
||||
|
||||
private String destTopicName;
|
||||
|
||||
@Inject
|
||||
ReceiveCommits(final ReviewDb db, final ApprovalTypes approvalTypes,
|
||||
final AccountResolver accountResolver,
|
||||
@@ -579,38 +580,55 @@ public class ReceiveCommits implements PreReceiveHook, PostReceiveHook {
|
||||
destBranchName = Constants.R_HEADS + destBranchName;
|
||||
}
|
||||
|
||||
if (rp.getAdvertisedRefs().containsKey(destBranchName)) {
|
||||
// We advertised the branch to the client so we know
|
||||
// the branch exists. Target this branch for the upload.
|
||||
//
|
||||
destBranch = new Branch.NameKey(project.getNameKey(), destBranchName);
|
||||
|
||||
} else {
|
||||
// We didn't advertise the branch, because it doesn't exist yet.
|
||||
// Allow it anyway if HEAD is a symbolic reference to the name.
|
||||
//
|
||||
final String head;
|
||||
try {
|
||||
head = repo.getFullBranch();
|
||||
} catch (IOException e) {
|
||||
log.error("Cannot read HEAD symref", e);
|
||||
reject(cmd, "internal error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (head.equals(destBranchName)) {
|
||||
destBranch = new Branch.NameKey(project.getNameKey(), destBranchName);
|
||||
}
|
||||
}
|
||||
|
||||
if (destBranch == null) {
|
||||
String n = destBranchName;
|
||||
if (n.startsWith(Constants.R_HEADS))
|
||||
n = n.substring(Constants.R_HEADS.length());
|
||||
reject(cmd, "branch " + n + " not found");
|
||||
final String head;
|
||||
try {
|
||||
head = repo.getFullBranch();
|
||||
} catch (IOException e) {
|
||||
log.error("Cannot read HEAD symref", e);
|
||||
reject(cmd, "internal error");
|
||||
return;
|
||||
}
|
||||
|
||||
// Split the destination branch by branch and topic. The topic
|
||||
// suffix is entirely optional, so it might not even exist.
|
||||
//
|
||||
int split = destBranchName.length();
|
||||
for (;;) {
|
||||
String name = destBranchName.substring(0, split);
|
||||
|
||||
if (rp.getAdvertisedRefs().containsKey(name)) {
|
||||
// We advertised the branch to the client so we know
|
||||
// the branch exists. Target this branch for the upload.
|
||||
//
|
||||
break;
|
||||
} else if (head.equals(name)) {
|
||||
// We didn't advertise the branch, because it doesn't exist yet.
|
||||
// Allow it anyway as HEAD is a symbolic reference to the name.
|
||||
//
|
||||
break;
|
||||
}
|
||||
|
||||
split = name.lastIndexOf('/', split - 1);
|
||||
if (split <= Constants.R_HEADS.length()) {
|
||||
String n = destBranchName;
|
||||
if (n.startsWith(Constants.R_HEADS))
|
||||
n = n.substring(Constants.R_HEADS.length());
|
||||
reject(cmd, "branch " + n + " not found");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (split < destBranchName.length()) {
|
||||
destTopicName = destBranchName.substring(split + 1);
|
||||
} else {
|
||||
// We use empty string here to denote the topic wasn't
|
||||
// supplied, but the caller used the syntax that allows
|
||||
// for a topic to be given.
|
||||
//
|
||||
destTopicName = "";
|
||||
}
|
||||
destBranch = new Branch.NameKey(project.getNameKey(), //
|
||||
destBranchName.substring(0, split));
|
||||
destBranchCtl = projectControl.controlForRef(destBranch);
|
||||
if (!destBranchCtl.canUpload()) {
|
||||
reject(cmd);
|
||||
@@ -858,6 +876,7 @@ public class ReceiveCommits implements PreReceiveHook, PostReceiveHook {
|
||||
|
||||
final Change change =
|
||||
new Change(changeKey, new Change.Id(db.nextChangeId()), me, destBranch);
|
||||
change.setTopic(destTopicName.isEmpty() ? null : destTopicName);
|
||||
change.nextPatchSetId();
|
||||
|
||||
final PatchSet ps = new PatchSet(change.currPatchSetId());
|
||||
@@ -1158,6 +1177,11 @@ public class ReceiveCommits implements PreReceiveHook, PostReceiveHook {
|
||||
@Override
|
||||
public Change update(Change change) {
|
||||
if (change.getStatus().isOpen()) {
|
||||
if (destTopicName != null) {
|
||||
change.setTopic(destTopicName.isEmpty() //
|
||||
? null //
|
||||
: destTopicName);
|
||||
}
|
||||
change.setStatus(Change.Status.NEW);
|
||||
change.setCurrentPatchSet(result.info);
|
||||
ChangeUtil.updated(change);
|
||||
|
@@ -32,7 +32,7 @@ import java.util.List;
|
||||
/** A version of the database schema. */
|
||||
public abstract class SchemaVersion {
|
||||
/** The current schema version. */
|
||||
private static final Class<? extends SchemaVersion> C = Schema_38.class;
|
||||
private static final Class<? extends SchemaVersion> C = Schema_39.class;
|
||||
|
||||
public static class Module extends AbstractModule {
|
||||
@Override
|
||||
|
@@ -0,0 +1,25 @@
|
||||
// Copyright (C) 2010 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.schema;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
public class Schema_39 extends SchemaVersion {
|
||||
@Inject
|
||||
Schema_39(Provider<Schema_38> prior) {
|
||||
super(prior);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user