gergich 1.2.3 → 2.0.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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/{bin → exe}/gergich +0 -0
  3. data/{bin → exe}/master_bouncer +0 -0
  4. data/lib/gergich/capture/androidlint_capture.rb +8 -3
  5. data/lib/gergich/capture/brakeman_capture.rb +3 -2
  6. data/lib/gergich/capture/eslint_capture.rb +2 -1
  7. data/lib/gergich/capture/flake8_capture.rb +1 -1
  8. data/lib/gergich/capture/i18nliner_capture.rb +1 -1
  9. data/lib/gergich/capture/rubocop_capture.rb +19 -3
  10. data/lib/gergich/capture/shellcheck_capture.rb +2 -1
  11. data/lib/gergich/capture/stylelint_capture.rb +2 -5
  12. data/lib/gergich/capture/swiftlint_capture.rb +1 -1
  13. data/lib/gergich/capture/yamllint_capture.rb +8 -2
  14. data/lib/gergich/capture.rb +12 -5
  15. data/lib/gergich/cli/gergich.rb +3 -3
  16. data/lib/gergich/cli/master_bouncer.rb +6 -6
  17. data/lib/gergich/cli.rb +1 -1
  18. data/lib/gergich.rb +21 -25
  19. metadata +38 -29
  20. data/LICENSE +0 -20
  21. data/README.md +0 -178
  22. data/bin/check_coverage +0 -8
  23. data/bin/run_tests.sh +0 -22
  24. data/spec/gergich/capture/androidlint_capture_spec.rb +0 -61
  25. data/spec/gergich/capture/brakeman_capture_spec.rb +0 -91
  26. data/spec/gergich/capture/custom_capture_spec.rb +0 -41
  27. data/spec/gergich/capture/eslint_capture_spec.rb +0 -31
  28. data/spec/gergich/capture/flake8_capture_spec.rb +0 -23
  29. data/spec/gergich/capture/i18nliner_capture_spec.rb +0 -25
  30. data/spec/gergich/capture/rubocop_capture_spec.rb +0 -75
  31. data/spec/gergich/capture/shellcheck_capture_spec.rb +0 -83
  32. data/spec/gergich/capture/stylelint_capture_spec.rb +0 -54
  33. data/spec/gergich/capture/swiftlint_capture_spec.rb +0 -42
  34. data/spec/gergich/capture/yamllint_capture_spec.rb +0 -31
  35. data/spec/gergich/capture_spec.rb +0 -75
  36. data/spec/gergich_spec.rb +0 -396
  37. data/spec/spec_helper.rb +0 -92
  38. data/spec/support/capture_shared_examples.rb +0 -19
data/README.md DELETED
@@ -1,178 +0,0 @@
1
- # Gergich
2
-
3
- [![Gem Version](https://badge.fury.io/rb/gergich.svg)](https://rubygems.org/gems/gergich)
4
- [![Build Status](https://travis-ci.org/instructure/gergich.svg?branch=master)](https://travis-ci.org/instructure/gergich)
5
-
6
- Gergich is a command-line tool (and ruby lib) for easily posting comments
7
- on a [Gerrit](https://www.gerritcodereview.com/) review from a CI
8
- environment. It can be wired up to linters (rubocop, eslint, etc.) so that
9
- you can get nice inline comments right on the Gerrit review. That way
10
- developers don't have to go digging through CI logs to see why their
11
- builds failed.
12
-
13
- ## How does it work?
14
-
15
- Gergich maintains a little sqlite db of any draft comments/labels/etc.
16
- for the current patchset (defined by revision+ChangeId). This way
17
- different processes can all contribute to the review. For example,
18
- various linters add inline comments, and when the CI build finishes,
19
- Gergich publishes the review to Gerrit.
20
-
21
- ## Limitations
22
-
23
- Because everything is synchronized/stored in a local sqlite db, you
24
- should only call Gergich from a single box/build per patchset unless you
25
- have a unique `GERGICH_COMMENT_PREFIX` set for each box/build per patchset.
26
- Gergich does a check when publishing to ensure he hasn't already posted on
27
- this patchset before (w/ the same `GERGICH_COMMENT_PREFIX`); if he has,
28
- publish will be a no-op. This protects against reposts (say, on a retrigger),
29
- but it does mean that you shouldn't have completely different builds posting
30
- Gergich comments on the same revision, unless you set up different
31
- credentials for each.
32
-
33
- ## Installation
34
-
35
- Add the following to your Gemfile (perhaps in your `:test` group?):
36
-
37
- ```ruby
38
- gem "gergich"
39
- ```
40
-
41
- To use Gergich, you'll need a Gerrit user whose credentials it'll use
42
- (ideally not your own). With your shiny new username and password in hand,
43
- set `GERGICH_USER` and `GERGICH_KEY` accordingly in your CI environment.
44
-
45
- Additionally, Gergich needs to know where your Gerrit installation
46
- lives, so be sure to set `GERRIT_BASE_URL` (e.g.
47
- `https://gerrit.example.com`) or `GERRIT_HOST` (e.g. `gerrit.example.com`).
48
-
49
- Lastly, if you have no .git directory in CI land (say if you are building
50
- in docker and want to keep your images small), you also need to set
51
- `GERRIT_CHANGE_ID` and `GERRIT_PATCHSET_REVISION`. If you use Jenkins and
52
- the gerrit-trigger plugin, typcially all `GERRIT_*` vars will already be
53
- set, it's just a matter of plumbing them down to docker.
54
-
55
- ## Usage
56
-
57
- Run `gergich help` for detailed information about all supported commands.
58
- In your build scripts, you'll typically be using `gergich comment`,
59
- `gergich capture` and `gergich publish`. Comments are stored locally in a
60
- sqlite database until you publish. This way you can queue up comments from
61
- many disparate processes. Comments are published to `HEAD`'s corresponding
62
- patchset in Gerrit (based on Change-Id + `<sha>`)
63
-
64
- ### `gergich comment <comment_data>`
65
-
66
- `<comment_data>` is a JSON object (or array of objects). Each comment
67
- object should have the following properties:
68
-
69
- * **path** - the relative file path, e.g. "app/models/user.rb"
70
- * **position** - either a number (line) or an object (range). If an object,
71
- must have the following numeric properties:
72
- * start_line
73
- * start_character
74
- * end_line
75
- * end_character
76
- * **message** - the text of the comment
77
- * **severity** - `"info"|"warn"|"error"` - this will automatically prefix
78
- the comment (e.g. `"[ERROR] message here"`), and the most severe comment
79
- will be used to determine the overall `Code-Review` score (0, -1, or -2
80
- respectively)
81
-
82
- Note that a cover message and `Code-Review` score will be inferred from the
83
- most severe comment.
84
-
85
- #### Examples
86
-
87
- ```bash
88
- gergich comment '{"path":"foo.rb","position":3,"severity":"error",
89
- "message":"ಠ_ಠ"}'
90
- gergich comment '{"path":"bar.rb","severity":"warn",
91
- "position":{"start_line":3,"start_character":5,...},
92
- "message":"¯\_(ツ)_/¯"}'
93
- gergich comment '[{"path":"baz.rb",...}, {...}, {...}]'
94
- ```
95
-
96
- ### `gergich capture <format> <command>`
97
-
98
- For common linting formats, `gergich capture` can be used to automatically
99
- do `gergich comment` calls so you don't have to wire it up yourself.
100
-
101
- `<format>` - One of the following:
102
-
103
- * `brakeman`
104
- * `rubocop`
105
- * `eslint`
106
- * `i18nliner`
107
- * `flake8`
108
- * `stylelint`
109
- * `yamllint`
110
- * `shellcheck` - shellcheck json output
111
- * `custom:<path>:<class_name>` - file path and ruby class_name of a custom
112
- formatter.
113
-
114
- `<command>` - The command to run whose output conforms to `<format>`.
115
- Output from the command will still go to STDOUT, and Gergich will
116
- preserve its exit status. If command is "-", Gergich will simply read
117
- from STDIN and the exit status will always be 0.
118
-
119
- #### Custom formatters:
120
-
121
- To create a custom formatter, create a class that implements a `run`
122
- method that takes a string of command output and returns an array of
123
- comment hashes (see `gergich comment`'s `<comment_data>` format), e.g.
124
-
125
- ```ruby
126
- class MyFormatter
127
- def run(output)
128
- output.scan(/^Oh noes! (.+?):(\d+): (.*)$/).map do |file, line, error|
129
- { path: file, message: error, position: line.to_i, severity: "error" }
130
- end
131
- end
132
- end
133
- ```
134
-
135
- #### Examples:
136
-
137
- ```bash
138
- gergich capture rubocop "bundle exec rubocop"
139
-
140
- gergich capture eslint eslint
141
-
142
- gergich capture i18nliner "rake i18nliner:check"
143
-
144
- gergich capture shellcheck "shellcheck --format json build.sh"
145
-
146
- gergich capture custom:./gergich/xss:Gergich::XSS "node script/xsslint"
147
-
148
- docker-compose run --rm web eslint | gergich capture eslint -
149
- # you might be interested in $PIPESTATUS[0]
150
- ```
151
-
152
- ### `gergich publish`
153
-
154
- Publish all draft comments/labels/messages for this patchset. no-op if
155
- there are none.
156
-
157
- The cover message and `Code-Review` label (e.g. -2) are inferred from the
158
- comments, but labels and messages may be manually set (via `gergich
159
- message` and `gergich labels`)
160
-
161
- ## How do I test my changes?
162
-
163
- Write tests of course, but also be sure to test it end-to-end via the
164
- CLI... Run `gergich` for a list of commands, as well as help for each
165
- command. There's also a `citest` thing that we run on our Jenkins that
166
- ensures each CLI command succeeds, but it doesn't test all branches for
167
- each command.
168
-
169
- After running a given command, you can run `gergich status` to see the
170
- current draft of the review (what will be sent to Gerrit when you do
171
- `gergich publish`).
172
-
173
- You can even do a test `publish` to Gerrit, if you have valid Gerrit
174
- credentials in `GERGICH_USER` / `GERGICH_KEY`. It infers the Gerrit patchset
175
- from the working directory, which may or may not correspond to something
176
- actually in Gerrit, so YMMV. That means you can post to a Gergich commit
177
- in Gerrit, or if you run it from another project's directory, you can post
178
- to its Gerrit revision.
data/bin/check_coverage DELETED
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require "simplecov"
5
-
6
- SimpleCov.command_name "check_coverage"
7
- SimpleCov.minimum_coverage 85
8
- SimpleCov.at_exit { SimpleCov.result.format! }
data/bin/run_tests.sh DELETED
@@ -1,22 +0,0 @@
1
- #!/bin/bash
2
-
3
- set -e
4
-
5
- bundle exec rubocop --fail-level autocorrect
6
-
7
- ruby -v | egrep "^ruby 2\.4" && export COVERAGE=1
8
-
9
- bundle exec rspec
10
-
11
- # these actually hit gerrit; only run them in CI land (you can do it
12
- # locally if you set all the docker-compose env vars)
13
- if [[ "$GERRIT_PATCHSET_REVISION" ]]; then
14
- bundle exec bin/gergich citest
15
- bundle exec bin/master_bouncer check
16
- DRY_RUN=1 bundle exec bin/master_bouncer check_all
17
- # ensure gergich works without .git directories
18
- rm -rf .git
19
- bundle exec bin/gergich status
20
- fi
21
-
22
- bundle exec bin/check_coverage
@@ -1,61 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../../support/capture_shared_examples"
4
-
5
- RSpec.describe Gergich::Capture::AndroidlintCapture do
6
- # rubocop:disable Layout/LineLength
7
- let(:rtl_hardcoded) { 'Consider adding android:drawableStart="@drawable/a_media" to better support right-to-left layouts [RtlHardcoded]' }
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]" }
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]' }
10
- let(:unused_quantity) { 'For language "fr" (French) the following quantities are not relevant: few, zero [UnusedQuantity]' }
11
- # rubocop:enable Layout/LineLength
12
- let(:output) do
13
- <<~OUTPUT
14
- /path/to/some.xml:27: Warning: #{rtl_hardcoded}
15
- android:drawableLeft="@drawable/ic_cv_media"/>
16
- ~~~~~~~~~~~~~~~~~~~~
17
-
18
- /path/to/AndroidManifest.xml: Warning: #{rtl_enabled}
19
-
20
- /path/to/library/0.0.2: Error: #{lint_error}
21
-
22
- /path/to/values.xml:5: Warning: #{unused_quantity}
23
- <plurals name="number">
24
- ^
25
-
26
- OUTPUT
27
- end
28
-
29
- let(:comments) do
30
- [
31
- {
32
- path: "/path/to/some.xml",
33
- position: 27,
34
- # rubocop:disable Layout/LineLength
35
- message: "[androidlint] #{rtl_hardcoded}\n\n android:drawableLeft=\"@drawable/ic_cv_media\"/>\n ~~~~~~~~~~~~~~~~~~~~",
36
- # rubocop:enable Layout/LineLength
37
- severity: "warn"
38
- },
39
- {
40
- path: "/path/to/AndroidManifest.xml",
41
- position: 0,
42
- message: "[androidlint] #{rtl_enabled}",
43
- severity: "warn"
44
- },
45
- {
46
- path: "/path/to/library/0.0.2",
47
- position: 0,
48
- message: "[androidlint] #{lint_error}",
49
- severity: "error"
50
- },
51
- {
52
- path: "/path/to/values.xml",
53
- position: 5,
54
- message: "[androidlint] #{unused_quantity}\n\n <plurals name=\"number\">\n ^",
55
- severity: "warn"
56
- }
57
- ]
58
- end
59
-
60
- it_behaves_like "a captor"
61
- end
@@ -1,91 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../../support/capture_shared_examples"
4
-
5
- RSpec.describe Gergich::Capture::BrakemanCapture do
6
- let(:output) do
7
- File.read(
8
- File.expand_path(File.dirname(__FILE__) + "/brakeman_example.json")
9
- )
10
- end
11
-
12
- let(:comments) do
13
- [
14
- {
15
- path: "app/models/custom_data.rb",
16
- position: 36,
17
- message: <<~MESSAGE.strip,
18
- [brakeman] Attribute Restriction: attr_accessible is recommended over attr_protected
19
- See: http://brakemanscanner.org/docs/warning_types/attribute_restriction/
20
- MESSAGE
21
- severity: "warn"
22
- },
23
- {
24
- path: "app/models/submission_comment.rb",
25
- position: 0,
26
- message: <<~MESSAGE.strip,
27
- [brakeman] Mass Assignment: Potentially dangerous attribute available for mass assignment
28
- Code: :context_id
29
- See: http://brakemanscanner.org/docs/warning_types/mass_assignment/
30
- MESSAGE
31
- severity: "warn"
32
- },
33
- {
34
- path: "app/controllers/context_controller.rb",
35
- position: 60,
36
- message: <<~MESSAGE.strip,
37
- [brakeman] Redirect: Possible unprotected redirect
38
- Code: redirect_to(CanvasKaltura::ClientV3.new.assetSwfUrl(params[:id]))
39
- User Input: params[:id]
40
- See: http://brakemanscanner.org/docs/warning_types/redirect/
41
- MESSAGE
42
- severity: "warn"
43
- },
44
- {
45
- path: "app/views/context/object_snippet.html.erb",
46
- position: 6,
47
- message: <<~MESSAGE.strip,
48
- [brakeman] Cross Site Scripting: Unescaped parameter value
49
- Code: Base64.decode64((params[:object_data] or ""))
50
- User Input: params[:object_data]
51
- See: http://brakemanscanner.org/docs/warning_types/cross_site_scripting
52
- MESSAGE
53
- severity: "warn"
54
- },
55
- {
56
- path: "app/models/account.rb",
57
- position: 795,
58
- message: <<~MESSAGE.strip,
59
- [brakeman] SQL Injection: Possible SQL injection
60
- Code: Account.find_by_sql(Account.sub_account_ids_recursive_sql(parent_account_id))
61
- User Input: Account.sub_account_ids_recursive_sql(parent_account_id)
62
- See: http://brakemanscanner.org/docs/warning_types/sql_injection/
63
- MESSAGE
64
- severity: "error"
65
- },
66
- {
67
- path: "lib/cc/importer/blti_converter.rb",
68
- position: 145,
69
- message: <<~MESSAGE.strip,
70
- [brakeman] SSL Verification Bypass: SSL certificate verification was bypassed
71
- Code: Net::HTTP.new(URI.parse(url).host, URI.parse(url).port).verify_mode = OpenSSL::SSL::VERIFY_NONE
72
- See: http://brakemanscanner.org/docs/warning_types/ssl_verification_bypass/
73
- MESSAGE
74
- severity: "error"
75
- },
76
- {
77
- path: "lib/cc/importer/canvas/quiz_converter.rb",
78
- position: 44,
79
- message: <<~MESSAGE.strip,
80
- [brakeman] Command Injection: Possible command injection
81
- Code: `\#{Qti.get_conversion_command(File.join(qti_folder, "qti_2_1"), qti_folder)}`
82
- User Input: Qti.get_conversion_command(File.join(qti_folder, "qti_2_1"), qti_folder)
83
- See: http://brakemanscanner.org/docs/warning_types/command_injection/
84
- MESSAGE
85
- severity: "warn"
86
- }
87
- ]
88
- end
89
-
90
- it_behaves_like "a captor"
91
- end
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../../../lib/gergich/capture"
4
-
5
- RSpec.describe "CustomCaptor" do
6
- class CustomCaptor
7
- def run(output)
8
- output.scan(/^(.+?):(\d+): (.*)$/).map do |file, line, error|
9
- { path: file, message: error, position: line.to_i, severity: "error" }
10
- end
11
- end
12
- end
13
-
14
- let(:described_class) { CustomCaptor }
15
- let(:capture_format) { "custom:sqlite3:CustomCaptor" }
16
- let(:output) do
17
- <<~OUTPUT
18
- foo.rb:1: you done screwed up
19
- OUTPUT
20
- end
21
- let(:comments) do
22
- [
23
- {
24
- path: "foo.rb",
25
- position: 1,
26
- message: "you done screwed up",
27
- severity: "error"
28
- }
29
- ]
30
- end
31
-
32
- it "loads" do
33
- captor = Gergich::Capture.load_captor(capture_format)
34
- expect(captor).to eq(described_class)
35
- end
36
-
37
- it "catches errors" do
38
- comments = subject.run(output)
39
- expect(comments).to match_array(comments)
40
- end
41
- end
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../../support/capture_shared_examples"
4
-
5
- RSpec.describe Gergich::Capture::EslintCapture do
6
- let(:output) do
7
- <<~OUTPUT
8
- jsapp/models/user.js
9
- 4:21 error Missing semicolon semi
10
- 5:1 warning Too much cowbell cowbell-overload
11
- OUTPUT
12
- end
13
- let(:comments) do
14
- [
15
- {
16
- path: "jsapp/models/user.js",
17
- position: 4,
18
- message: "[eslint] Missing semicolon",
19
- severity: "error"
20
- },
21
- {
22
- path: "jsapp/models/user.js",
23
- position: 5,
24
- message: "[eslint] Too much cowbell",
25
- severity: "warn"
26
- }
27
- ]
28
- end
29
-
30
- it_behaves_like "a captor"
31
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../../support/capture_shared_examples"
4
-
5
- RSpec.describe Gergich::Capture::Flake8Capture do
6
- let(:output) do
7
- <<~OUTPUT
8
- ./djangogeneric/settings/base.py:73:80: E501 line too long (81 > 79 characters)
9
- OUTPUT
10
- end
11
- let(:comments) do
12
- [
13
- {
14
- path: "./djangogeneric/settings/base.py",
15
- position: 73,
16
- message: "[flake8] E501 line too long (81 > 79 characters)",
17
- severity: "error"
18
- }
19
- ]
20
- end
21
-
22
- it_behaves_like "a captor"
23
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../../support/capture_shared_examples"
4
-
5
- RSpec.describe Gergich::Capture::I18nlinerCapture do
6
- let(:output) do
7
- <<~OUTPUT
8
- 1)
9
- invalid signature on line 4: <unsupported expression>
10
- jsapp/models/user.js
11
- OUTPUT
12
- end
13
- let(:comments) do
14
- [
15
- {
16
- path: "jsapp/models/user.js",
17
- position: 4,
18
- message: "[i18n] invalid signature: <unsupported expression>",
19
- severity: "error"
20
- }
21
- ]
22
- end
23
-
24
- it_behaves_like "a captor"
25
- end
@@ -1,75 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../../support/capture_shared_examples"
4
-
5
- RSpec.describe Gergich::Capture::RubocopCapture do
6
- let(:output) do
7
- <<~OUTPUT
8
- Offenses:
9
-
10
- bin/gergich:47:8: C: Prefer double-quoted strings
11
- if ENV['DEBUG']
12
- ^^^^^^^
13
- foo/bar/baz.rb:1:2: W: no context for this one :shrug:
14
- lib/gergich.rb:10:9: E: this is a terrible name
15
-
16
- seriously, what were you thinking?
17
- def foo
18
- ^^^
19
- lib/gergich.rb:22:55: W: Line is too long. [55/54]
20
- def initialize(ref = "HEAD", revision_number = nil)
21
- ^^
22
-
23
- 1 file inspected, 35 offenses detected, 27 offenses auto-correctable
24
- OUTPUT
25
- end
26
- let(:comments) do
27
- [
28
- {
29
- path: "bin/gergich",
30
- position: 47,
31
- message: "[rubocop] Prefer double-quoted strings\n\n if ENV['DEBUG']\n ^^^^^^^\n",
32
- severity: "info"
33
- },
34
- {
35
- path: "foo/bar/baz.rb",
36
- position: 1,
37
- message: "[rubocop] no context for this one :shrug:\n",
38
- severity: "warn"
39
- },
40
- {
41
- path: "lib/gergich.rb",
42
- position: 10,
43
- message: <<~OUTPUT,
44
- [rubocop] this is a terrible name
45
-
46
- seriously, what were you thinking?
47
-
48
- def foo
49
- ^^^
50
- OUTPUT
51
- severity: "error"
52
- },
53
- {
54
- path: "lib/gergich.rb",
55
- position: 22,
56
- message: <<~OUTPUT,
57
- [rubocop] Line is too long. [55/54]
58
-
59
- def initialize(ref = "HEAD", revision_number = nil)
60
- ^^
61
- OUTPUT
62
- severity: "warn"
63
- }
64
- ]
65
- end
66
-
67
- it_behaves_like "a captor"
68
-
69
- it "raises an error if it couldn't run" do
70
- expect { subject.run(<<-OUTPUT) }.to raise_error(/RuboCop failed to run properly/)
71
- Could not find i18n-1.8.9 in any of the sources
72
- Run `bundle install` to install missing gems.
73
- OUTPUT
74
- end
75
- end
@@ -1,83 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../../support/capture_shared_examples"
4
-
5
- RSpec.describe Gergich::Capture::ShellcheckCapture do
6
- let(:output) do
7
- <<~'OUTPUT'
8
- [
9
- {
10
- "file": "bin/sync-translations.sh",
11
- "line": 23,
12
- "endLine": 23,
13
- "column": 21,
14
- "endColumn": 21,
15
- "level": "style",
16
- "code": 2006,
17
- "message": "Use $(..) instead of legacy `..`."
18
- },
19
- {
20
- "file": "bin/sync-translations.sh",
21
- "line": 23,
22
- "endLine": 23,
23
- "column": 43,
24
- "endColumn": 43,
25
- "level": "warning",
26
- "code": 2046,
27
- "message": "Quote this to prevent word splitting."
28
- },
29
- {
30
- "file": "bin/sync-translations.sh",
31
- "line": 32,
32
- "endLine": 32,
33
- "column": 62,
34
- "endColumn": 62,
35
- "level": "info",
36
- "code": 2086,
37
- "message": "Double quote to prevent globbing and word splitting."
38
- },
39
- {
40
- "file": "fail.sh",
41
- "line": 3,
42
- "endLine": 3,
43
- "column": 12,
44
- "endColumn": 12,
45
- "level": "error",
46
- "code": 1101,
47
- "message": "Delete trailing spaces after \\ to break line (or use quotes for literal space)."
48
- }
49
- ]
50
- OUTPUT
51
- end
52
-
53
- let(:comments) do
54
- [
55
- {
56
- path: "bin/sync-translations.sh",
57
- position: 23,
58
- message: "Use $(..) instead of legacy `..`.",
59
- severity: "info"
60
- },
61
- {
62
- path: "bin/sync-translations.sh",
63
- position: 23,
64
- message: "Quote this to prevent word splitting.",
65
- severity: "warn"
66
- },
67
- {
68
- path: "bin/sync-translations.sh",
69
- position: 32,
70
- message: "Double quote to prevent globbing and word splitting.",
71
- severity: "info"
72
- },
73
- {
74
- path: "fail.sh",
75
- position: 3,
76
- message: "Delete trailing spaces after \\ to break line (or use quotes for literal space).",
77
- severity: "error"
78
- }
79
- ]
80
- end
81
-
82
- it_behaves_like "a captor"
83
- end