Give CL author a default owner +1 vote.
* A changed file does not need other owner approval,
if the author is one of the owners.
* Find Owners button always shows file groups with owner approvals.
Change-Id: I6a716fbfcb65ab2a01b6ba595ae00ab4b2c3261e
diff --git a/src/main/java/com/googlesource/gerrit/plugins/findowners/Checker.java b/src/main/java/com/googlesource/gerrit/plugins/findowners/Checker.java
index ff75081..6b9897d 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/findowners/Checker.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/findowners/Checker.java
@@ -49,7 +49,7 @@
}
/** Returns a map from reviewer email to vote value. */
- static Map<String, Integer> getVotes(AccountCache accountCache, ChangeData changeData)
+ Map<String, Integer> getVotes(AccountCache accountCache, ChangeData changeData)
throws OrmException {
Map<String, Integer> map = new HashMap<>();
for (PatchSetApproval p : changeData.currentApprovals()) {
@@ -59,6 +59,12 @@
Integer.valueOf(p.getValue()));
}
}
+ // Give CL author a default minVoteLevel vote.
+ String author =
+ accountCache.get(changeData.change().getOwner()).getAccount().getPreferredEmail();
+ if (!map.containsKey(author) || map.get(author) == 0) {
+ map.put(author, minVoteLevel);
+ }
return map;
}
@@ -69,8 +75,6 @@
for (String owner : owners) {
if (votes.containsKey(owner)) {
int v = votes.get(owner);
- // TODO: Maybe add a configurable feature in the next version
- // to exclude the committer's vote from the "foundApproval".
foundApproval |= (v >= minVoteLevel);
foundVeto |= (v < 0); // an owner's -1 vote is a veto
} else if (owner.equals("*")) {
diff --git a/src/main/resources/static/find-owners.js b/src/main/resources/static/find-owners.js
index 8122474..79bcc72 100644
--- a/src/main/resources/static/find-owners.js
+++ b/src/main/resources/static/find-owners.js
@@ -14,9 +14,9 @@
Gerrit.install(function(self) {
function onFindOwners(c) {
- const HTML_ALL_HAVE_OWNER_APPROVAL =
- '<b>All files have owner approval.</b><br>';
const HTML_BULLET = '<small>★</small>'; // a Black Star
+ const HTML_HAS_APPROVAL_HEADER =
+ '<hr><b>Files with +1 or +2 Code-Review vote from owners:</b><br>';
const HTML_IS_EXEMPTED =
'<b>This commit is exempted from owner approval.</b><br>';
const HTML_NEED_REVIEWER_HEADER =
@@ -39,15 +39,18 @@
const CHECKBOX_ID = 'FindOwners:CheckBox';
const HEADER_DIV_ID = 'FindOwners:Header';
const OWNERS_DIV_ID = 'FindOwners:Owners';
+ const HAS_APPROVAL_DIV_ID = 'FindOwners:HasApproval';
const NEED_APPROVAL_DIV_ID = 'FindOwners:NeedApproval';
const NEED_REVIEWER_DIV_ID = 'FindOwners:NeedReviewer';
// Aliases to values in the context.
const branch = c.change.branch;
const changeId = c.change._number;
+ const changeOwner = c.change.owner;
const message = c.revision.commit.message;
const project = c.change.project;
+ var minVoteLevel = 1; // could be changed by server returned results.
var reviewerId = {}; // map from a reviewer's email to account id.
var reviewerVote = {}; // map from a reviewer's email to Code-Review vote.
@@ -76,6 +79,14 @@
}
}
});
+ // Give CL author a default minVoteLevel vote.
+ if (changeOwner != null &&
+ 'email' in changeOwner && '_account_id' in changeOwner &&
+ (!(changeOwner.email in reviewerId) ||
+ reviewerVote[changeOwner.email] == 0)) {
+ reviewerId[changeOwner.email] = changeOwner._account_id;
+ reviewerVote[changeOwner.email] = minVoteLevel;
+ }
}
function checkAddRemoveLists() {
// Gerrit.post and delete are asynchronous.
@@ -121,7 +132,7 @@
return (owner in reviewers || owner == '*');
});
}
- function hasOwnerApproval(votes, minVoteLevel, owners) {
+ function hasOwnerApproval(votes, owners) {
var foundApproval = false;
for (var j = 0; j < owners.length; j++) {
if (owners[j] in votes) {
@@ -129,7 +140,6 @@
if (v < 0) {
return false; // cannot have any negative vote
}
- // TODO: do not count if owners[j] is the patch committer.
foundApproval |= v >= minVoteLevel;
}
}
@@ -164,6 +174,7 @@
addKeyValue('changeId', changeId);
addKeyValue('project', project);
addKeyValue('branch', branch);
+ addKeyValue('changeOwner.email', changeOwner.email);
addKeyValue('Gerrit.url', Gerrit.url());
addKeyValue('self.url', self.url());
showJsonLines(args, 'changeOwner', c.change.owner);
@@ -184,11 +195,14 @@
var header = emptyDiv(HEADER_DIV_ID);
var needReviewerDiv = emptyDiv(NEED_REVIEWER_DIV_ID);
var needApprovalDiv = emptyDiv(NEED_APPROVAL_DIV_ID);
+ var hasApprovalDiv = emptyDiv(HAS_APPROVAL_DIV_ID);
addApplyButton();
var ownersDiv = emptyDiv(OWNERS_DIV_ID);
var numCheckBoxes = 0;
var owner2boxes = {}; // owner name ==> array of checkbox id
var owner2email = {}; // owner name ==> email address
+ minVoteLevel =
+ ('minOwnerVoteLevel' in result ? result.minOwnerVoteLevel : 1);
function addApplyButton() {
var apply = c.button('Apply', {onclick: doApplyButton});
@@ -285,6 +299,7 @@
function updateDivContent() {
var groupNeedReviewer = [];
var groupNeedApproval = [];
+ var groupHasApproval = [];
numCheckBoxes = 0;
owner2boxes = {};
Object.keys(groups).sort().forEach(function(key) {
@@ -293,24 +308,21 @@
groupNeedReviewer.push(key);
} else if (g.needApproval) {
groupNeedApproval.push(key);
+ } else {
+ groupHasApproval.push(key);
}
});
- if (0 == groupNeedReviewer.length && 0 == groupNeedApproval.length) {
- showDiv(header, HTML_ALL_HAVE_OWNER_APPROVAL);
- } else {
- showDiv(header, HTML_SELECT_REVIEWERS);
- addGroupsToDiv(needReviewerDiv, groupNeedReviewer,
- HTML_NEED_REVIEWER_HEADER);
- addGroupsToDiv(needApprovalDiv, groupNeedApproval,
- HTML_NEED_APPROVAL_HEADER);
- addOwnersDiv(ownersDiv, HTML_OWNERS_HEADER);
- }
+ showDiv(header, HTML_SELECT_REVIEWERS);
+ addGroupsToDiv(needReviewerDiv, groupNeedReviewer,
+ HTML_NEED_REVIEWER_HEADER);
+ addGroupsToDiv(needApprovalDiv, groupNeedApproval,
+ HTML_NEED_APPROVAL_HEADER);
+ addGroupsToDiv(hasApprovalDiv, groupHasApproval,
+ HTML_HAS_APPROVAL_HEADER);
+ addOwnersDiv(ownersDiv, HTML_OWNERS_HEADER);
}
function createGroups() {
var owners2group = {}; // owner list to group name
- var minVoteLevel =
- ('minOwnerVoteLevel' in result ?
- result['minOwnerVoteLevel'] : 1);
Object.keys(result.file2owners).sort().forEach(function(name) {
var splitOwners = result.file2owners[name];
var owners = splitOwners.join(' ');
@@ -321,7 +333,7 @@
groupSize[name] = 1;
var needReviewer = !hasOwnerReviewer(reviewerId, splitOwners);
var needApproval = !needReviewer &&
- !hasOwnerApproval(reviewerVote, minVoteLevel, splitOwners);
+ !hasOwnerApproval(reviewerVote, splitOwners);
groups[name] = {
'needReviewer': needReviewer,
'needApproval': needApproval,
diff --git a/src/test/java/com/googlesource/gerrit/plugins/findowners/FindOwnersIT.java b/src/test/java/com/googlesource/gerrit/plugins/findowners/FindOwnersIT.java
index 9ab3e48..b72c860 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/findowners/FindOwnersIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/findowners/FindOwnersIT.java
@@ -37,6 +37,7 @@
import com.google.inject.Inject;
import java.util.Collection;
import org.eclipse.jgit.lib.ObjectLoader;
+import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
@@ -301,6 +302,20 @@
}
@Test
+ public void authorDefaultVoteTest() throws Exception {
+ // CL author has default +1 owner vote.
+ addFile("add d1/OWNERS", "d1/OWNERS", user.email + "\n"); // d1 owned by user
+ addFile("add d2/OWNERS", "d2/OWNERS", admin.email + "\n"); // d2 owned by admin
+ // admin is the author of CLs created by createChange.
+ PushOneCommit.Result r1 = createChange("add d1/t.c", "d1/t.c", "Hello1");
+ PushOneCommit.Result r2 = createChange("add d2/t.c", "d2/t.c", "Hello2");
+ PushOneCommit.Result r3 = createChange("add d3/t.c", "d3/t.c", "Hello3");
+ assertThat(checkApproval(r1)).isEqualTo(-1); // owner is not change author
+ assertThat(checkApproval(r2)).isEqualTo(1); // owner is change author, default +1
+ assertThat(checkApproval(r3)).isEqualTo(0); // no owner is found in d3
+ }
+
+ @Test
public void actionApplyTest() throws Exception {
Cache cache = Cache.getInstance().init(0, 10);
assertThat(cache.size()).isEqualTo(0);
@@ -425,6 +440,14 @@
approveSubmit(commit);
}
+ private int checkApproval(PushOneCommit.Result r) throws Exception {
+ Repository repo = repoManager.openRepository(r.getChange().project());
+ Cache cache = Cache.getInstance().init(0, 0);
+ OwnersDb db = cache.get(accountCache, accounts, repo, r.getChange(), 1);
+ Checker c = new Checker(repo, r.getChange(), 1);
+ return c.findApproval(accountCache, db);
+ }
+
// Remove '"' and space; replace '\n' with ' '; ignore unpredictable "owner_revision".
private static String filteredJson(String json) {
return json.replaceAll("[\" ]*", "").replace('\n', ' ').replaceAll("owner_revision:[^ ]* ", "");