gergich 0.2.2 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/LICENSE +2 -2
- data/README.md +0 -1
- data/bin/check_coverage +2 -1
- data/bin/gergich +1 -0
- data/bin/master_bouncer +1 -1
- data/bin/run_tests.sh +8 -43
- data/lib/gergich.rb +20 -24
- data/lib/gergich/capture.rb +8 -4
- data/lib/gergich/capture/androidlint_capture.rb +5 -1
- data/lib/gergich/capture/brakeman_capture.rb +4 -2
- data/lib/gergich/capture/eslint_capture.rb +2 -0
- data/lib/gergich/capture/flake8_capture.rb +2 -0
- data/lib/gergich/capture/i18nliner_capture.rb +2 -0
- data/lib/gergich/capture/rubocop_capture.rb +2 -0
- data/lib/gergich/capture/shellcheck_capture.rb +2 -0
- data/lib/gergich/capture/stylelint_capture.rb +8 -5
- data/lib/gergich/capture/swiftlint_capture.rb +5 -1
- data/lib/gergich/cli.rb +4 -2
- data/lib/gergich/cli/gergich.rb +119 -118
- data/lib/gergich/cli/master_bouncer.rb +16 -14
- data/spec/gergich/capture/androidlint_capture_spec.rb +15 -10
- data/spec/gergich/capture/brakeman_capture_spec.rb +43 -41
- data/spec/gergich/capture/custom_capture_spec.rb +4 -2
- data/spec/gergich/capture/eslint_capture_spec.rb +6 -4
- data/spec/gergich/capture/flake8_capture_spec.rb +4 -2
- data/spec/gergich/capture/i18nliner_capture_spec.rb +6 -4
- data/spec/gergich/capture/rubocop_capture_spec.rb +24 -22
- data/spec/gergich/capture/shellcheck_capture_spec.rb +45 -43
- data/spec/gergich/capture/stylelint_capture_spec.rb +16 -7
- data/spec/gergich/capture/swiftlint_capture_spec.rb +8 -5
- data/spec/gergich/capture_spec.rb +6 -4
- data/spec/gergich_spec.rb +58 -4
- data/spec/spec_helper.rb +2 -0
- data/spec/support/capture_shared_examples.rb +2 -0
- metadata +39 -40
data/lib/gergich/cli.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "shellwords"
|
2
4
|
require "English"
|
3
5
|
|
@@ -38,7 +40,7 @@ def help_command(commands)
|
|
38
40
|
end
|
39
41
|
},
|
40
42
|
help: -> {
|
41
|
-
indentation = commands.keys.map(&:size).
|
43
|
+
indentation = commands.keys.map(&:size).max
|
42
44
|
commands_help = commands
|
43
45
|
.to_a
|
44
46
|
.sort_by(&:first)
|
@@ -73,7 +75,7 @@ def run_app(commands)
|
|
73
75
|
run_command(action)
|
74
76
|
rescue GergichError
|
75
77
|
error $ERROR_INFO.message
|
76
|
-
rescue
|
78
|
+
rescue StandardError
|
77
79
|
error "Unhandled exception: #{$ERROR_INFO}\n#{$ERROR_INFO.backtrace.join("\n")}"
|
78
80
|
end
|
79
81
|
else
|
data/lib/gergich/cli/gergich.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative "../cli"
|
4
4
|
require_relative "../../gergich"
|
@@ -14,11 +14,11 @@ CI_TEST_ARGS = {
|
|
14
14
|
],
|
15
15
|
"label" => ["Code-Review", 1],
|
16
16
|
"message" => ["this is a test"],
|
17
|
-
"capture" => ["rubocop", "echo
|
18
|
-
bin/gergich:47:8: C: Prefer double-quoted strings
|
19
|
-
if ENV['DEBUG']
|
20
|
-
|
21
|
-
OUTPUT
|
17
|
+
"capture" => ["rubocop", format("echo %<output>s", output: Shellwords.escape(<<~OUTPUT))]
|
18
|
+
bin/gergich:47:8: C: Prefer double-quoted strings
|
19
|
+
if ENV['DEBUG']
|
20
|
+
^^^^^^^
|
21
|
+
OUTPUT
|
22
22
|
}.freeze
|
23
23
|
|
24
24
|
def run_ci_test!(all_commands)
|
@@ -27,13 +27,14 @@ def run_ci_test!(all_commands)
|
|
27
27
|
commands_to_test << "status" # put it at the end, so we maximize the stuff it tests
|
28
28
|
|
29
29
|
commands = commands_to_test.map { |command| [command, CI_TEST_ARGS[command] || []] }
|
30
|
-
commands.concat
|
30
|
+
commands.concat(all_commands.map { |command| ["help", [command]] })
|
31
31
|
|
32
32
|
# after running our test commands, reset and publish frd:
|
33
33
|
commands << ["reset"]
|
34
|
-
|
35
|
-
|
36
|
-
commands << ["label", ["
|
34
|
+
# Note that while gergich should always be able to vote on these labels, he may be used to
|
35
|
+
# vone on other branches depending on project usage and project-specific permissions
|
36
|
+
commands << ["label", ["Lint-Review", 1]]
|
37
|
+
commands << ["label", ["Code-Review", 1]] # Not all projects have Lint-Review
|
37
38
|
commands << ["message", ["\`gergich citest\` checks out :thumbsup: :mj:"]]
|
38
39
|
commands << ["publish"]
|
39
40
|
|
@@ -50,21 +51,21 @@ commands = {}
|
|
50
51
|
|
51
52
|
commands["reset"] = {
|
52
53
|
summary: "Clear out pending comments/labels/messages for this patchset",
|
53
|
-
action: ->
|
54
|
+
action: -> {
|
54
55
|
Gergich::Draft.new.reset!
|
55
56
|
},
|
56
57
|
help: -> {
|
57
|
-
|
58
|
-
gergich reset
|
58
|
+
<<~TEXT
|
59
|
+
gergich reset
|
59
60
|
|
60
|
-
Clear out the draft for this patchset. Useful for testing.
|
61
|
-
TEXT
|
61
|
+
Clear out the draft for this patchset. Useful for testing.
|
62
|
+
TEXT
|
62
63
|
}
|
63
64
|
}
|
64
65
|
|
65
66
|
commands["publish"] = {
|
66
67
|
summary: "Publish the draft for this patchset",
|
67
|
-
action: ->
|
68
|
+
action: -> {
|
68
69
|
if (data = Gergich::Review.new.publish!)
|
69
70
|
puts "Published #{data[:total_comments]} comments, set score to #{data[:score]}"
|
70
71
|
else
|
@@ -72,33 +73,33 @@ commands["publish"] = {
|
|
72
73
|
end
|
73
74
|
},
|
74
75
|
help: -> {
|
75
|
-
|
76
|
-
gergich publish
|
76
|
+
<<~TEXT
|
77
|
+
gergich publish
|
77
78
|
|
78
|
-
Publish all draft comments/labels/messages for this patchset. no-op if
|
79
|
-
there are none.
|
79
|
+
Publish all draft comments/labels/messages for this patchset. no-op if
|
80
|
+
there are none.
|
80
81
|
|
81
|
-
The cover message and Code-Review label (e.g. -2) are inferred from the
|
82
|
-
comments, but labels and messages may be manually set (via `gergich
|
83
|
-
message` and `gergich labels`)
|
84
|
-
TEXT
|
82
|
+
The cover message and Code-Review label (e.g. -2) are inferred from the
|
83
|
+
comments, but labels and messages may be manually set (via `gergich
|
84
|
+
message` and `gergich labels`)
|
85
|
+
TEXT
|
85
86
|
}
|
86
87
|
}
|
87
88
|
|
88
89
|
commands["status"] = {
|
89
90
|
summary: "Show the current draft for this patchset",
|
90
|
-
action: ->
|
91
|
+
action: -> {
|
91
92
|
Gergich::Review.new.status
|
92
93
|
},
|
93
94
|
help: -> {
|
94
|
-
|
95
|
-
gergich status
|
95
|
+
<<~TEXT
|
96
|
+
gergich status
|
96
97
|
|
97
|
-
Show the current draft for this patchset
|
98
|
+
Show the current draft for this patchset
|
98
99
|
|
99
|
-
Display any labels, cover messages and inline comments that will be set
|
100
|
-
as part of this review.
|
101
|
-
TEXT
|
100
|
+
Display any labels, cover messages and inline comments that will be set
|
101
|
+
as part of this review.
|
102
|
+
TEXT
|
102
103
|
}
|
103
104
|
}
|
104
105
|
|
@@ -107,8 +108,8 @@ commands["comment"] = {
|
|
107
108
|
action: ->(comment_data) {
|
108
109
|
comment_data = begin
|
109
110
|
JSON.parse(comment_data)
|
110
|
-
|
111
|
-
|
111
|
+
rescue JSON::ParserError
|
112
|
+
error("Unable to parse <comment_data> json", "comment")
|
112
113
|
end
|
113
114
|
comment_data = [comment_data] unless comment_data.is_a?(Array)
|
114
115
|
|
@@ -120,36 +121,36 @@ commands["comment"] = {
|
|
120
121
|
comment["severity"]
|
121
122
|
end
|
122
123
|
},
|
123
|
-
help: ->
|
124
|
-
|
125
|
-
gergich comment <comment_data>
|
126
|
-
|
127
|
-
<comment_data> is a JSON object (or array of objects). Each comment object
|
128
|
-
should have the following properties:
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
Note that a cover message and Code-Review score will be inferred from the
|
143
|
-
most severe comment.
|
144
|
-
|
145
|
-
Examples
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
TEXT
|
124
|
+
help: -> {
|
125
|
+
<<~TEXT
|
126
|
+
gergich comment <comment_data>
|
127
|
+
|
128
|
+
<comment_data> is a JSON object (or array of objects). Each comment object
|
129
|
+
should have the following properties:
|
130
|
+
path - the relative file path, e.g. "app/models/user.rb"
|
131
|
+
position - either a number (line) or an object (range). If an object,
|
132
|
+
must have the following numeric properties:
|
133
|
+
* start_line
|
134
|
+
* start_character
|
135
|
+
* end_line
|
136
|
+
* end_character
|
137
|
+
message - the text of the comment
|
138
|
+
severity - "info"|"warn"|"error" - this will automatically prefix the
|
139
|
+
comment (e.g. "[ERROR] message here"), and the most severe
|
140
|
+
comment will be used to determine the overall Code-Review
|
141
|
+
score (0, -1, or -2 respectively)
|
142
|
+
|
143
|
+
Note that a cover message and Code-Review score will be inferred from the
|
144
|
+
most severe comment.
|
145
|
+
|
146
|
+
Examples
|
147
|
+
gergich comment '{"path":"foo.rb","position":3,"severity":"error",
|
148
|
+
"message":"ಠ_ಠ"}'
|
149
|
+
gergich comment '{"path":"bar.rb","severity":"warn",
|
150
|
+
"position":{"start_line":3,"start_character":5,...},
|
151
|
+
"message":"¯\\_(ツ)_/¯"}'
|
152
|
+
gergich comment '[{"path":"baz.rb",...}, {...}, {...}]'
|
153
|
+
TEXT
|
153
154
|
}
|
154
155
|
}
|
155
156
|
|
@@ -159,13 +160,13 @@ commands["message"] = {
|
|
159
160
|
draft = Gergich::Draft.new
|
160
161
|
draft.add_message message
|
161
162
|
},
|
162
|
-
help: ->
|
163
|
-
|
164
|
-
gergich message <message>
|
163
|
+
help: -> {
|
164
|
+
<<~TEXT
|
165
|
+
gergich message <message>
|
165
166
|
|
166
|
-
<message> will be appended to existing cover messages (inferred or manually
|
167
|
-
added) for this patchset.
|
168
|
-
TEXT
|
167
|
+
<message> will be appended to existing cover messages (inferred or manually
|
168
|
+
added) for this patchset.
|
169
|
+
TEXT
|
169
170
|
}
|
170
171
|
}
|
171
172
|
|
@@ -174,16 +175,16 @@ commands["label"] = {
|
|
174
175
|
action: ->(label, score) {
|
175
176
|
Gergich::Draft.new.add_label label, score
|
176
177
|
},
|
177
|
-
help: ->
|
178
|
-
|
179
|
-
gergich label <label> <score>
|
178
|
+
help: -> {
|
179
|
+
<<~TEXT
|
180
|
+
gergich label <label> <score>
|
180
181
|
|
181
|
-
Add a draft label to this patchset. If the same label is set multiple
|
182
|
-
times, the lowest score will win.
|
182
|
+
Add a draft label to this patchset. If the same label is set multiple
|
183
|
+
times, the lowest score will win.
|
183
184
|
|
184
|
-
<label> - a valid label (e.g. "Code-Review")
|
185
|
-
<score> - a valid score (e.g. -1)
|
186
|
-
TEXT
|
185
|
+
<label> - a valid label (e.g. "Code-Review")
|
186
|
+
<score> - a valid score (e.g. -1)
|
187
|
+
TEXT
|
187
188
|
}
|
188
189
|
}
|
189
190
|
|
@@ -194,63 +195,63 @@ commands["capture"] = {
|
|
194
195
|
status, = Gergich::Capture.run(format, command)
|
195
196
|
exit status
|
196
197
|
},
|
197
|
-
help: ->
|
198
|
-
|
199
|
-
gergich capture <format> <command>
|
198
|
+
help: -> {
|
199
|
+
<<~TEXT
|
200
|
+
gergich capture <format> <command>
|
200
201
|
|
201
|
-
For common linting formats, `gergich capture` can be used to automatically
|
202
|
-
do `gergich comment` calls so you don't have to wire it up yourself.
|
202
|
+
For common linting formats, `gergich capture` can be used to automatically
|
203
|
+
do `gergich comment` calls so you don't have to wire it up yourself.
|
203
204
|
|
204
|
-
<format> - One of the following:
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
205
|
+
<format> - One of the following:
|
206
|
+
* brakeman
|
207
|
+
* rubocop
|
208
|
+
* eslint
|
209
|
+
* i18nliner
|
210
|
+
* flake8
|
211
|
+
* stylelint
|
212
|
+
* custom:<path>:<class_name> - file path and ruby
|
213
|
+
class_name of a custom formatter.
|
213
214
|
|
214
|
-
<command> - The command to run whose output conforms to <format>.
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
215
|
+
<command> - The command to run whose output conforms to <format>.
|
216
|
+
Output from the command will still go to STDOUT, and
|
217
|
+
Gergich will preserve its exit status.
|
218
|
+
If command is "-", Gergich will simply read from STDIN
|
219
|
+
and the exit status will always be 0.
|
219
220
|
|
220
|
-
Examples:
|
221
|
-
|
221
|
+
Examples:
|
222
|
+
gergich capture rubocop "bundle exec rubocop"
|
222
223
|
|
223
|
-
|
224
|
+
gergich capture eslint eslint
|
224
225
|
|
225
|
-
|
226
|
+
gergich capture i18nliner "rake i18nliner:check"
|
226
227
|
|
227
|
-
|
228
|
+
gergich capture custom:./gergich/xss:Gergich::XSS "node script/xsslint"
|
228
229
|
|
229
|
-
|
230
|
-
|
231
|
-
TEXT
|
230
|
+
docker-compose run --rm web eslint | gergich capture eslint -
|
231
|
+
# you might be interested in $PIPESTATUS[0]
|
232
|
+
TEXT
|
232
233
|
}
|
233
234
|
}
|
234
235
|
|
235
236
|
commands["citest"] = {
|
236
237
|
summary: "Do a full gergich test based on the current commit",
|
237
|
-
action: ->
|
238
|
+
action: -> {
|
238
239
|
# automagically test any new command that comes along
|
239
240
|
run_ci_test!(commands.keys)
|
240
241
|
},
|
241
|
-
help: ->
|
242
|
-
|
243
|
-
gergich citest
|
244
|
-
|
245
|
-
You shouldn't need to run this locally, it runs on jenkins. It does the
|
246
|
-
following:
|
247
|
-
|
248
|
-
1. runs all the gergich commands (w/ dummy data)
|
249
|
-
2. ensure all `help` commands work
|
250
|
-
3. ensures gergich status is correct
|
251
|
-
4. resets
|
252
|
-
5. posts an actual +1
|
253
|
-
6. publishes
|
242
|
+
help: -> {
|
243
|
+
<<~TEXT
|
244
|
+
gergich citest
|
245
|
+
|
246
|
+
You shouldn't need to run this locally, it runs on jenkins. It does the
|
247
|
+
following:
|
248
|
+
|
249
|
+
1. runs all the gergich commands (w/ dummy data)
|
250
|
+
2. ensure all `help` commands work
|
251
|
+
3. ensures gergich status is correct
|
252
|
+
4. resets
|
253
|
+
5. posts an actual +1
|
254
|
+
6. publishes
|
254
255
|
TEXT
|
255
256
|
}
|
256
257
|
}
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative "../cli"
|
2
4
|
|
3
5
|
ENV["GERGICH_USER"] = ENV.fetch("MASTER_BOUNCER_USER", "master_bouncer")
|
@@ -19,7 +21,7 @@ def potentially_mergeable_changes
|
|
19
21
|
"branch:master" \
|
20
22
|
"&o=CURRENT_REVISION"
|
21
23
|
changes = Gergich::API.get(url)
|
22
|
-
changes.
|
24
|
+
changes.reject { |c| c["subject"] =~ /\Awip($|\W)/i }
|
23
25
|
end
|
24
26
|
|
25
27
|
def maybe_bounce_commit!(commit)
|
@@ -67,22 +69,22 @@ commands = {}
|
|
67
69
|
|
68
70
|
commands["check"] = {
|
69
71
|
summary: "Check the current commit's age",
|
70
|
-
action: ->
|
72
|
+
action: -> {
|
71
73
|
maybe_bounce_commit! Gergich::Commit.new
|
72
74
|
},
|
73
|
-
help: ->
|
74
|
-
|
75
|
-
master_bouncer check
|
75
|
+
help: -> {
|
76
|
+
<<~TEXT
|
77
|
+
master_bouncer check
|
76
78
|
|
77
|
-
Check the current commit's age, and bounce it if it's too old (-1 or -2,
|
78
|
-
depending on the threshold)
|
79
|
-
TEXT
|
79
|
+
Check the current commit's age, and bounce it if it's too old (-1 or -2,
|
80
|
+
depending on the threshold)
|
81
|
+
TEXT
|
80
82
|
}
|
81
83
|
}
|
82
84
|
|
83
85
|
commands["check_all"] = {
|
84
86
|
summary: "Check the age of all potentially mergeable changes",
|
85
|
-
action: ->
|
87
|
+
action: -> {
|
86
88
|
Gergich.git("fetch")
|
87
89
|
gerrit_host = ENV["GERRIT_HOST"] || error("No GERRIT_HOST set")
|
88
90
|
|
@@ -102,12 +104,12 @@ commands["check_all"] = {
|
|
102
104
|
sleep 1
|
103
105
|
end
|
104
106
|
},
|
105
|
-
help: ->
|
106
|
-
|
107
|
-
master_bouncer check_all
|
107
|
+
help: -> {
|
108
|
+
<<~TEXT
|
109
|
+
master_bouncer check_all
|
108
110
|
|
109
|
-
Check all open Verified+1 patchsets and bounce any that are too old.
|
110
|
-
TEXT
|
111
|
+
Check all open Verified+1 patchsets and bounce any that are too old.
|
112
|
+
TEXT
|
111
113
|
}
|
112
114
|
}
|
113
115
|
|
@@ -1,24 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative "../../support/capture_shared_examples"
|
2
4
|
|
3
5
|
RSpec.describe Gergich::Capture::AndroidlintCapture do
|
4
|
-
# rubocop:disable
|
6
|
+
# rubocop:disable Layout/LineLength
|
5
7
|
let(:rtl_hardcoded) { 'Consider adding android:drawableStart="@drawable/a_media" to better support right-to-left layouts [RtlHardcoded]' }
|
6
8
|
let(:rtl_enabled) { "The project references RTL attributes, but does not explicitly enable or disable RTL support with android:supportsRtl in the manifest [RtlEnabled]" }
|
7
9
|
let(:lint_error) { 'No .class files were found in project "0.0.2", so none of the classfile based checks could be run. Does the project need to be built first? [LintError]' }
|
8
10
|
let(:unused_quantity) { 'For language "fr" (French) the following quantities are not relevant: few, zero [UnusedQuantity]' }
|
11
|
+
# rubocop:enable Layout/LineLength
|
9
12
|
let(:output) do
|
10
|
-
|
11
|
-
/path/to/some.xml:27: Warning: #{rtl_hardcoded}
|
12
|
-
|
13
|
-
|
13
|
+
<<~OUTPUT
|
14
|
+
/path/to/some.xml:27: Warning: #{rtl_hardcoded}
|
15
|
+
android:drawableLeft="@drawable/ic_cv_media"/>
|
16
|
+
~~~~~~~~~~~~~~~~~~~~
|
14
17
|
|
15
|
-
/path/to/AndroidManifest.xml: Warning: #{rtl_enabled}
|
18
|
+
/path/to/AndroidManifest.xml: Warning: #{rtl_enabled}
|
16
19
|
|
17
|
-
/path/to/library/0.0.2: Error: #{lint_error}
|
20
|
+
/path/to/library/0.0.2: Error: #{lint_error}
|
18
21
|
|
19
|
-
/path/to/values.xml:5: Warning: #{unused_quantity}
|
20
|
-
|
21
|
-
|
22
|
+
/path/to/values.xml:5: Warning: #{unused_quantity}
|
23
|
+
<plurals name="number">
|
24
|
+
^
|
22
25
|
|
23
26
|
OUTPUT
|
24
27
|
end
|
@@ -28,7 +31,9 @@ RSpec.describe Gergich::Capture::AndroidlintCapture do
|
|
28
31
|
{
|
29
32
|
path: "/path/to/some.xml",
|
30
33
|
position: 27,
|
34
|
+
# rubocop:disable Layout/LineLength
|
31
35
|
message: "[androidlint] #{rtl_hardcoded}\n\n android:drawableLeft=\"@drawable/ic_cv_media\"/>\n ~~~~~~~~~~~~~~~~~~~~",
|
36
|
+
# rubocop:enable Layout/LineLength
|
32
37
|
severity: "warn"
|
33
38
|
},
|
34
39
|
{
|