prophet 1.6.2 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/lib/prophet/prophet.rb +152 -109
- data/lib/prophet/pull_request.rb +5 -1
- data/lib/prophet/railtie.rb +1 -1
- metadata +15 -15
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: abc7fdf796527eb07bc79a4a33db0c14f8a2ff1257e6cc440f9f2849bce0aac9
|
|
4
|
+
data.tar.gz: 3fe67e31b766b0bbb65a4433fb98d60472e287d9bd3f153cf6decca5463d6afa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7fa6ebed72ea06d9d6864da904b6d2d63919c221639563ef1b30ea3af8dd136b6902a1519759afd8240a7b81df9ea945507b99da054b405204443977713d5896
|
|
7
|
+
data.tar.gz: 1d01a53dac853e473ad2edfcedbfd4373ba3ad0cd80ab217538966cb48207124a2fc49b3cc64d3bfb2e400b38f363305eaa5b2090ff449e5253ff6f51d26b852
|
data/lib/prophet/prophet.rb
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
require 'English'
|
|
2
|
+
require 'open3'
|
|
3
|
+
|
|
1
4
|
class Prophet
|
|
2
5
|
|
|
3
|
-
attr_accessor :
|
|
4
|
-
:
|
|
6
|
+
attr_accessor :username_pass,
|
|
7
|
+
:access_token_pass,
|
|
5
8
|
:username_fail,
|
|
6
|
-
:
|
|
9
|
+
:access_token_fail,
|
|
7
10
|
:rerun_on_source_change,
|
|
8
11
|
:rerun_on_target_change,
|
|
9
12
|
:prepare_block,
|
|
@@ -15,7 +18,10 @@ class Prophet
|
|
|
15
18
|
:status_success,
|
|
16
19
|
:comment_failure,
|
|
17
20
|
:comment_success,
|
|
18
|
-
:
|
|
21
|
+
:disable_comments,
|
|
22
|
+
:reuse_comments,
|
|
23
|
+
:status_context,
|
|
24
|
+
:status_target_url
|
|
19
25
|
|
|
20
26
|
# Allow configuration blocks being passed to Prophet.
|
|
21
27
|
# See the README.md for examples on how to call this method.
|
|
@@ -42,7 +48,7 @@ class Prophet
|
|
|
42
48
|
begin
|
|
43
49
|
self.prepare_block.call
|
|
44
50
|
rescue Exception => e
|
|
45
|
-
|
|
51
|
+
logger.error "Preparation block raised an exception: #{e}"
|
|
46
52
|
end
|
|
47
53
|
# Loop through all 'open' pull requests.
|
|
48
54
|
selected_requests = pull_requests.select do |request|
|
|
@@ -53,30 +59,38 @@ class Prophet
|
|
|
53
59
|
remove_comment unless self.reuse_comments
|
|
54
60
|
true
|
|
55
61
|
end
|
|
62
|
+
|
|
56
63
|
# Run code on all selected requests.
|
|
57
64
|
selected_requests.each do |request|
|
|
58
65
|
@request = request
|
|
59
|
-
|
|
66
|
+
logger.info "Running for request ##{@request.id}."
|
|
60
67
|
# GitHub always creates a merge commit for its 'Merge Button'.
|
|
61
68
|
# Prophet reuses that commit to run the code on it.
|
|
62
|
-
switch_branch_to_merged_state
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
if switch_branch_to_merged_state
|
|
70
|
+
# Run specified code (i.e. tests) for the project.
|
|
71
|
+
begin
|
|
72
|
+
self.exec_block.call
|
|
73
|
+
# Unless self.success has already been set (to true/false) manually,
|
|
74
|
+
# the success/failure is determined by the last command's return code.
|
|
75
|
+
self.success = ($CHILD_STATUS && $CHILD_STATUS.exitstatus == 0) if self.success.nil?
|
|
76
|
+
rescue Exception => e
|
|
77
|
+
logger.error "Execution block raised an exception: #{e}"
|
|
78
|
+
self.success = false
|
|
79
|
+
end
|
|
80
|
+
switch_branch_back
|
|
81
|
+
comment_on_github
|
|
82
|
+
set_status_on_github
|
|
72
83
|
end
|
|
73
|
-
switch_branch_back
|
|
74
|
-
comment_on_github
|
|
75
|
-
set_status_on_github
|
|
76
84
|
self.success = nil
|
|
77
85
|
end
|
|
78
86
|
end
|
|
79
87
|
|
|
88
|
+
def logger
|
|
89
|
+
@logger ||= Logger.new(STDOUT).tap do |log|
|
|
90
|
+
log.level = Logger::INFO
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
80
94
|
|
|
81
95
|
private
|
|
82
96
|
|
|
@@ -86,46 +100,35 @@ class Prophet
|
|
|
86
100
|
end
|
|
87
101
|
|
|
88
102
|
def configure
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
else
|
|
93
|
-
@log = Logger.new(STDOUT)
|
|
94
|
-
@log.level = Logger::INFO
|
|
95
|
-
end
|
|
103
|
+
self.username_fail ||= self.username_pass
|
|
104
|
+
self.access_token_fail ||= self.access_token_pass
|
|
105
|
+
|
|
96
106
|
# Set default fall back values for options that aren't set.
|
|
97
|
-
self.username ||= git_config['github.login']
|
|
98
|
-
self.password ||= git_config['github.password']
|
|
99
|
-
self.username_fail ||= self.username
|
|
100
|
-
self.password_fail ||= self.password
|
|
101
107
|
self.rerun_on_source_change = true if self.rerun_on_source_change.nil?
|
|
102
108
|
self.rerun_on_target_change = true if self.rerun_on_target_change.nil?
|
|
103
109
|
self.reuse_comments = false if self.reuse_comments.nil?
|
|
110
|
+
self.disable_comments = false if self.disable_comments.nil?
|
|
104
111
|
# Allow for custom messages.
|
|
105
112
|
self.status_pending ||= 'Prophet is still running.'
|
|
106
113
|
self.status_failure ||= 'Prophet reports failure.'
|
|
107
114
|
self.status_success ||= 'Prophet reports success.'
|
|
108
115
|
self.comment_failure ||= 'Prophet reports failure.'
|
|
109
116
|
self.comment_success ||= 'Prophet reports success.'
|
|
117
|
+
self.status_context ||= 'prophet/default'
|
|
110
118
|
# Find environment (tasks, project, ...).
|
|
111
119
|
self.prepare_block ||= lambda {}
|
|
112
120
|
self.exec_block ||= lambda { `rake` }
|
|
113
|
-
@github = connect_to_github
|
|
114
|
-
@github_fail =
|
|
115
|
-
@github
|
|
116
|
-
else
|
|
117
|
-
connect_to_github self.username_fail, self.password_fail
|
|
118
|
-
end
|
|
121
|
+
@github = connect_to_github(access_token: access_token_pass)
|
|
122
|
+
@github_fail = connect_to_github(access_token: access_token_fail)
|
|
119
123
|
end
|
|
120
124
|
|
|
121
|
-
def connect_to_github(
|
|
122
|
-
github = Octokit::Client.new(
|
|
123
|
-
|
|
124
|
-
:password => pass
|
|
125
|
-
)
|
|
125
|
+
def connect_to_github(access_token:)
|
|
126
|
+
github = Octokit::Client.new(access_token: access_token)
|
|
127
|
+
|
|
126
128
|
# Check user login to GitHub.
|
|
127
129
|
github.login
|
|
128
|
-
|
|
130
|
+
logger.info "Successfully logged into GitHub with user '#{github.user.login}'."
|
|
131
|
+
|
|
129
132
|
# Ensure the user has access to desired project.
|
|
130
133
|
# NOTE: All three variants should work:
|
|
131
134
|
# 'ssh://git@github.com:user/project.git'
|
|
@@ -134,20 +137,20 @@ class Prophet
|
|
|
134
137
|
@project ||= /github\.com[\/:](.*)\.git$/.match(git_config['remote.origin.url'])[1]
|
|
135
138
|
begin
|
|
136
139
|
github.repo @project
|
|
137
|
-
|
|
140
|
+
logger.info "Successfully accessed GitHub project '#{@project}'"
|
|
138
141
|
github
|
|
139
142
|
rescue Octokit::Unauthorized => e
|
|
140
|
-
|
|
143
|
+
logger.error "Unable to access GitHub project with user '#{github.user}':\n#{e.message}"
|
|
141
144
|
abort
|
|
142
145
|
end
|
|
143
146
|
end
|
|
144
147
|
|
|
145
148
|
def pull_requests
|
|
146
|
-
request_list = @github.pulls @project, 'open'
|
|
149
|
+
request_list = @github.pulls @project, state: 'open'
|
|
147
150
|
requests = request_list.collect do |request|
|
|
148
151
|
PullRequest.new(@github.pull_request @project, request.number)
|
|
149
152
|
end
|
|
150
|
-
|
|
153
|
+
logger.info "Found #{requests.size > 0 ? requests.size : 'no'} open pull requests in '#{@project}'."
|
|
151
154
|
requests
|
|
152
155
|
end
|
|
153
156
|
|
|
@@ -155,73 +158,91 @@ class Prophet
|
|
|
155
158
|
# - the pull request hasn't been used for a run before.
|
|
156
159
|
# - the pull request has been updated since the last run.
|
|
157
160
|
# - the target (i.e. master) has been updated since the last run.
|
|
161
|
+
# - the pull request does not originate from a fork (to avoid malicious code execution on CI machines)
|
|
158
162
|
def run_necessary?
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
@request.
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
shas = /Merged ([\w]+) into ([\w]+)/.match(comment.body)
|
|
169
|
-
if shas && shas[1] && shas[2]
|
|
170
|
-
# Remember comment to be able to update or delete it later.
|
|
171
|
-
@request.comment = comment
|
|
172
|
-
break
|
|
163
|
+
logger.info "Checking pull request ##{@request.id}: #{@request.content.title}"
|
|
164
|
+
|
|
165
|
+
unless @request.from_fork || @request.wip
|
|
166
|
+
# Compare current sha ids of target and source branch with those from the last test run.
|
|
167
|
+
@request.target_head_sha = @github.commits(@project).first.sha
|
|
168
|
+
comments = @github.issue_comments(@project, @request.id)
|
|
169
|
+
comments = comments.select { |c| [username_pass, username_fail].include?(c.user.login) }.reverse
|
|
170
|
+
comments.each do |comment|
|
|
171
|
+
@request.comment = comment if /Merged ([\w]+) into ([\w]+)/.match(comment.body)
|
|
173
172
|
end
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
173
|
+
|
|
174
|
+
statuses = @github.status(@project, @request.head_sha).statuses.select { |s| s.context == self.status_context }
|
|
175
|
+
# Only run if it's mergeable.
|
|
176
|
+
if @request.content.mergeable
|
|
177
|
+
if statuses.empty?
|
|
178
|
+
# If there is no status yet, it has to be a new request.
|
|
179
|
+
logger.info 'New pull request detected, run needed.'
|
|
180
|
+
return true
|
|
181
|
+
elsif !self.disable_comments && !@request.comment
|
|
182
|
+
logger.info 'Rerun forced.'
|
|
183
|
+
return true
|
|
184
|
+
end
|
|
181
185
|
else
|
|
182
|
-
|
|
183
|
-
if @request.
|
|
184
|
-
|
|
185
|
-
|
|
186
|
+
# Sometimes GitHub doesn't have a proper boolean value stored.
|
|
187
|
+
if @request.content.mergeable.nil? && switch_branch_to_merged_state
|
|
188
|
+
# Pull request is mergeable after all.
|
|
189
|
+
switch_branch_back
|
|
190
|
+
else
|
|
191
|
+
logger.info 'Pull request not auto-mergeable. Not running.'
|
|
192
|
+
if @request.comment
|
|
193
|
+
logger.info 'Deleting existing comment.'
|
|
194
|
+
call_github(old_comment_success?).delete_comment(@project, @request.comment.id)
|
|
195
|
+
end
|
|
196
|
+
create_status(:error, "Pull request not auto-mergeable. Not running.") if statuses.first && statuses.first.state != 'error'
|
|
197
|
+
return false
|
|
186
198
|
end
|
|
187
|
-
return false
|
|
188
199
|
end
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
200
|
+
|
|
201
|
+
# Initialize shas to ensure it will live on after the 'each' block.
|
|
202
|
+
shas = nil
|
|
203
|
+
statuses.each do |status|
|
|
204
|
+
shas = /Merged ([\w]+) into ([\w]+)/.match(status.description)
|
|
205
|
+
break if shas && shas[1] && shas[2]
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
if shas
|
|
209
|
+
logger.info "Current target sha: '#{@request.target_head_sha}', pull sha: '#{@request.head_sha}'."
|
|
210
|
+
logger.info "Last test run target sha: '#{shas[2]}', pull sha: '#{shas[1]}'."
|
|
211
|
+
if self.rerun_on_source_change && (shas[1] != @request.head_sha)
|
|
212
|
+
logger.info 'Re-running due to new commit in pull request.'
|
|
213
|
+
return true
|
|
214
|
+
elsif self.rerun_on_target_change && (shas[2] != @request.target_head_sha)
|
|
215
|
+
logger.info 'Re-running due to new commit in target branch.'
|
|
216
|
+
return true
|
|
217
|
+
end
|
|
218
|
+
else
|
|
219
|
+
# If there are no SHAs yet, it has to be a new request.
|
|
220
|
+
logger.info 'New pull request detected, run needed.'
|
|
198
221
|
return true
|
|
199
222
|
end
|
|
200
|
-
else
|
|
201
|
-
# If there are no comments yet, it has to be a new request.
|
|
202
|
-
@log.info 'New pull request detected, run needed.'
|
|
203
|
-
return true
|
|
204
223
|
end
|
|
205
|
-
|
|
224
|
+
|
|
225
|
+
logger.info "Pull request comes from a fork." if @request.from_fork
|
|
226
|
+
logger.info "Not running for request ##{@request.id}."
|
|
206
227
|
false
|
|
207
228
|
end
|
|
208
229
|
|
|
209
|
-
def switch_branch_to_merged_state
|
|
230
|
+
def switch_branch_to_merged_state
|
|
210
231
|
# Fetch the merge-commit for the pull request.
|
|
211
232
|
# NOTE: This commit is automatically created by 'GitHub Merge Button'.
|
|
212
|
-
# FIXME: Use cheetah to pipe to
|
|
233
|
+
# FIXME: Use cheetah to pipe to logger.debug instead of that /dev/null hack.
|
|
213
234
|
`git fetch origin refs/pull/#{@request.id}/merge: &> /dev/null`
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
235
|
+
_output, status = Open3.capture2 'git checkout FETCH_HEAD &> /dev/null'
|
|
236
|
+
if status != 0
|
|
237
|
+
logger.error 'Unable to switch to merge branch.'
|
|
238
|
+
return false
|
|
218
239
|
end
|
|
219
240
|
true
|
|
220
241
|
end
|
|
221
242
|
|
|
222
243
|
def switch_branch_back
|
|
223
|
-
# FIXME: Use cheetah to pipe to
|
|
224
|
-
|
|
244
|
+
# FIXME: Use cheetah to pipe to logger.debug instead of that /dev/null hack.
|
|
245
|
+
logger.info 'Switching back to original branch.'
|
|
225
246
|
# FIXME: For branches other than master, remember the original branch.
|
|
226
247
|
`git checkout master &> /dev/null`
|
|
227
248
|
# Clean up potential remains and run garbage collector.
|
|
@@ -243,33 +264,60 @@ class Prophet
|
|
|
243
264
|
end
|
|
244
265
|
|
|
245
266
|
def comment_on_github
|
|
267
|
+
return if self.disable_comments
|
|
268
|
+
|
|
246
269
|
# Determine comment message.
|
|
247
270
|
message = if self.success
|
|
248
|
-
|
|
249
|
-
self.comment_success
|
|
271
|
+
logger.info 'Successful run.'
|
|
272
|
+
self.comment_success
|
|
250
273
|
else
|
|
251
|
-
|
|
252
|
-
self.comment_failure
|
|
274
|
+
logger.info 'Failing run.'
|
|
275
|
+
self.comment_failure
|
|
253
276
|
end
|
|
254
|
-
message +=
|
|
277
|
+
message += status_string
|
|
255
278
|
if self.reuse_comments && old_comment_success? == self.success
|
|
256
279
|
# Replace existing comment's body with the correct connection.
|
|
257
|
-
|
|
280
|
+
logger.info "Updating existing #{notion(self.success)} comment."
|
|
258
281
|
call_github(self.success).update_comment(@project, @request.comment.id, message)
|
|
259
282
|
else
|
|
260
283
|
if @request.comment
|
|
261
|
-
|
|
284
|
+
logger.info "Deleting existing #{notion(!self.success)} comment."
|
|
262
285
|
# Delete old comment with correct connection (if @request.comment exists).
|
|
263
286
|
call_github(!self.success).delete_comment(@project, @request.comment.id)
|
|
264
287
|
end
|
|
265
288
|
# Create new comment with correct connection.
|
|
266
|
-
|
|
289
|
+
logger.info "Adding new #{notion(self.success)} comment."
|
|
267
290
|
call_github(self.success).add_comment(@project, @request.id, message)
|
|
268
291
|
end
|
|
269
292
|
end
|
|
270
293
|
|
|
294
|
+
def status_string
|
|
295
|
+
case self.success
|
|
296
|
+
when true
|
|
297
|
+
" (Merged #{@request.head_sha} into #{@request.target_head_sha})"
|
|
298
|
+
when false
|
|
299
|
+
" (Merged #{@request.head_sha} into #{@request.target_head_sha})"
|
|
300
|
+
else
|
|
301
|
+
""
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
def create_status(state, description)
|
|
306
|
+
logger.info "Setting status '#{state}': '#{description}'"
|
|
307
|
+
@github.create_status(
|
|
308
|
+
@project,
|
|
309
|
+
@request.head_sha,
|
|
310
|
+
state,
|
|
311
|
+
{
|
|
312
|
+
"description" => description,
|
|
313
|
+
"context" => status_context,
|
|
314
|
+
"target_url" => self.status_target_url
|
|
315
|
+
}
|
|
316
|
+
)
|
|
317
|
+
end
|
|
318
|
+
|
|
271
319
|
def set_status_on_github
|
|
272
|
-
|
|
320
|
+
logger.info 'Updating status on GitHub.'
|
|
273
321
|
case self.success
|
|
274
322
|
when true
|
|
275
323
|
state_symbol = :success
|
|
@@ -281,12 +329,7 @@ class Prophet
|
|
|
281
329
|
state_symbol = :pending
|
|
282
330
|
state_message = self.status_pending
|
|
283
331
|
end
|
|
284
|
-
|
|
285
|
-
"repos/#{@project}/statuses/#{@request.head_sha}", {
|
|
286
|
-
:state => state_symbol,
|
|
287
|
-
:description => state_message
|
|
288
|
-
}
|
|
289
|
-
)
|
|
332
|
+
create_status(state_symbol, state_message + status_string)
|
|
290
333
|
end
|
|
291
334
|
|
|
292
335
|
def notion(success)
|
data/lib/prophet/pull_request.rb
CHANGED
|
@@ -4,12 +4,16 @@ class PullRequest
|
|
|
4
4
|
:content,
|
|
5
5
|
:comment,
|
|
6
6
|
:head_sha,
|
|
7
|
-
:target_head_sha
|
|
7
|
+
:target_head_sha,
|
|
8
|
+
:from_fork,
|
|
9
|
+
:wip
|
|
8
10
|
|
|
9
11
|
def initialize(content)
|
|
10
12
|
@content = content
|
|
11
13
|
@id = content.number
|
|
12
14
|
@head_sha = content.head.sha
|
|
15
|
+
@from_fork = content.head.attrs[:repo].attrs[:fork] if content.head.attrs[:repo]
|
|
16
|
+
@wip = content.labels.map(&:name).map(&:downcase).include? 'wip'
|
|
13
17
|
end
|
|
14
18
|
|
|
15
19
|
end
|
data/lib/prophet/railtie.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: prophet
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 2.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dominik Bamberger
|
|
@@ -10,50 +10,50 @@ authors:
|
|
|
10
10
|
autorequire:
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date:
|
|
13
|
+
date: 2021-03-17 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: faraday_middleware
|
|
17
17
|
requirement: !ruby/object:Gem::Requirement
|
|
18
18
|
requirements:
|
|
19
|
-
- -
|
|
19
|
+
- - "~>"
|
|
20
20
|
- !ruby/object:Gem::Version
|
|
21
|
-
version: 0.
|
|
21
|
+
version: 0.11.0
|
|
22
22
|
type: :runtime
|
|
23
23
|
prerelease: false
|
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
|
25
25
|
requirements:
|
|
26
|
-
- -
|
|
26
|
+
- - "~>"
|
|
27
27
|
- !ruby/object:Gem::Version
|
|
28
|
-
version: 0.
|
|
28
|
+
version: 0.11.0
|
|
29
29
|
- !ruby/object:Gem::Dependency
|
|
30
30
|
name: faraday
|
|
31
31
|
requirement: !ruby/object:Gem::Requirement
|
|
32
32
|
requirements:
|
|
33
|
-
- -
|
|
33
|
+
- - "~>"
|
|
34
34
|
- !ruby/object:Gem::Version
|
|
35
|
-
version: 0.
|
|
35
|
+
version: 0.11.0
|
|
36
36
|
type: :runtime
|
|
37
37
|
prerelease: false
|
|
38
38
|
version_requirements: !ruby/object:Gem::Requirement
|
|
39
39
|
requirements:
|
|
40
|
-
- -
|
|
40
|
+
- - "~>"
|
|
41
41
|
- !ruby/object:Gem::Version
|
|
42
|
-
version: 0.
|
|
42
|
+
version: 0.11.0
|
|
43
43
|
- !ruby/object:Gem::Dependency
|
|
44
44
|
name: octokit
|
|
45
45
|
requirement: !ruby/object:Gem::Requirement
|
|
46
46
|
requirements:
|
|
47
|
-
- -
|
|
47
|
+
- - "~>"
|
|
48
48
|
- !ruby/object:Gem::Version
|
|
49
|
-
version:
|
|
49
|
+
version: '4.0'
|
|
50
50
|
type: :runtime
|
|
51
51
|
prerelease: false
|
|
52
52
|
version_requirements: !ruby/object:Gem::Requirement
|
|
53
53
|
requirements:
|
|
54
|
-
- -
|
|
54
|
+
- - "~>"
|
|
55
55
|
- !ruby/object:Gem::Version
|
|
56
|
-
version:
|
|
56
|
+
version: '4.0'
|
|
57
57
|
description: Prophet runs custom code (i.e. your project's test suite) on open pull
|
|
58
58
|
requests on GitHub. Afterwards it posts the result as a comment to the respective
|
|
59
59
|
request. This should give you an outlook on the future state of your repository
|
|
@@ -89,7 +89,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
89
89
|
version: '0'
|
|
90
90
|
requirements: []
|
|
91
91
|
rubyforge_project:
|
|
92
|
-
rubygems_version: 2.
|
|
92
|
+
rubygems_version: 2.7.6.2
|
|
93
93
|
signing_key:
|
|
94
94
|
specification_version: 4
|
|
95
95
|
summary: An easy way to loop through open pull requests and run code onthe merged
|