gitarro 0.1.0
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 +7 -0
- data/bin/gitarro +34 -0
- data/lib/gitarro/backend.rb +281 -0
- data/lib/gitarro/git_op.rb +128 -0
- data/lib/gitarro/opt_parser.rb +197 -0
- metadata +161 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 21a43e24207cd6e412c688d57f5b72ed7ea32cec
|
4
|
+
data.tar.gz: 609ce571224ad1e2f22c07ac485827ecb9d58a48
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e15bf72520a193ba91c5c0a3a8d997e9d383602c79eee58268f23a8ee1d91a8cde6e6ff8548a94c43140d0e8a4b0e12365e04e0c0a05ff12de40c081f8e5c163
|
7
|
+
data.tar.gz: 340b3c242adc41878378ca5753ed4aa92ffbf0402fadffd4fc0a894f7477f603879d97abeedca827cd66243ea94d16490b94650430215c4d153a64e9e1cd19cc
|
data/bin/gitarro
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require 'English'
|
4
|
+
require 'octokit'
|
5
|
+
require 'optparse'
|
6
|
+
require 'gitarro/opt_parser'
|
7
|
+
require 'gitarro/git_op'
|
8
|
+
require 'gitarro/backend'
|
9
|
+
|
10
|
+
b = Backend.new
|
11
|
+
prs = b.open_prs
|
12
|
+
|
13
|
+
prs.each do |pr|
|
14
|
+
puts '=' * 30 + "\n" + "TITLE_PR: #{pr.title}, NR: #{pr.number}\n" + '=' * 30
|
15
|
+
# this check the last commit state, catch for review or not reviewd status.
|
16
|
+
comm_st = b.client.status(b.repo, pr.head.sha)
|
17
|
+
# pr number trigger.
|
18
|
+
break if b.trigger_by_pr_number(pr)
|
19
|
+
# retrigger if magic word found
|
20
|
+
b.retrigger_check(pr)
|
21
|
+
# check if changelog test was enabled
|
22
|
+
break if b.changelog_active(pr, comm_st)
|
23
|
+
# 0) do test for unreviewed pr
|
24
|
+
break if b.unreviewed_pr_test(pr, comm_st)
|
25
|
+
# we run the test in 2 conditions:
|
26
|
+
# 1) the context is not set, test didnt run
|
27
|
+
# 2) the pending status is set on commit, repeat always when pending set
|
28
|
+
# check the conditions 1,2 and it they happens run_test
|
29
|
+
break if b.reviewed_pr_test(comm_st, pr)
|
30
|
+
end
|
31
|
+
STDOUT.flush
|
32
|
+
|
33
|
+
# red balls for jenkins
|
34
|
+
exit 1 if b.j_status == 'failure'
|
@@ -0,0 +1,281 @@
|
|
1
|
+
#! /usr/bin/ruby
|
2
|
+
|
3
|
+
require 'octokit'
|
4
|
+
require 'optparse'
|
5
|
+
require 'English'
|
6
|
+
require_relative 'opt_parser'
|
7
|
+
require_relative 'git_op'
|
8
|
+
|
9
|
+
# This is a private class, which has the task to execute/run tests
|
10
|
+
# called by Backend
|
11
|
+
class TestExecutor
|
12
|
+
def initialize(options)
|
13
|
+
@options = options
|
14
|
+
@options.each do |key, value|
|
15
|
+
instance_variable_set("@#{key}", value)
|
16
|
+
self.class.send(:attr_accessor, key)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# this will clone the repo and execute the tests
|
21
|
+
def pr_test(pr)
|
22
|
+
git = GitOp.new(@git_dir, pr, @options)
|
23
|
+
# merge PR-branch to upstream branch
|
24
|
+
git.merge_pr_totarget(pr.base.ref, pr.head.ref)
|
25
|
+
# do valid tests and store the result
|
26
|
+
test_status = run_script
|
27
|
+
# del branch
|
28
|
+
git.del_pr_branch(pr.base.ref, pr.head.ref)
|
29
|
+
test_status
|
30
|
+
end
|
31
|
+
|
32
|
+
# run validation script for validating the PR.
|
33
|
+
def run_script
|
34
|
+
script_exists?(@test_file)
|
35
|
+
puts `#{@test_file}`
|
36
|
+
$CHILD_STATUS.exitstatus.nonzero? ? 'failure' : 'success'
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def script_exists?(script)
|
42
|
+
n_exist = "\'#{script}\' doesn't exists.Enter valid file, -t option"
|
43
|
+
raise n_exist if File.file?(script) == false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# this the public class is the backend of gitarro,
|
48
|
+
# were we execute the tests and so on
|
49
|
+
class Backend
|
50
|
+
attr_accessor :j_status, :options, :client, :pr_files, :gbexec
|
51
|
+
# public method of backend
|
52
|
+
def initialize(option = nil)
|
53
|
+
Octokit.auto_paginate = true
|
54
|
+
@client = Octokit::Client.new(netrc: true)
|
55
|
+
@options = option.nil? ? OptParser.new.cmdline_options : option
|
56
|
+
@j_status = ''
|
57
|
+
@pr_files = []
|
58
|
+
# each options will generate a object variable dinamically
|
59
|
+
@options.each do |key, value|
|
60
|
+
instance_variable_set("@#{key}", value)
|
61
|
+
self.class.send(:attr_accessor, key)
|
62
|
+
end
|
63
|
+
@gbexec = TestExecutor.new(@options)
|
64
|
+
end
|
65
|
+
|
66
|
+
# public method for get prs opens
|
67
|
+
# given a repo
|
68
|
+
def open_prs
|
69
|
+
prs = @client.pull_requests(@repo, state: 'open')
|
70
|
+
puts 'no Pull request OPEN on the REPO!' unless prs.any?
|
71
|
+
prs
|
72
|
+
end
|
73
|
+
|
74
|
+
# public for etrigger the test
|
75
|
+
def retrigger_check(pr)
|
76
|
+
return unless retrigger_needed?(pr)
|
77
|
+
client.create_status(@repo, pr.head.sha, 'pending',
|
78
|
+
context: @context, description: @description,
|
79
|
+
target_url: @target_url)
|
80
|
+
exit 1 if @check
|
81
|
+
launch_test_and_setup_status(@repo, pr)
|
82
|
+
j_status == 'success' ? exit(0) : exit(1)
|
83
|
+
end
|
84
|
+
|
85
|
+
# public always rerun tests against the pr number if this exists
|
86
|
+
def trigger_by_pr_number(pr)
|
87
|
+
return false if @pr_number.nil?
|
88
|
+
return false if @pr_number != pr.number
|
89
|
+
puts "Got triggered by PR_NUMBER OPTION, rerunning on #{@pr_number}"
|
90
|
+
launch_test_and_setup_status(@repo, pr)
|
91
|
+
true
|
92
|
+
end
|
93
|
+
|
94
|
+
# public method, trigger changelogtest if option active
|
95
|
+
def changelog_active(pr, comm_st)
|
96
|
+
return false unless @changelog_test
|
97
|
+
return false unless changelog_changed(@repo, pr, comm_st)
|
98
|
+
true
|
99
|
+
end
|
100
|
+
|
101
|
+
def unreviewed_pr_test(pr, comm_st)
|
102
|
+
return unless unreviewed_pr_ck(comm_st)
|
103
|
+
pr_all_files_type(@repo, pr.number, @file_type)
|
104
|
+
return if empty_files_changed_by_pr
|
105
|
+
# gb.check is true when there is a job running as scheduler
|
106
|
+
# which doesn't execute the test but trigger another job
|
107
|
+
return false if @check
|
108
|
+
launch_test_and_setup_status(@repo, pr)
|
109
|
+
true
|
110
|
+
end
|
111
|
+
|
112
|
+
def reviewed_pr_test(comm_st, pr)
|
113
|
+
# if PR status is not on pending and the context is not set,
|
114
|
+
# we dont run the tests
|
115
|
+
return false unless context_pr(comm_st) == false ||
|
116
|
+
pending_pr(comm_st) == true
|
117
|
+
pr_all_files_type(@repo, pr.number, @file_type)
|
118
|
+
return true if changelog_active(pr, comm_st)
|
119
|
+
return false unless @pr_files.any?
|
120
|
+
exit 1 if @check
|
121
|
+
launch_test_and_setup_status(@repo, pr)
|
122
|
+
true
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
# this function setup first pending to PR, then execute the tests
|
128
|
+
# then set the status according to the results of script executed.
|
129
|
+
# pr_head = is the PR branch
|
130
|
+
# base = is a the upstream branch, where the pr targets
|
131
|
+
def launch_test_and_setup_status(repo, pr)
|
132
|
+
# pending
|
133
|
+
@client.create_status(repo, pr.head.sha, 'pending',
|
134
|
+
context: @context, description: @description,
|
135
|
+
target_url: @target_url)
|
136
|
+
# do tests
|
137
|
+
@j_status = gbexec.pr_test(pr)
|
138
|
+
# set status
|
139
|
+
@client.create_status(repo, pr.head.sha, @j_status,
|
140
|
+
context: @context, description: @description,
|
141
|
+
target_url: @target_url)
|
142
|
+
end
|
143
|
+
|
144
|
+
# this function will check if the PR contains in comment the magic word
|
145
|
+
# # for retrigger all the tests.
|
146
|
+
def magicword(repo, pr_number, context)
|
147
|
+
magic_word_trigger = "@gitarro rerun #{context} !!!"
|
148
|
+
pr_comment = @client.issue_comments(repo, pr_number)
|
149
|
+
# a pr contain always a comments, cannot be nil
|
150
|
+
pr_comment.each do |com|
|
151
|
+
# delete comment otherwise it will be retrigger infinetely
|
152
|
+
if com.body.include? magic_word_trigger
|
153
|
+
@client.delete_comment(repo, com.id)
|
154
|
+
return true
|
155
|
+
end
|
156
|
+
end
|
157
|
+
false
|
158
|
+
end
|
159
|
+
|
160
|
+
# check all files of a Prs Number if they are a specific type
|
161
|
+
# EX: Pr 56, we check if files are '.rb'
|
162
|
+
def pr_all_files_type(repo, pr_number, type)
|
163
|
+
files = @client.pull_request_files(repo, pr_number)
|
164
|
+
files.each do |file|
|
165
|
+
@pr_files.push(file.filename) if file.filename.include? type
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# check if the commit of a pr is on pending
|
170
|
+
def pending_pr(comm_st)
|
171
|
+
# 2) pending
|
172
|
+
pending_on_context = false
|
173
|
+
(0..comm_st.statuses.size - 1).each do |pr_status|
|
174
|
+
if comm_st.statuses[pr_status]['context'] == @context &&
|
175
|
+
comm_st.statuses[pr_status]['state'] == 'pending'
|
176
|
+
pending_on_context = true
|
177
|
+
end
|
178
|
+
end
|
179
|
+
pending_on_context
|
180
|
+
end
|
181
|
+
|
182
|
+
# if the Pr contains magic word, test changelog
|
183
|
+
# is true
|
184
|
+
def magic_comment(repo, pr_num)
|
185
|
+
@client.issue_comments(repo, pr_num).each do |com|
|
186
|
+
if com.body.include?('no changelog needed!')
|
187
|
+
@j_status = 'success'
|
188
|
+
break
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# check it the cm of pr contain the context from gitarro already
|
194
|
+
def context_pr(cm_st)
|
195
|
+
# 1) context_present == false triggers test. >
|
196
|
+
# this means the PR is not with context tagged
|
197
|
+
context_present = false
|
198
|
+
(0..cm_st.statuses.size - 1).each do |pr_status|
|
199
|
+
context_present = true if cm_st.statuses[pr_status]['context'] == @context
|
200
|
+
end
|
201
|
+
context_present
|
202
|
+
end
|
203
|
+
|
204
|
+
# if the pr has travis test and one custom, we will have 2 elements.
|
205
|
+
# in this case, if the 1st element doesn't have the state property
|
206
|
+
# state property is "pending", failure etc.
|
207
|
+
# if we don't have this, so we have 0 status
|
208
|
+
# the PRs is "unreviewed"
|
209
|
+
def unreviewed_pr_ck(comm_st)
|
210
|
+
puts comm_st.statuses[0]['state']
|
211
|
+
return false
|
212
|
+
rescue NoMethodError
|
213
|
+
return true
|
214
|
+
end
|
215
|
+
|
216
|
+
def success_status?(comm_st)
|
217
|
+
status = false
|
218
|
+
(0..comm_st.statuses.size - 1).each do |pr_status|
|
219
|
+
if comm_st.statuses[pr_status]['context'] == @context &&
|
220
|
+
comm_st.statuses[pr_status]['state'] == 'success'
|
221
|
+
status = true
|
222
|
+
end
|
223
|
+
end
|
224
|
+
status
|
225
|
+
end
|
226
|
+
|
227
|
+
def failed_status?(comm_st)
|
228
|
+
status = false
|
229
|
+
(0..comm_st.statuses.size - 1).each do |pr_status|
|
230
|
+
if comm_st.statuses[pr_status]['context'] == @context &&
|
231
|
+
comm_st.statuses[pr_status]['state'] == 'failure'
|
232
|
+
status = true
|
233
|
+
end
|
234
|
+
end
|
235
|
+
status
|
236
|
+
end
|
237
|
+
|
238
|
+
# control if the pr change add any files, specified
|
239
|
+
# it can be also a dir
|
240
|
+
def empty_files_changed_by_pr
|
241
|
+
return if pr_files.any?
|
242
|
+
puts "no files of type #{@file_type} found! skipping"
|
243
|
+
true
|
244
|
+
end
|
245
|
+
|
246
|
+
def do_changelog_test(repo, pr)
|
247
|
+
@j_status = 'failure'
|
248
|
+
pr_all_files_type(repo, pr.number, @file_type)
|
249
|
+
# if the pr contains changes on .changes file, test ok
|
250
|
+
@j_status = 'success' if @pr_files.any?
|
251
|
+
magic_comment(repo, pr.number)
|
252
|
+
@client.create_status(repo, pr.head.sha, @j_status,
|
253
|
+
context: @context, description: @description,
|
254
|
+
target_url: @target_url)
|
255
|
+
true
|
256
|
+
end
|
257
|
+
|
258
|
+
# do the changelog test and set status
|
259
|
+
def changelog_changed(repo, pr, comm_st)
|
260
|
+
return false unless @changelog_test
|
261
|
+
# only execute 1 time, don"t run if test is failed, or ok
|
262
|
+
return false if failed_status?(comm_st)
|
263
|
+
return false if success_status?(comm_st)
|
264
|
+
do_changelog_test(repo, pr)
|
265
|
+
end
|
266
|
+
|
267
|
+
def retrigger_needed?(pr)
|
268
|
+
# we want redo sometimes tests
|
269
|
+
return false unless magicword(@repo, pr.number, @context)
|
270
|
+
# changelog trigger
|
271
|
+
if @changelog_test
|
272
|
+
do_changelog_test(@repo, pr)
|
273
|
+
return false
|
274
|
+
end
|
275
|
+
pr_all_files_type(@repo, pr.number, @file_type)
|
276
|
+
return false unless @pr_files.any?
|
277
|
+
# if check is set, the comment in the trigger job will be del.
|
278
|
+
# so setting it to pending, it will be remembered
|
279
|
+
true
|
280
|
+
end
|
281
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
#! /usr/bin/ruby
|
2
|
+
|
3
|
+
require 'English'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'timeout'
|
6
|
+
|
7
|
+
# git operation for gitarro
|
8
|
+
class GitOp
|
9
|
+
attr_reader :git_dir, :pr, :pr_fix, :repo_external, :repo_protocol
|
10
|
+
def initialize(git_dir, pr, options)
|
11
|
+
@git_dir = git_dir
|
12
|
+
# prefix for the test pr that gitarro tests.
|
13
|
+
@pr_fix = 'PR-'
|
14
|
+
# pr object for extract all relev. data.
|
15
|
+
@pr = pr
|
16
|
+
# All GitBot options
|
17
|
+
@options = options
|
18
|
+
# object to handle external repos
|
19
|
+
@repo_external = ExternalRepoGit.new(pr, options)
|
20
|
+
gh = 'https://github.com/'
|
21
|
+
gg = 'git@github.com:'
|
22
|
+
@repo_protocol = @options[:https] ? gh : gg
|
23
|
+
end
|
24
|
+
|
25
|
+
def ck_or_clone_git
|
26
|
+
return if File.directory?(git_dir)
|
27
|
+
FileUtils.mkdir_p(git_dir)
|
28
|
+
Dir.chdir git_dir
|
29
|
+
repo_url = "#{repo_protocol}#{@options[:repo]}.git"
|
30
|
+
puts `git clone #{repo_url}`
|
31
|
+
end
|
32
|
+
|
33
|
+
# this function merge the pr branch into target branch,
|
34
|
+
# where the author of pr wanted to submit
|
35
|
+
def goto_prj_dir
|
36
|
+
git_repo_dir = git_dir + '/' + @options[:repo].split('/')[1]
|
37
|
+
# chech that dir exist, otherwise clone it
|
38
|
+
ck_or_clone_git
|
39
|
+
begin
|
40
|
+
# /tmp/gitarro, this is in case the dir already exists
|
41
|
+
Dir.chdir git_repo_dir
|
42
|
+
rescue Errno::ENOENT
|
43
|
+
# this is in case we clone the repo
|
44
|
+
Dir.chdir @options[:repo].split('/')[1]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def check_git_dir
|
49
|
+
msg_err = 'gitarro is not working on a git directory'
|
50
|
+
raise msg_err if File.directory?('.git') == false
|
51
|
+
end
|
52
|
+
|
53
|
+
# this is for preventing that a test branch exists already
|
54
|
+
# and we have some internal error
|
55
|
+
def check_duplicata_pr_branch(pr)
|
56
|
+
puts `git branch --list #{pr}`
|
57
|
+
`git branch -D #{pr} 2>/dev/null` if $CHILD_STATUS.exitstatus.zero?
|
58
|
+
end
|
59
|
+
|
60
|
+
# merge pr_branch into upstream targeted branch
|
61
|
+
def merge_pr_totarget(upstream, pr_branch)
|
62
|
+
goto_prj_dir
|
63
|
+
check_git_dir
|
64
|
+
`git checkout #{upstream}`
|
65
|
+
check_duplicata_pr_branch("#{pr_fix}#{pr_branch}")
|
66
|
+
`git remote update`
|
67
|
+
`git fetch`
|
68
|
+
`git pull origin #{upstream}`
|
69
|
+
`git checkout -b #{pr_fix}#{pr_branch} origin/#{pr_branch}`
|
70
|
+
return if $CHILD_STATUS.exitstatus.zero?
|
71
|
+
# if it fails the PR contain a forked external repo
|
72
|
+
repo_external.checkout_into
|
73
|
+
end
|
74
|
+
|
75
|
+
# cleanup the pr_branch(delete it)
|
76
|
+
def del_pr_branch(upstream, pr)
|
77
|
+
`git checkout #{upstream}`
|
78
|
+
`git branch -D #{pr_fix}#{pr}`
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# This private class handle the case the repo from PR
|
83
|
+
# comes from a user external repo
|
84
|
+
# PR open against: openSUSE/gitarro
|
85
|
+
# PR repo: MyUSER/gitarro
|
86
|
+
class ExternalRepoGit
|
87
|
+
attr_reader :pr, :rem_repo, :pr_fix
|
88
|
+
def initialize(pr, options)
|
89
|
+
# pr object for extract all relev. data.
|
90
|
+
@pr = pr
|
91
|
+
@pr_fix = 'PR-'
|
92
|
+
@options = options
|
93
|
+
end
|
94
|
+
|
95
|
+
def checkout_into
|
96
|
+
rem_repo = 'rem' + pr.head.ref
|
97
|
+
add_remote(rem_repo)
|
98
|
+
fetch_remote(rem_repo)
|
99
|
+
checkout_to_rem_branch(rem_repo)
|
100
|
+
remove_repo(rem_repo)
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def checkout_to_rem_branch(rem_repo)
|
106
|
+
puts `git checkout -b #{pr_fix}#{branch_rem} #{rem_repo}/#{branch_rem}`
|
107
|
+
exit 1 if $CHILD_STATUS.exitstatus.nonzero?
|
108
|
+
end
|
109
|
+
|
110
|
+
def branch_rem
|
111
|
+
pr.head.ref
|
112
|
+
end
|
113
|
+
|
114
|
+
def add_remote(rem_repo)
|
115
|
+
repo_url = @options[:https] ? pr.head.repo.html_url : pr.head.repo.ssh_url
|
116
|
+
puts `git remote add #{rem_repo} #{repo_url}`
|
117
|
+
end
|
118
|
+
|
119
|
+
def fetch_remote(rem_repo)
|
120
|
+
puts `git remote update`
|
121
|
+
puts `git fetch`
|
122
|
+
puts `git pull #{rem_repo} #{pr.head.ref}`
|
123
|
+
end
|
124
|
+
|
125
|
+
def remove_repo(rem_repo)
|
126
|
+
puts `git remote remove #{rem_repo}`
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,197 @@
|
|
1
|
+
#! /usr/bin/ruby
|
2
|
+
|
3
|
+
# this are the mandatory options
|
4
|
+
module MandatoryOptions
|
5
|
+
# primary
|
6
|
+
def context_opt(opt)
|
7
|
+
desc = 'Context to set on comment (test name). For example: python-test.'
|
8
|
+
opt.on('-c', "--context 'CONTEXT'", desc) do |context|
|
9
|
+
@options[:context] = context
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def repo_opt(opt)
|
14
|
+
desc = 'GitHub repository to look for PRs. For example: openSUSE/gitarro.'
|
15
|
+
opt.on('-r', "--repo 'REPO'", desc) { |repo| @options[:repo] = repo }
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_opt(opt)
|
19
|
+
desc = 'Command, or full path to script/binary to be used to run the test.'
|
20
|
+
opt.on('-t', "--test 'TEST.SH'", desc) do |test_file|
|
21
|
+
@options[:test_file] = test_file
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def file_opt(opt)
|
26
|
+
file_description = 'pr_file type to run the test against: .py, .rb'
|
27
|
+
opt.on('-f', "--file \'.py\'", file_description) do |file_type|
|
28
|
+
@options[:file_type] = file_type
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def git_opt(opt)
|
33
|
+
desc = 'Specify a location where gitarro will clone the GitHub project. '\
|
34
|
+
'If the dir does not exists, gitarro will create one. '\
|
35
|
+
'For example: /tmp/'
|
36
|
+
opt.on('-g', "--git_dir 'GIT_LOCAL_DIR'", desc) do |git_dir|
|
37
|
+
@options[:git_dir] = git_dir
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def mandatory_options(opt)
|
42
|
+
opt.separator 'Mandatory options:'
|
43
|
+
repo_opt(opt)
|
44
|
+
context_opt(opt)
|
45
|
+
test_opt(opt)
|
46
|
+
file_opt(opt)
|
47
|
+
git_opt(opt)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# this are the optional options
|
52
|
+
module OptionalOptions
|
53
|
+
def check_opt(opt)
|
54
|
+
desc = 'Check if there is any PR requiring a test, but do not run it.'
|
55
|
+
opt.on('-C', '--check', desc) { |check| @options[:check] = check }
|
56
|
+
end
|
57
|
+
|
58
|
+
def desc_opt(opt)
|
59
|
+
opt.on('-d', "--description 'DESCRIPTION'", 'Test decription') do |d|
|
60
|
+
@options[:description] = d
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def url_opt(opt)
|
65
|
+
desc = 'Specify the URL to append to add to the GitHub review. ' \
|
66
|
+
'Usually you will use an URL to the Jenkins build log.'
|
67
|
+
opt.on('-u', "--url 'TARGET_URL'", desc) do |target_url|
|
68
|
+
@options[:target_url] = target_url
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def https_opt(opt)
|
73
|
+
https_desc = 'If present, use https instead of ssh for git operations'
|
74
|
+
opt.on('--https', https_desc) { |https| @options[:https] = https }
|
75
|
+
end
|
76
|
+
|
77
|
+
def changelog_opt(opt)
|
78
|
+
desc = 'Check if the PR includes a changelog entry ' \
|
79
|
+
'(Automatically sets --file ".changes").'
|
80
|
+
opt.on('--changelogtest', desc) do |changelogtest|
|
81
|
+
@options[:changelog_test] = changelogtest
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def pr_number(opt)
|
86
|
+
desc = 'Specify the PR number instead of checking all of them. ' \
|
87
|
+
'Force to rerun against a specific PR number,' \
|
88
|
+
'even if it is not needed.'
|
89
|
+
opt.on('-P', "--PR 'NUMBER'", desc) do |pr_number|
|
90
|
+
@options[:pr_number] = Integer(pr_number)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def optional_options(opt)
|
95
|
+
opt.separator ''
|
96
|
+
opt.separator 'Optional options:'
|
97
|
+
desc_opt(opt)
|
98
|
+
check_opt(opt)
|
99
|
+
changelog_opt(opt)
|
100
|
+
url_opt(opt)
|
101
|
+
pr_number(opt)
|
102
|
+
https_opt(opt)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# this class is only private and helper for main class OptParser
|
107
|
+
class OptParserInternal
|
108
|
+
include MandatoryOptions
|
109
|
+
include OptionalOptions
|
110
|
+
attr_accessor :options
|
111
|
+
def initialize
|
112
|
+
@options = {}
|
113
|
+
@options = options.clone if options.any?
|
114
|
+
end
|
115
|
+
|
116
|
+
# all this methods are private
|
117
|
+
def raise_incorrect_syntax(msg)
|
118
|
+
puts "Incorrect syntax: #{msg}\n\n"
|
119
|
+
puts 'Use option -h for help'
|
120
|
+
exit 1
|
121
|
+
end
|
122
|
+
|
123
|
+
def ck_mandatory_option(option)
|
124
|
+
return unless @options[option.to_sym].nil?
|
125
|
+
raise_incorrect_syntax("option --#{option} not found")
|
126
|
+
end
|
127
|
+
|
128
|
+
def parse(opt_parser)
|
129
|
+
parse_options(opt_parser)
|
130
|
+
mandatory_options = %w[repo context test_file file_type git_dir]
|
131
|
+
mandatory_options.each { |opt| ck_mandatory_option(opt) }
|
132
|
+
if @options[:test_file].nil? && @options[:changelog_test].nil?
|
133
|
+
raise_incorrect_syntax('Incorrect syntax (use -h for help)')
|
134
|
+
end
|
135
|
+
defaults_false
|
136
|
+
defaults_to_text
|
137
|
+
end
|
138
|
+
|
139
|
+
# option help
|
140
|
+
def option_help(opt)
|
141
|
+
opt.separator ''
|
142
|
+
opt.separator 'Help:'
|
143
|
+
opt.on('-h', '--help', 'help') do
|
144
|
+
opt.separator ''
|
145
|
+
opt.separator "Example: gitarro.rb -r openSUSE/gitarro -c 'python-test' "\
|
146
|
+
"-d 'someCoolTest' -g /tmp/pr-ruby01/ -t /tmp/test.sh "\
|
147
|
+
"-f '.py'"
|
148
|
+
puts @opt_parser
|
149
|
+
exit 0
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
def parse_options(opt_parser)
|
156
|
+
opt_parser.parse!
|
157
|
+
rescue OptionParser::ParseError
|
158
|
+
raise_incorrect_syntax($ERROR_INFO.to_s)
|
159
|
+
end
|
160
|
+
|
161
|
+
# set some default values
|
162
|
+
def defaults_false
|
163
|
+
@options[:check] = false if @options[:check].nil?
|
164
|
+
@options[:changelog_test] = false if @options[:changelog_test].nil?
|
165
|
+
@options[:target_url] = '' if @options[:target_url].nil?
|
166
|
+
@options[:https] = false if @options[:https].nil?
|
167
|
+
end
|
168
|
+
|
169
|
+
def defaults_to_text
|
170
|
+
desc = 'use option -d to set a custom test description.'
|
171
|
+
@options[:file_type] = '.changes' if @options[:changelog_test]
|
172
|
+
@options[:description] = desc if @options[:description].nil?
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# Opt_parser class, is for getting needed options
|
177
|
+
# this is the public class used by backend
|
178
|
+
class OptParser < OptParserInternal
|
179
|
+
private
|
180
|
+
|
181
|
+
def option_banner(opt)
|
182
|
+
opt.banner = "Usage: gitarro.rb [options]\n\n" \
|
183
|
+
end
|
184
|
+
|
185
|
+
public
|
186
|
+
|
187
|
+
def cmdline_options
|
188
|
+
@opt_parser = OptionParser.new do |opt|
|
189
|
+
option_banner(opt)
|
190
|
+
mandatory_options(opt)
|
191
|
+
optional_options(opt)
|
192
|
+
option_help(opt)
|
193
|
+
end
|
194
|
+
parse(@opt_parser)
|
195
|
+
@options
|
196
|
+
end
|
197
|
+
end
|
metadata
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gitarro
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dario Maiocchi
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-09-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: english
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.6'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '5.9'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '5.9'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest-reporters
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.1'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.1'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: netrc
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.11'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.11'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: octokit
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '4.7'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '4.7'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '10.5'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '10.5'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0.49'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0.49'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rspec
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '3.6'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '3.6'
|
125
|
+
description: gitarro run tests on GitHub PRs using almost any script,language or binary,
|
126
|
+
it integrate easy with other tools.
|
127
|
+
email: dmaiocchi@suse.com
|
128
|
+
executables:
|
129
|
+
- gitarro
|
130
|
+
extensions: []
|
131
|
+
extra_rdoc_files: []
|
132
|
+
files:
|
133
|
+
- bin/gitarro
|
134
|
+
- lib/gitarro/backend.rb
|
135
|
+
- lib/gitarro/git_op.rb
|
136
|
+
- lib/gitarro/opt_parser.rb
|
137
|
+
homepage: https://github.com/openSUSE/gitarro
|
138
|
+
licenses:
|
139
|
+
- MIT
|
140
|
+
metadata: {}
|
141
|
+
post_install_message:
|
142
|
+
rdoc_options: []
|
143
|
+
require_paths:
|
144
|
+
- lib
|
145
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
146
|
+
requirements:
|
147
|
+
- - ">="
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0'
|
150
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
151
|
+
requirements:
|
152
|
+
- - ">="
|
153
|
+
- !ruby/object:Gem::Version
|
154
|
+
version: '0'
|
155
|
+
requirements: []
|
156
|
+
rubyforge_project:
|
157
|
+
rubygems_version: 2.5.2
|
158
|
+
signing_key:
|
159
|
+
specification_version: 4
|
160
|
+
summary: gitarro gem
|
161
|
+
test_files: []
|