Skip to content

Commit

Permalink
Add ShellCheck linter (#155)
Browse files Browse the repository at this point in the history
  • Loading branch information
Greg Lazarev authored and turino committed Dec 28, 2017
1 parent d50c53d commit c5dd200
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 0 deletions.
1 change: 1 addition & 0 deletions Aptfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
shellcheck
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ This service uses the following linters:
* [rubocop](https://github.com/bbatsov/rubocop) for Ruby
* [sass-lint](https://github.com/sasstools/sass-lint) for SASS
* [scss-lint](https://github.com/brigade/scss-lint) for SCSS
* [shellcheck](https://github.com/koalaman/shellcheck) for shell scripts
* [slim-lint](https://github.com/sds/slim-lint) for Slim
* [stylelint](https://github.com/stylelint/stylelint) for SCSS/CSS
* [tslint](https://github.com/palantir/tslint) for TypeScript
Expand Down
9 changes: 9 additions & 0 deletions bin/setup
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ mix compile
# Python setup
python -m pip install flake8

# ShellCheck setup
if [ "$(uname)" = "Darwin" ]; then
brew install shellcheck
else
sudo apt-add-repository "deb http://archive.ubuntu.com/ubuntu trusty-backports main restricted universe"
sudo apt-get update
sudo apt-get install shellcheck
fi

# Add binstubs to PATH via export PATH=".git/safe/../../bin:$PATH" in ~/.zshenv
mkdir -p .git/safe

Expand Down
1 change: 1 addition & 0 deletions jobs/linters_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
require "linters/rubocop/options"
require "linters/sass_lint/options"
require "linters/scss_lint/options"
require "linters/shellcheck/options"
require "linters/slim_lint/options"
require "linters/stylelint/options"
require "linters/tslint/options"
Expand Down
33 changes: 33 additions & 0 deletions lib/linters/shellcheck/options.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
require "linters/base/options"
require "linters/shellcheck/tokenizer"

module Linters
module Shellcheck
class Options < Linters::Base::Options
def command
"shellcheck #{command_options} #{filepath}"
end

def tokenizer
Tokenizer.new
end

def config_content; end

private

attr_reader :filepath, :raw_config_content

def command_options
excluded_rules = parsed_config["exclude"]
if excluded_rules
"-e #{excluded_rules.join(',')}"
end
end

def parsed_config
YAML.safe_load(config).to_h
end
end
end
end
31 changes: 31 additions & 0 deletions lib/linters/shellcheck/tokenizer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module Linters
module Shellcheck
class Tokenizer
VIOLATION_REGEX = /\A
\s*In\s
(?<file>.+)\sline\s
(?<line_number>\d+).*\^--\s
(?<code>\w+):\s
(?<message>.*)
\z/xm

def parse(text)
text.split("\n\n").map { |line| tokenize(line) }.compact
end

private

def tokenize(line)
matches = VIOLATION_REGEX.match(line)

if matches
line_number = matches[:line_number].to_i
{
line: line_number,
message: matches[:message].strip,
}
end
end
end
end
end
58 changes: 58 additions & 0 deletions spec/integrations/shellcheck_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
require "jobs/linters_job"

RSpec.describe LintersJob, "for ShellCheck" do
include LintersHelper

context "when file contains violations" do
it "reports violations" do
expect_violations_in_file(
config: "",
content: content,
filename: "foo/bar.sh",
linter_name: "shellcheck",
violations: [
{
line: 3,
message: "Double quote to prevent globbing and word splitting.",
},
{
line: 4,
message: "foo appears unused. Verify it or export it.",
},
],
)
end
end

context "when custom configuraton is provided" do
it "respects the custom configuration" do
config = <<~CONFIG
exclude:
- SC2086 # Double quote to prevent globbing and word splitting.
CONFIG

expect_violations_in_file(
config: config,
content: content,
filename: "foo/bar.sh",
linter_name: "shellcheck",
violations: [
{
line: 4,
message: "foo appears unused. Verify it or export it.",
},
],
)
end
end

def content
<<~SCRIPT
#!/bin/sh
hello_world () {
echo $1
foo=42
}
SCRIPT
end
end

0 comments on commit c5dd200

Please sign in to comment.