Skip to content

Commit 2336746

Browse files
committed
Automatically add owners as read-only collaborators.
1 parent 280a4cc commit 2336746

File tree

11 files changed

+110
-404
lines changed

11 files changed

+110
-404
lines changed

lib/comment.js

Lines changed: 23 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
"use strict";
22
var github = require('./github');
33
var q = require('q');
4-
var funk = require("./funk");
54
var labelModel = require("./label-model");
6-
7-
var NO_COLAB = "None of the owners of this pull request are repo collaborators. Please reach out on W3C's irc server (irc.w3.org, port 6665) on channel #testing ([web client](http://irc.w3.org/?channels=testing)) to get someone to merge this or get added as a collaborator. Thank you!";
8-
9-
var NO_OWNERS = "There are no owners for this pull request. Please reach out on W3C's irc server (irc.w3.org, port 6665) on channel #testing ([web client](http://irc.w3.org/?channels=testing)) to get help with this. Thank you!";
105

116
function promise(value) {
127
var deferred = q.defer();
@@ -15,66 +10,32 @@ function promise(value) {
1510
}
1611

1712
module.exports = function(number, metadata) {
18-
if (metadata.reviewers.length || metadata.reviewedUpstream) { // If there are reviewers we abord early. They know best.
13+
if (metadata.reviewers.length || metadata.reviewedUpstream) {
14+
// If there are reviewers we abord early. They know best.
1915
return promise();
20-
} else {
21-
// if there are collaborators, we ask them for a review
22-
if (metadata.collaborators.length > 0) {
23-
return requestReview(number, metadata.collaborators).then(function() {
24-
// And we ping the non-collaborators in a comment.
25-
if (metadata.nonCollaborators.length > 0) {
26-
var msg = msgToNonCollaborators(metadata);
27-
return comment(number, msg);
28-
}
29-
return;
30-
});
31-
} else if (metadata.authorIsCollaborator) {
32-
// There are no collaborators outside of the author.
33-
if (metadata.nonCollaborators.length > 0) {
34-
var msg = msgToNonCollaborators(metadata);
35-
return comment(number, msg);
16+
}
17+
18+
// if there are collaborators, we ask them for a review
19+
if (metadata.ownersExcludingAuthor.length > 0) {
20+
var reviewers = metadata.ownersExcludingAuthor.map(function(owner) { return owner.login });
21+
return github.post('/repos/:owner/:repo/pulls/:number/requested_reviewers', {
22+
reviewers: reviewers
23+
}, { number: number }).then(function() {
24+
if (!metadata.isMergeable) {
25+
return labelAndComment("status:needs-collaborator", "No owner on this pull request has write-access to the repository.");
3626
}
37-
return promise();
38-
} else if (metadata.nonCollaborators.length > 0) {
39-
// We've no collaborators but some owners.
40-
var msg = NO_COLAB + "\n\n" + msgToNonCollaborators(metadata);
41-
return labelModel.post(number, ["status:needs-collaborator"]).then(function() {
42-
return comment(number, msg);
43-
});
44-
} else {
45-
return labelModel.post(number, ["status:needs-owners"]).then(function() {
46-
return comment(number, NO_OWNERS);
47-
});
27+
});
28+
} else {
29+
if (metadata.author.isOwner) {
30+
return labelAndComment("status:needs-owners", "There are no owners for this pull request besides its author.");
4831
}
32+
return labelAndComment("status:needs-owners", "There are no owners for this pull request.");
4933
}
5034
};
5135

52-
function comment(number, body) {
53-
return github.post('/repos/:owner/:repo/issues/:number/comments', { body: body }, { number: number });
54-
}
55-
56-
function requestReview(number, collaborators) {
57-
return github.post('/repos/:owner/:repo/pulls/:number/requested_reviewers', {
58-
reviewers: collaborators
59-
}, { number: number })
60-
}
61-
62-
function msgToNonCollaborators(metadata) {
63-
var handles = metadata.nonCollaborators.map(function(nonCollab) { return "@" + nonCollab; });
64-
return "Notifying owners who are not repo collaborators: " + join(handles) + ".";
65-
}
66-
67-
module.exports.join = join;
68-
function join(owners) {
69-
if (owners.length == 0) {
70-
return "";
71-
}
72-
if (owners.length == 1) {
73-
return owners[0];
74-
}
75-
if (owners.length == 2) {
76-
return owners[0] + " and " + owners[1];
77-
}
78-
var last = owners.pop();
79-
return owners.join(", ") + ", and " + last;
80-
}
36+
function labelAndComment(label, msg) {
37+
msg += " Please reach out on W3C's irc server (irc.w3.org, port 6665) on channel #testing ([web client](http://irc.w3.org/?channels=testing)) to get help with this. Thank you!";
38+
return labelModel.post(number, [label]).then(function() {
39+
return github.post('/repos/:owner/:repo/issues/:number/comments', { body: msg }, { number: number });
40+
});
41+
}

lib/github.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,27 @@ function getHeaders() {
2121
}
2222

2323
function post(url, body, options) {
24+
return _post("POST", url, body, options);
25+
}
26+
27+
function put(url, body, options) {
28+
return _post("PUT", url, body, options);
29+
}
30+
31+
function _post(method, url, body, options) {
2432
options = mergeOptions(options || {});
2533
url = replaceURL(baseURL(url), options);
2634
var deferred = q.defer();
2735
body = typeof body == "string" ? body : JSON.stringify(body)
28-
console.log("POST " + url + "\n" + body);
29-
request.post({
36+
console.log(method + " " + url + "\n" + body);
37+
request[method.toLowerCase()]({
3038
url: url,
3139
headers: getHeaders(),
3240
body: body
3341
}, function(err, response, body) {
3442
if (err) {
3543
deferred.reject(err);
36-
} else if (response.statusCode == 200) {
44+
} else if (response.statusCode >= 200 && response.statusCode < 300) {
3745
deferred.resolve(JSON.parse(body));
3846
} else {
3947
deferred.reject(errFrom(body));
@@ -51,7 +59,7 @@ function get(url, options) {
5159
function onResponse(err, response, body) {
5260
if (err) {
5361
deferred.reject(err);
54-
} else if (response.statusCode == 200) {
62+
} else if (response.statusCode >= 200 && response.statusCode < 300) {
5563
var link = response.headers.link;
5664
body = JSON.parse(body);
5765
if (link) {
@@ -116,4 +124,5 @@ function replaceURL(url, options) {
116124
}
117125

118126
exports.get = get;
119-
exports.post = post;
127+
exports.post = post;
128+
exports.put = put;

lib/metadata/check-author-status.js

Lines changed: 0 additions & 13 deletions
This file was deleted.

lib/metadata/index.js

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,17 @@
33
var filenames = require('./filenames'),
44
paths = require('./paths'),
55
rawLabels = require('./raw-labels'),
6-
// isSafe = require('./is-safe'),
7-
// testUrls = require('./test-urls'),
86
findSpecs = require('./find-specs'),
97
findOwners = require('./find-owners'),
108
wg = require('./wg'),
11-
checkAuthorStatus = require('./check-author-status'),
9+
status = require('./status'),
1210
labels = require('./labels'),
1311
funk = require('../funk'),
1412
github = require('../github');
1513

1614
module.exports = function getMetadada(number, author, content) {
1715
var metadata = {
18-
issue: number,
19-
author: author
16+
issue: number
2017
};
2118

2219
return filenames(number)
@@ -25,46 +22,45 @@ module.exports = function getMetadada(number, author, content) {
2522
metadata.filenamesIgnoreRemoved = filenames.ignoreRemoved;
2623
metadata.paths = paths(metadata.filenames);
2724
metadata.rawLabels = rawLabels(metadata.filenames);
28-
// metadata.isSafe = isSafe(filenames.ignoreRemoved);
29-
// metadata.testUrls = testUrls(number, filenames.ignoreRemoved, metadata.paths);
3025
return findSpecs(metadata.rawLabels);
3126
}).then(function(specs) {
3227
metadata.specs = specs;
3328
metadata.workingGroups = wg(specs);
3429
metadata.labels = labels(metadata);
3530
}).then(function() {
36-
return findOwners(metadata.paths);
31+
return findOwners(metadata.paths)
3732
}).then(function(owners) {
38-
metadata.owners = owners;
33+
return status(owners);
34+
}).then(function(owners) {
35+
metadata.owners = owners;
3936
}).then(function() {
40-
return github.get("/repos/:owner/:repo/collaborators").then(function(collaborators) {
41-
collaborators = collaborators.map(funk.prop("login"));
42-
43-
metadata.authorIsCollaborator = collaborators.some(function(login) {
44-
return login == metadata.author;
45-
});
46-
47-
var _owners = metadata.owners.filter(function(owner) {
48-
return owner != metadata.author;
49-
})
50-
51-
// owners which have commit rights to the repo but are not the author
52-
metadata.collaborators = _owners.filter(function(owner) {
53-
return collaborators.indexOf(owner) > -1;
54-
});
55-
56-
// owners which do not have commit rights to the repo and are not the author
57-
metadata.nonCollaborators = _owners.filter(function(owner) {
58-
return collaborators.indexOf(owner) < 0;
37+
return status(author);
38+
}).then(function(status) {
39+
metadata.author = {
40+
login: author,
41+
permission: permission
42+
};
43+
}).then(function() {
44+
metadata.isMergeable = metadata.author.permission == "admin" ||
45+
metadata.author.permission == "write" ||
46+
metadata.owners.some(function(owner) {
47+
return owner.permission == "admin" || owner.permission == "write";
5948
});
49+
50+
metadata.ownersExcludingAuthor = metadata.owners.filter(function(owner) {
51+
return owner.login != metadata.author.login;
52+
});
53+
54+
metadata.author.isOwner = metadata.owners.some(function(owner) {
55+
return owner.login == metadata.author.login;
6056
});
6157
}).then(function() {
6258
return github.get('/repos/:owner/:repo/pulls/:number/requested_reviewers', { number: number }).then(function(reviewers) {
6359
metadata.reviewers = reviewers.map(function(r) { return r.login }).sort();
6460
});
6561
}).then(function() {
66-
metadata.reviewedUpstream = (metadata.author == "chromium-wpt-export-bot") ||
67-
(metadata.author == "jgraham" && content.indexOf("MozReview-Commit-ID") > -1);
62+
metadata.reviewedUpstream = (metadata.author.login == "chromium-wpt-export-bot") ||
63+
(metadata.author.login == "jgraham" && content.indexOf("MozReview-Commit-ID") > -1);
6864
return metadata;
6965
});
7066
};

lib/metadata/is-safe.js

Lines changed: 0 additions & 58 deletions
This file was deleted.

lib/metadata/status.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
"use strict";
2+
3+
var github = require("../github");
4+
var q = require('q');
5+
6+
function promise(value) {
7+
var deferred = q.defer();
8+
deferred.resolve(value);
9+
return deferred.promise;
10+
}
11+
12+
module.exports = function(arg) {
13+
return typeof arg == "string" ? _status(arg) : _statuses(arg);
14+
}
15+
16+
function _statuses(handles) {
17+
handles = handles.slice(0);
18+
var output = [];
19+
var deferred = q.defer();
20+
21+
function next() {
22+
if (handles.length > 0) {
23+
var handle = handles.pop();
24+
_status(handle).then(function(permission) {
25+
output.push({ login: handle, permission: permission });
26+
}, function(err) { deferred.reject(err) });
27+
} else {
28+
deferred.resolve(output);
29+
}
30+
}
31+
next();
32+
return deferred.promise;
33+
}
34+
35+
36+
function _status(handle) {
37+
return github.get("/repos/:owner/:repo/collaborators/:username", { username: handle }).then(function() {
38+
return github.get("/repos/:owner/:repo/collaborators/:username/permission", { username: handle }).then(function(data) {
39+
return data.permission;
40+
});
41+
}, function() {
42+
return github.put('/repos/:owner/:repo/collaborators/:username', { permission: "pull" }, { username: username }).then(function() {
43+
return "read";
44+
});
45+
});
46+
}
47+

lib/metadata/test-urls.js

Lines changed: 0 additions & 30 deletions
This file was deleted.

0 commit comments

Comments
 (0)