gergich 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/gergich.svg)](https://rubygems.org/gems/gergich)
|
4
|
+
[![Dependency Status](https://gemnasium.com/badges/a2946a7849cd94f5ec0f4c3173a968f4.svg)](https://gemnasium.com/cc6fb44edee9fcf855cec82d3b6aed0f)
|
5
|
+
[![Build Status](https://travis-ci.org/instructure/gergich.svg?branch=master)](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
|