gergich 0.0.3 → 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 +4 -4
- data/README.md +4 -0
- data/bin/master_bouncer +5 -0
- data/bin/run_tests.sh +49 -0
- data/lib/gergich.rb +11 -7
- data/lib/gergich/capture.rb +1 -1
- data/lib/gergich/capture/eslint_capture.rb +6 -3
- data/lib/gergich/cli/gergich.rb +1 -0
- data/lib/gergich/cli/master_bouncer.rb +9 -5
- data/spec/gergich/capture_spec.rb +71 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0f0688286ddfbfdcc686368378288bfb25914eb4
|
4
|
+
data.tar.gz: 3343039cccc137106652aed7061be6ecd6096995
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 10294cd73ad93b2e289aa7f68b5bc08bed49fb3b6aaa30d6912ad1b61fd0e7f2dc550a335e0487da9149582a29bbb14754f9e7e28d21f4ec5fe88e0d86a6e308
|
7
|
+
data.tar.gz: 29b71a28a0ca12b710cbd00bb232fa9100d516d16c4d0a8883783c0476016beb8cb04c7d8e5784e7881edcae5ca32e7a90b202ea9b15f0066c56a4643b797882
|
data/README.md
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# Gergich
|
2
2
|
|
3
|
+
[](https://rubygems.org/gems/gergich)
|
4
|
+
[](https://gemnasium.com/cc6fb44edee9fcf855cec82d3b6aed0f)
|
5
|
+
[](https://travis-ci.org/instructure/gergich)
|
6
|
+
|
3
7
|
Gergich is a command-line tool (and ruby lib) for easily posting comments
|
4
8
|
on a [Gerrit](https://www.gerritcodereview.com/) review from a CI
|
5
9
|
environment. It can be wired up to linters (rubocop, eslint, etc.) so that
|
data/bin/master_bouncer
CHANGED
data/bin/run_tests.sh
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
set -e
|
4
|
+
|
5
|
+
function run_command {
|
6
|
+
echo -e "\n[$@] STARTING $(date)"
|
7
|
+
last_status=0
|
8
|
+
"$@" || last_status=$?
|
9
|
+
if [[ $last_status == 0 ]]; then
|
10
|
+
echo -e "[$@] \033[32mOK\033[0m"
|
11
|
+
else
|
12
|
+
echo -e "[$@] \033[31mFAILED!\033[0m"
|
13
|
+
fi
|
14
|
+
echo -e "[$@] FINISHED $(date)\n"
|
15
|
+
|
16
|
+
[[ $last_status == 0 ]] || clean_up_and_exit
|
17
|
+
}
|
18
|
+
|
19
|
+
function clean_up_and_exit {
|
20
|
+
end_timestamp=$(date +%s)
|
21
|
+
duration=$((end_timestamp-start_timestamp))
|
22
|
+
|
23
|
+
if [[ $last_status != 0 ]]; then
|
24
|
+
echo -e "\033[31mBUILD FAILED\033[0m in $duration seconds\n"
|
25
|
+
else
|
26
|
+
echo "BUILD PASSED in $duration seconds"
|
27
|
+
fi
|
28
|
+
exit $last_status
|
29
|
+
}
|
30
|
+
|
31
|
+
start_timestamp=$(date +%s)
|
32
|
+
|
33
|
+
run_command bundle exec rubocop
|
34
|
+
|
35
|
+
export COVERAGE=1
|
36
|
+
|
37
|
+
run_command bundle exec rspec
|
38
|
+
run_command bin/gergich citest
|
39
|
+
run_command bin/master_bouncer check
|
40
|
+
DRY_RUN=1 run_command bin/master_bouncer check_all
|
41
|
+
|
42
|
+
run_command bin/check_coverage
|
43
|
+
|
44
|
+
if [[ $GEMNASIUM_TOKEN && $GEMNASIUM_ENABLED ]]; then
|
45
|
+
# Push our dependency specification files to gemnasium for analysis
|
46
|
+
run_command gemnasium dependency_files push -f=gergich.gemspec
|
47
|
+
fi
|
48
|
+
|
49
|
+
clean_up_and_exit
|
data/lib/gergich.rb
CHANGED
@@ -73,13 +73,17 @@ module Gergich
|
|
73
73
|
API.post(generate_url, generate_payload)
|
74
74
|
|
75
75
|
# because why not
|
76
|
-
if
|
76
|
+
if change_name?
|
77
77
|
API.put("/accounts/self/name", { name: whats_his_face }.to_json)
|
78
78
|
end
|
79
79
|
|
80
80
|
review_info
|
81
81
|
end
|
82
82
|
|
83
|
+
def change_name?
|
84
|
+
ENV["GERGICH_CHANGE_NAME"] != "0" && rand < 0.01 && GERGICH_USER == "gergich"
|
85
|
+
end
|
86
|
+
|
83
87
|
def anything_to_publish?
|
84
88
|
!review_info[:comments].empty? ||
|
85
89
|
!review_info[:cover_message].empty? ||
|
@@ -202,7 +206,7 @@ module Gergich
|
|
202
206
|
@base_url ||= \
|
203
207
|
ENV["GERRIT_BASE_URL"] ||
|
204
208
|
ENV.key?("GERRIT_HOST") && "https://#{ENV['GERRIT_HOST']}" ||
|
205
|
-
raise("need to set GERRIT_BASE_URL or GERRIT_HOST")
|
209
|
+
raise(GergichError, "need to set GERRIT_BASE_URL or GERRIT_HOST")
|
206
210
|
end
|
207
211
|
|
208
212
|
def base_options
|
@@ -281,8 +285,8 @@ module Gergich
|
|
281
285
|
# a higher score set here.
|
282
286
|
def add_label(name, score)
|
283
287
|
score = score.to_i
|
284
|
-
raise "invalid score" if score < -2 || score > 1
|
285
|
-
raise "can't set #{name}" if %w[Verified].include?(name)
|
288
|
+
raise GergichError, "invalid score" if score < -2 || score > 1
|
289
|
+
raise GergichError, "can't set #{name}" if %w[Verified].include?(name)
|
286
290
|
|
287
291
|
db.execute "INSERT INTO labels (name, score) VALUES (?, ?)",
|
288
292
|
[name, score]
|
@@ -311,10 +315,10 @@ module Gergich
|
|
311
315
|
# severe comment will be used to determine the overall
|
312
316
|
# Code-Review score (0, -1, or -2 respectively)
|
313
317
|
def add_comment(path, position, message, severity)
|
314
|
-
raise "invalid position `#{position}`" unless valid_position?(position)
|
318
|
+
raise GergichError, "invalid position `#{position}`" unless valid_position?(position)
|
315
319
|
position = position.to_json if position.is_a?(Hash)
|
316
|
-
raise "invalid severity `#{severity}`" unless SEVERITY_MAP.key?(severity)
|
317
|
-
raise "no message specified" unless message.is_a?(String) && !message.empty?
|
320
|
+
raise GergichError, "invalid severity `#{severity}`" unless SEVERITY_MAP.key?(severity)
|
321
|
+
raise GergichError, "no message specified" unless message.is_a?(String) && !message.empty?
|
318
322
|
|
319
323
|
db.execute "INSERT INTO comments (path, position, message, severity) VALUES (?, ?, ?, ?)",
|
320
324
|
[path, position, message, severity]
|
data/lib/gergich/capture.rb
CHANGED
@@ -1,17 +1,20 @@
|
|
1
1
|
module Gergich
|
2
2
|
module Capture
|
3
3
|
class EslintCapture < BaseCapture
|
4
|
+
SEVERITY_MAP = { "error" => "error", "warning" => "warn" }.freeze
|
5
|
+
|
4
6
|
def run(output)
|
5
7
|
# e.g. " 4:21 error Missing semicolon semi"
|
6
|
-
error_pattern = /\s\s+(\d+):\d+\s
|
8
|
+
error_pattern = /\s\s+(\d+):\d+\s+(\w+)\s+(.*?)\s+[\w-]+\n/
|
7
9
|
pattern = %r{ # Example:
|
8
10
|
^([^\n]+)\n # jsapp/models/user.js
|
9
11
|
((#{error_pattern})+) # 4:21 error Missing semicolon semi
|
10
12
|
}mx
|
11
13
|
|
12
14
|
output.scan(pattern).map { |file, errors|
|
13
|
-
errors.scan(error_pattern).map { |line, error|
|
14
|
-
|
15
|
+
errors.scan(error_pattern).map { |line, severity, error|
|
16
|
+
severity = SEVERITY_MAP[severity]
|
17
|
+
{ path: file, message: "[eslint] #{error}", position: line.to_i, severity: severity }
|
15
18
|
}
|
16
19
|
}.compact.flatten
|
17
20
|
end
|
data/lib/gergich/cli/gergich.rb
CHANGED
@@ -66,7 +66,7 @@ commands = {}
|
|
66
66
|
|
67
67
|
commands["check"] = {
|
68
68
|
summary: "Check the current commit's age",
|
69
|
-
action: ->(
|
69
|
+
action: ->() {
|
70
70
|
maybe_bounce_commit! Gergich::Commit.new
|
71
71
|
},
|
72
72
|
help: ->() {
|
@@ -81,17 +81,21 @@ TEXT
|
|
81
81
|
|
82
82
|
commands["check_all"] = {
|
83
83
|
summary: "Check the age of all potentially mergeable changes",
|
84
|
-
action: ->(
|
84
|
+
action: ->() {
|
85
85
|
Gergich.git("fetch")
|
86
|
+
gerrit_host = ENV["GERRIT_HOST"] || error("No GERRIT_HOST set")
|
86
87
|
|
87
|
-
|
88
|
-
|
88
|
+
changes = potentially_mergeable_changes
|
89
|
+
next if ENV["DRY_RUN"]
|
89
90
|
|
91
|
+
changes.each do |change|
|
90
92
|
sha = change["current_revision"]
|
91
93
|
revinfo = change["revisions"][sha]
|
92
94
|
refspec = revinfo["ref"]
|
93
95
|
number = revinfo["_number"]
|
94
|
-
|
96
|
+
|
97
|
+
print "Checking g/#{change['_number']}... "
|
98
|
+
Gergich.git("fetch ssh://#{gerrit_host}:29418/#{PROJECT} #{refspec}")
|
95
99
|
|
96
100
|
maybe_bounce_commit! Gergich::Commit.new(sha, number)
|
97
101
|
sleep 1
|
@@ -5,6 +5,11 @@ RSpec.describe Gergich::Capture do
|
|
5
5
|
|
6
6
|
before do
|
7
7
|
allow(Gergich::Draft).to receive(:new).and_return(draft)
|
8
|
+
$stdout = StringIO.new
|
9
|
+
end
|
10
|
+
|
11
|
+
after do
|
12
|
+
$stdout = STDOUT
|
8
13
|
end
|
9
14
|
|
10
15
|
context "rubocop" do
|
@@ -28,7 +33,8 @@ OUTPUT
|
|
28
33
|
it "should catch errors" do
|
29
34
|
allow(described_class).to receive(:run_command).and_return([0, <<-OUTPUT])
|
30
35
|
jsapp/models/user.js
|
31
|
-
4:21 error
|
36
|
+
4:21 error Missing semicolon semi
|
37
|
+
5:1 warning Too much cowbell cowbell-overload
|
32
38
|
OUTPUT
|
33
39
|
expect(draft).to receive(:add_comment).with(
|
34
40
|
"jsapp/models/user.js",
|
@@ -36,6 +42,13 @@ OUTPUT
|
|
36
42
|
"[eslint] Missing semicolon",
|
37
43
|
"error"
|
38
44
|
)
|
45
|
+
|
46
|
+
expect(draft).to receive(:add_comment).with(
|
47
|
+
"jsapp/models/user.js",
|
48
|
+
5,
|
49
|
+
"[eslint] Too much cowbell",
|
50
|
+
"warn"
|
51
|
+
)
|
39
52
|
described_class.run("eslint", "false")
|
40
53
|
end
|
41
54
|
end
|
@@ -56,4 +69,61 @@ OUTPUT
|
|
56
69
|
described_class.run("i18nliner", "false")
|
57
70
|
end
|
58
71
|
end
|
72
|
+
|
73
|
+
context "custom" do
|
74
|
+
class CustomCaptor
|
75
|
+
def run(output)
|
76
|
+
puts output
|
77
|
+
output.scan(/^(.+?):(\d+): (.*)$/).map do |file, line, error|
|
78
|
+
{ path: file, message: error, position: line.to_i, severity: "error" }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should catch errors" do
|
84
|
+
allow(described_class).to receive(:run_command).and_return([0, <<-OUTPUT])
|
85
|
+
foo.rb:1: you done screwed up
|
86
|
+
OUTPUT
|
87
|
+
expect(draft).to receive(:add_comment).with(
|
88
|
+
"foo.rb",
|
89
|
+
1,
|
90
|
+
"you done screwed up",
|
91
|
+
"error"
|
92
|
+
)
|
93
|
+
described_class.run("custom:sqlite3:CustomCaptor", "false")
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context "stdin" do
|
98
|
+
let :output do
|
99
|
+
<<-OUTPUT
|
100
|
+
jsapp/models/user.js
|
101
|
+
4:21 error Missing semicolon semi
|
102
|
+
OUTPUT
|
103
|
+
end
|
104
|
+
|
105
|
+
before do
|
106
|
+
$stdin = StringIO.new(output)
|
107
|
+
end
|
108
|
+
|
109
|
+
after do
|
110
|
+
$stdin = STDIN
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should catch errors" do
|
114
|
+
expect(draft).to receive(:add_comment).with(
|
115
|
+
"jsapp/models/user.js",
|
116
|
+
4,
|
117
|
+
"[eslint] Missing semicolon",
|
118
|
+
"error"
|
119
|
+
)
|
120
|
+
described_class.run("eslint", "-")
|
121
|
+
end
|
122
|
+
|
123
|
+
it "shouldn't eat stdin" do
|
124
|
+
allow(draft).to receive(:add_comment)
|
125
|
+
expect($stdout).to receive(:puts).exactly(output.lines.size).times
|
126
|
+
described_class.run("eslint", "-")
|
127
|
+
end
|
128
|
+
end
|
59
129
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gergich
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jon Jensen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-04-
|
11
|
+
date: 2016-04-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sqlite3
|
@@ -52,6 +52,7 @@ files:
|
|
52
52
|
- bin/check_coverage
|
53
53
|
- bin/gergich
|
54
54
|
- bin/master_bouncer
|
55
|
+
- bin/run_tests.sh
|
55
56
|
- lib/gergich.rb
|
56
57
|
- lib/gergich/capture.rb
|
57
58
|
- lib/gergich/capture/eslint_capture.rb
|