pronto-github_resolver 0.0.1 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +3 -1
- data/lib/pronto/github_resolver/version.rb +1 -1
- data/lib/pronto/github_resolver.rb +81 -5
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 96e8c0465386136dab740a7e36d4804a1a84fe6e2cb9bfab2ff2d567494c80e7
|
4
|
+
data.tar.gz: 817f09eb49a66f716d384f301334bab472f5e939b03c71ba962780c02ce27002
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e06e67a83cf9c1cfec2d4152812c2948fd802f785f3565202dccfa8ca7ccf3af04f4a1ceee1fa2f8485f8f5ac2fb99cc183949c792088d7785381612e7fb8d59
|
7
|
+
data.tar.gz: bb93f3ea985b455ad96897e05a2724dc0e63f4ecfd6b90c87e630a15b989aa2f4b06d0c56d2d4419ceb5ee255730ce6a265576ef0ea5fc37cfcd226be5709568
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -22,7 +22,9 @@ Or install it yourself as:
|
|
22
22
|
|
23
23
|
## Usage
|
24
24
|
|
25
|
-
|
25
|
+
- When any of pronto runners emits message with level `:error` or `:fatal` - generated PR review will have resolution 'REQUEST_CHANGES', and default in other cases.
|
26
|
+
- On each run comment threads where message is no longer generated will be marked as resolved.
|
27
|
+
- Set ENV['PRONTO_GITHUB_BOT_ID'] to github id of your bot user. This enables posting PR 'APPROVE' review by bot after all messages are resolved.
|
26
28
|
|
27
29
|
## Development
|
28
30
|
|
@@ -29,7 +29,7 @@ module Pronto
|
|
29
29
|
client.create_pull_request_review(slug, pull_id, options)
|
30
30
|
end
|
31
31
|
|
32
|
-
def approve_pull_request(message=
|
32
|
+
def approve_pull_request(message="")
|
33
33
|
client.create_pull_request_review(slug, pull_id, {
|
34
34
|
event: 'APPROVE', body: message, accept: 'application/vnd.github.v3.diff+json'
|
35
35
|
})
|
@@ -39,8 +39,64 @@ module Pronto
|
|
39
39
|
client.pull_request_reviews(slug, pull_id)
|
40
40
|
end
|
41
41
|
|
42
|
-
def
|
43
|
-
|
42
|
+
def get_review_threads
|
43
|
+
owner, repo_name = (slug || "").split('/')
|
44
|
+
res = client.post :graphql, { query: <<~GQL }.to_json
|
45
|
+
query getUserId {
|
46
|
+
repository(owner: "#{owner}", name: "#{repo_name}") {
|
47
|
+
pullRequest: issueOrPullRequest(number: #{pull_id}) {
|
48
|
+
... on PullRequest {
|
49
|
+
reviewThreads(last:100) {
|
50
|
+
totalCount
|
51
|
+
nodes {
|
52
|
+
id
|
53
|
+
comments(last: 10) {
|
54
|
+
nodes {
|
55
|
+
viewerDidAuthor
|
56
|
+
path position body
|
57
|
+
}
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
}
|
65
|
+
GQL
|
66
|
+
|
67
|
+
if res.errors || !res.data
|
68
|
+
# ex: [{:message=>"Parse error on \"11\" (INT) at [1, 22]", :locations=>[{:line=>1, :column=>22}]}]
|
69
|
+
# TODO: handle errors
|
70
|
+
return []
|
71
|
+
end
|
72
|
+
|
73
|
+
res.data.repository.pullRequest.reviewThreads.nodes.to_h { |node|
|
74
|
+
[
|
75
|
+
node.id,
|
76
|
+
node.comments.nodes.map{ |comment|
|
77
|
+
{
|
78
|
+
authored: comment.viewerDidAuthor,
|
79
|
+
path: comment.path, position: comment.position, body: comment.body
|
80
|
+
}
|
81
|
+
}
|
82
|
+
]
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
86
|
+
def resolve_review_threads(node_ids)
|
87
|
+
return unless node_ids.any?
|
88
|
+
|
89
|
+
owner, repo_name = (slug || "").split('/')
|
90
|
+
query = <<~GQL
|
91
|
+
mutation {
|
92
|
+
#{
|
93
|
+
node_ids.each_with_index.map {|id, index|
|
94
|
+
"q#{index}: resolveReviewThread(input: { threadId: \"#{id}\" }){ thread { id } } "
|
95
|
+
}.join("\n")
|
96
|
+
}
|
97
|
+
}
|
98
|
+
GQL
|
99
|
+
client.post :graphql, { query: query }.to_json
|
44
100
|
end
|
45
101
|
end
|
46
102
|
|
@@ -52,12 +108,14 @@ module Pronto
|
|
52
108
|
comments = new_comments(messages, patches)
|
53
109
|
additions = remove_duplicate_comments(existing, comments)
|
54
110
|
|
111
|
+
# TODO: we can reuse some threads from graphql for existing messages detection (but there's no pagination)
|
112
|
+
resolve_old_messages(client, repo, comments)
|
113
|
+
|
55
114
|
if comments.none?
|
56
115
|
bot_reviews = client.existing_pull_request_reviews.select { |review| review.user.type == 'Bot' }
|
57
116
|
if bot_reviews.any?
|
58
|
-
bot_id = client.bot_user_id
|
59
117
|
current_bot_review_status = bot_reviews.inject(nil) do |prev_status, review|
|
60
|
-
next prev_status unless review
|
118
|
+
next prev_status unless review_by_this_bot?(review)
|
61
119
|
|
62
120
|
case review.state
|
63
121
|
when 'CHANGES_REQUESTED' then review.state
|
@@ -79,11 +137,29 @@ module Pronto
|
|
79
137
|
"#{additions.count} Pronto messages posted to #{pretty_name}"
|
80
138
|
end
|
81
139
|
|
140
|
+
def review_by_this_bot?(review)
|
141
|
+
ENV['PRONTO_GITHUB_BOT_ID'] && review.user.id == ENV['PRONTO_GITHUB_BOT_ID'].to_i
|
142
|
+
end
|
143
|
+
|
82
144
|
def submit_comments(client, comments, event: nil)
|
83
145
|
client.publish_pull_request_comments(comments, event: event)
|
84
146
|
rescue Octokit::UnprocessableEntity, HTTParty::Error => e
|
85
147
|
$stderr.puts "Failed to post: #{e.message}"
|
86
148
|
end
|
149
|
+
|
150
|
+
def resolve_old_messages(client, repo, actual_comments)
|
151
|
+
thread_ids_to_resolve = []
|
152
|
+
client.get_review_threads.each_pair do |thread_id, thread_comments|
|
153
|
+
next unless thread_comments.all? do |comment|
|
154
|
+
comment[:authored] &&
|
155
|
+
(actual_comments[[comment[:path], comment[:position]]] || []).none? { |actual_comment|
|
156
|
+
comment[:body].include?(actual_comment.body)
|
157
|
+
}
|
158
|
+
end
|
159
|
+
thread_ids_to_resolve << thread_id
|
160
|
+
end
|
161
|
+
client.resolve_review_threads(thread_ids_to_resolve)
|
162
|
+
end
|
87
163
|
end
|
88
164
|
|
89
165
|
class GithubPullRequestResolvingReviewFormatter < PullRequestFormatter
|