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 ?")
|
@Query("WHERE open = true AND sortKey < ? ORDER BY sortKey DESC LIMIT ?")
|
||||||
ResultSet<Change> allOpenNext(String sortKey, int limit) throws OrmException;
|
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 > ?"
|
@Query("WHERE open = true AND dest.projectName = ? AND sortKey > ?"
|
||||||
+ " ORDER BY sortKey LIMIT ?")
|
+ " ORDER BY sortKey LIMIT ?")
|
||||||
ResultSet<Change> byProjectOpenPrev(Project.NameKey p, String sortKey,
|
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,
|
private PatchSet.Id doReplace(final ReplaceRequest request)
|
||||||
OrmException {
|
throws IOException, OrmException {
|
||||||
final RevCommit c = request.newCommit;
|
final RevCommit c = request.newCommit;
|
||||||
rp.getRevWalk().parseBody(c);
|
rp.getRevWalk().parseBody(c);
|
||||||
if (!validCommitter(request.cmd, c)) {
|
if (!validCommitter(request.cmd, c)) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Account.Id me = currentUser.getAccountId();
|
final Account.Id me = currentUser.getAccountId();
|
||||||
@@ -1080,6 +1080,7 @@ final class Receive extends AbstractGitCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
sendMergedEmail(result);
|
sendMergedEmail(result);
|
||||||
|
return result != null ? result.info.getKey() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void insertDummyApproval(final ReplaceResult result,
|
private void insertDummyApproval(final ReplaceResult result,
|
||||||
@@ -1245,12 +1246,35 @@ final class Receive extends AbstractGitCommand {
|
|||||||
rw.markUninteresting(rw.parseCommit(cmd.getOldId()));
|
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;
|
RevCommit c;
|
||||||
while ((c = rw.next()) != null) {
|
while ((c = rw.next()) != null) {
|
||||||
Ref r = changes.get(c.copy());
|
final Ref ref = byCommit.get(c.copy());
|
||||||
if (r != null) {
|
if (ref != null) {
|
||||||
closeChange(cmd, PatchSet.Id.fromRef(r.getName()));
|
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) {
|
} catch (IOException e) {
|
||||||
@@ -1307,6 +1331,14 @@ final class Receive extends AbstractGitCommand {
|
|||||||
return refsById;
|
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,
|
private void markChangeMergedByPush(final ReviewDb db, final Transaction txn,
|
||||||
final ReplaceResult result) throws OrmException {
|
final ReplaceResult result) throws OrmException {
|
||||||
final Change change = result.change;
|
final Change change = result.change;
|
||||||
|
|||||||
Reference in New Issue
Block a user