This repository has been archived by the owner on Feb 23, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathgithub.rb
177 lines (152 loc) · 6.5 KB
/
github.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
require 'octokit'
require 'pony'
class Github
VALID_LABELS = %w(unverified verified failing reopened address_feedback need_specs discussion security)
CORE_USERS = %w(BDQ schof JDutil huoxito peterberkenbosch rlister bryanmtl gmacdougall cbrunsdon jhawthorn adammathys seantaylor Senjai futhr athal7 jordan-brough BenMorganIO mbj dkubb jasonfb)
EXPLANATION_LABELS = %w(expected_behavior feature_request not_a_bug question stalled steps version works_for_me security)
CI_FAILED_LABEL = 'failing'
PR_OPEN_STATE = 'open'
UNVERIFIED_ISSUE_LABEL = 'unverified'
def client
@github_client ||= Octokit::Client.new(:access_token => ENV["GITHUB_TOKEN"])
end
def label_is_valid?(label)
valid_labels = VALID_LABELS + EXPLANATION_LABELS
valid_labels.include?(label)
end
# Reads all the md files from the `explanations` dir and will build
# a hash where the label is the key and the file contents the value.
#
# @return [Hash] the explanation hash with labels as key
def explanations
paths = Dir.glob(File.join(File.dirname(__FILE__), "explanations/*.md"))
explanation_hash = {}
paths.each do |path|
pn = Pathname.new(path)
key = pn.basename(".*").to_s.to_sym
explanation_hash[key] = pn.read
end
explanation_hash
end
# Removes all invalid labels from the issue
#
# @param repo [String] The repository in "user/repo" format. ie 'spree/spree'
# @param issue_id [Integer] The issue number on that repository
#
def remove_invalid_labels(repo, issue_id)
labels = client.labels_for_issue(repo, issue_id)
invalid_labels = []
labels.each do |label|
unless label_is_valid?(label.name)
client.remove_label(repo, issue_id, label.name)
client.delete_label!(repo, label.name)
invalid_labels << label.name
end
end
msg = "You attempted to add an unsupported label, we only use the following labels: #{VALID_LABELS.join(", ")}"
client.add_comment(repo, issue_id, msg) unless invalid_labels.empty?
end
# Add the label 'unverified' to the specified issue
#
# @param repo [String] The repository in "user/repo" format. ie 'spree/spree'
# @param issue_id [Integer] The issue number on that repository
#
def mark_issue_unverified(repo, issue_id)
client.add_labels_to_an_issue(repo, issue_id, [UNVERIFIED_ISSUE_LABEL])
end
# Closes an issue when comment is done by a user in the [CORE_USERS] and applies
# the passed in label when it's in the [VALID_LABELS]
#
# @param repo [String] The repository in "user/repo" format. ie 'spree/spree'
# @param issue_id [Integer] The issue number on that repository
# @param login [String] The login name for the user that commented
# @param label [String] The label to be applied to the issue
#
def close_and_label_issue(repo, issue_id, login, label)
add_comment_to_issue(repo, issue_id, "not_authorized") unless CORE_USERS.include?(login)
if CORE_USERS.include?(login) && label_is_valid?(label)
client.add_labels_to_an_issue(repo, issue_id, [label])
client.close_issue(repo, issue_id)
add_comment_to_issue(repo, issue_id, label) if EXPLANATION_LABELS.include?(label)
end
end
# Reject a PR that is failing on the CI server
# adds the label "failing" to the PR and closes it.
#
# @param repo [String] The repository in "user/repo" format. ie 'spree/spree'
# @param pull_request_id [Integer] The pullrequest number on that repository
#
def reject_failing_pull(repo, pull_request_id)
client.close_pull_request(repo, pull_request_id)
client.add_labels_to_an_issue(repo, pull_request_id, [CI_FAILED_LABEL])
end
# Reopens a PR that was closed before when it failed on the CI server.
# removes the label 'failing' as well.
#
# @param repo [String] The repository in "user/repo" format. ie 'spree/spree'
# @param pull_request_id [Integer] The pullrequest number on that repository
#
def reopen_succesfull_pull(repo, pull_request_id)
client.update_pull_request(repo, pull_request_id, nil, nil, PR_OPEN_STATE)
client.remove_label(repo, issue_id, CI_FAILED_LABEL)
end
# Label an existing issue using the specified text
#
# @param repo [String] The repository in "user/repo" format. ie 'spree/spree'
# @param issue_id [Integer] The issue number on that repository
# @param label [String] The label to be applied to the issue
def create_issue_label(repo, issue_id, label)
client.add_labels_to_an_issue(repo, issue_id, [label])
end
# Removes a label from the specified issue
#
# @param repo [String] The repository in "user/repo" format. ie 'spree/spree'
# @param issue_id [Integer] The issue number on that repository
# @param label [String] The label to be removed from the issue
def remove_issue_label(repo, issue_id, label)
# GH will create an event for removing the label, even if it doesn't exist
# so we should check for that first
return if client.labels_for_issue(repo, issue_id).select do |l|
l[:name] == label
end.empty?
client.remove_label(repo, issue_id, label)
end
# Add a comment to the issue if an entry exists in the explanations hash
# with the value in that hash to explain the closing reason better.
#
# @param repo [String] The repository in "user/repo" format. ie 'spree/spree'
# @param issue_id [Integer] The issue number on that repository
# @param label [String] The label to be removed from the issue
def add_comment_to_issue(repo, issue_id, label)
if explanations.has_key?(label.to_sym)
client.add_comment(repo, issue_id, explanations[label.to_sym])
end
end
def redact_and_email_security_issue(repo, issue_id)
issue = client.issue(repo, issue_id)
title = issue.title
body = issue.body
submitted_by = issue.user
client.update_issue(repo, issue_id, '[redacted]', explanations[:security])
send_security_email(repo, issue_id, title, body, submitted_by)
end
def send_security_email(repo, issue_id, title, body, submitted_by)
submitted_by_email = submitted_by.email
Pony.mail(
to: '[email protected]',
from: '[email protected]',
cc: submitted_by_email,
subject: "#{repo} - ##{issue_id} - #{title} by #{submitted_by.login}",
html_body: body,
via: :smtp,
via_options: {
address: 'smtp.mandrillapp.com',
port: '587',
user_name: ENV['MANDRILL_USERNAME'],
password: ENV['MANDRILL_APIKEY'],
authentication: :plain, # :plain, :login, :cram_md5, no auth by default
domain: "spreebot.herokuapp.com"
}
)
end
end