Automatically close changes when pushing into a branch with Change-Id
If new commits are being directly pushed into the branch and their messages contain Change-Id tags which correspond to an open change on our server in this project, we should tag that change as closed by marking the final commit as a replacement commit and updating the change. Change-Id: Ieb914afddedca8f21c39a8ba5711bbef6d6dd43c Signed-off-by: Shawn O. Pearce <sop@google.com>
This commit is contained in:
@@ -57,6 +57,9 @@ public interface ChangeAccess extends Access<Change, Change.Id> {
|
||||
@Query("WHERE open = true AND sortKey < ? ORDER BY sortKey DESC LIMIT ?")
|
||||
ResultSet<Change> allOpenNext(String sortKey, int limit) throws OrmException;
|
||||
|
||||
@Query("WHERE open = true AND dest.projectName = ?")
|
||||
ResultSet<Change> byProjectOpenAll(Project.NameKey p) throws OrmException;
|
||||
|
||||
@Query("WHERE open = true AND dest.projectName = ? AND sortKey > ?"
|
||||
+ " ORDER BY sortKey LIMIT ?")
|
||||
ResultSet<Change> byProjectOpenPrev(Project.NameKey p, String sortKey,
|
||||
|
||||
@@ -863,12 +863,12 @@ final class Receive extends AbstractGitCommand {
|
||||
}
|
||||
}
|
||||
|
||||
private void doReplace(final ReplaceRequest request) throws IOException,
|
||||
OrmException {
|
||||
private PatchSet.Id doReplace(final ReplaceRequest request)
|
||||
throws IOException, OrmException {
|
||||
final RevCommit c = request.newCommit;
|
||||
rp.getRevWalk().parseBody(c);
|
||||
if (!validCommitter(request.cmd, c)) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
final Account.Id me = currentUser.getAccountId();
|
||||
@@ -1080,6 +1080,7 @@ final class Receive extends AbstractGitCommand {
|
||||
}
|
||||
}
|
||||
sendMergedEmail(result);
|
||||
return result != null ? result.info.getKey() : null;
|
||||
}
|
||||
|
||||
private void insertDummyApproval(final ReplaceResult result,
|
||||
@@ -1245,12 +1246,35 @@ final class Receive extends AbstractGitCommand {
|
||||
rw.markUninteresting(rw.parseCommit(cmd.getOldId()));
|
||||
}
|
||||
|
||||
final Map<ObjectId, Ref> changes = changeRefsById();
|
||||
final Map<ObjectId, Ref> byCommit = changeRefsById();
|
||||
final Map<Change.Key, Change.Id> byKey = openChangesByKey();
|
||||
final List<ReplaceRequest> toClose = new ArrayList<ReplaceRequest>();
|
||||
RevCommit c;
|
||||
while ((c = rw.next()) != null) {
|
||||
Ref r = changes.get(c.copy());
|
||||
if (r != null) {
|
||||
closeChange(cmd, PatchSet.Id.fromRef(r.getName()));
|
||||
final Ref ref = byCommit.get(c.copy());
|
||||
if (ref != null) {
|
||||
closeChange(cmd, PatchSet.Id.fromRef(ref.getName()));
|
||||
continue;
|
||||
}
|
||||
|
||||
rw.parseBody(c);
|
||||
for (final String changeId : c.getFooterLines(CHANGE_ID)) {
|
||||
final Change.Id onto = byKey.get(new Change.Key(changeId));
|
||||
if (onto != null) {
|
||||
toClose.add(new ReplaceRequest(onto, c, cmd));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (final ReplaceRequest req : toClose) {
|
||||
final PatchSet.Id psi = doReplace(req);
|
||||
if (psi != null) {
|
||||
closeChange(req.cmd, psi);
|
||||
} else {
|
||||
log.warn("Replacement of Change-Id " + req.ontoChange
|
||||
+ " with commit " + req.newCommit.name()
|
||||
+ " did not import the new patch set.");
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
@@ -1307,6 +1331,14 @@ final class Receive extends AbstractGitCommand {
|
||||
return refsById;
|
||||
}
|
||||
|
||||
private Map<Change.Key, Change.Id> openChangesByKey() throws OrmException {
|
||||
final Map<Change.Key, Change.Id> r = new HashMap<Change.Key, Change.Id>();
|
||||
for (Change c : db.changes().byProjectOpenAll(proj.getNameKey())) {
|
||||
r.put(c.getKey(), c.getId());
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
private void markChangeMergedByPush(final ReviewDb db, final Transaction txn,
|
||||
final ReplaceResult result) throws OrmException {
|
||||
final Change change = result.change;
|
||||
|
||||
Reference in New Issue
Block a user