sanelint 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c8fefbe650839c23ff8e0882bc9bd94b2163b85f
4
+ data.tar.gz: 406a8a7f7f6d8480934e988688bf9c3f10970318
5
+ SHA512:
6
+ metadata.gz: 76833df22508fa6604776e3bcac8ab08bf3dbc320427b728eb8c2b6b946eb0bc73ddd4140441f7f44a8dcfe96c447abcd4a78ac7dae48762b7d598d6a9b411a8
7
+ data.tar.gz: 2526121d38891c5b57652d11f8e009ff4236ab45803db88fb90c25201d542ad3d72301815e3c7aa0ff69e120eaa60860632aa39f518708690f7f062a1ef6a2b7
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in sanelint.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Tymon Tobolski
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,32 @@
1
+ # Sanelint
2
+
3
+ Code lint utility with sane configuration
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ gem install sanelint
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ Go to project directory and nd then execute:
14
+
15
+ ```bash
16
+ sanelint
17
+ ```
18
+
19
+ ## About
20
+
21
+ sanelint make use of two well known projects:
22
+
23
+ - [rails_best_practices](https://github.com/railsbp/rails_best_practices)
24
+ - [brakeman](https://github.com/presidentbeef/brakeman)
25
+
26
+ ## Contributing
27
+
28
+ 1. Fork it ( http://github.com/monterail/sanelint/fork )
29
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
30
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
31
+ 4. Push to the branch (`git push origin my-new-feature`)
32
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/sanelint ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
4
+ require "sanelint"
5
+ Sanelint.run!
@@ -0,0 +1,13 @@
1
+ <%=
2
+ @errors.map do |error|
3
+ {
4
+ :level => "warning",
5
+ :file => error.short_filename,
6
+ :line => error.line_number,
7
+ :message => error.message,
8
+ :link => error.url,
9
+ :git_commit => error.git_commit,
10
+ :git_username => error.git_username
11
+ }
12
+ end.to_json
13
+ %>
@@ -0,0 +1,66 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title><%= File.basename(root) %> Sanelint Report</title>
5
+ <style type="text/css">
6
+ body {
7
+ font: 12px sans-serif;
8
+ }
9
+ .container { margin: 50px; }
10
+ table {
11
+ border-collapse: collapse;
12
+ }
13
+ th {
14
+ font-weight: bold;
15
+ }
16
+ td,th { padding: 5px; border: 1px solid #eee;}
17
+ pre {
18
+ overflow: scroll;
19
+ max-width: 300px
20
+ }
21
+ </style>
22
+ </head>
23
+ <body>
24
+ <div class="container">
25
+ <table class="table table-striped">
26
+ <tr>
27
+ <th>#</th>
28
+ <th>File</th>
29
+ <th>Error</th>
30
+ <th>Code</th>
31
+ <th>Commit</th>
32
+ </tr>
33
+ <% @entries.each_with_index do |entry, index| %>
34
+ <tr>
35
+ <td><%= index + 1 %></td>
36
+ <td><code><%= entry.file %>:<%= entry.line %></code></td>
37
+
38
+ <td>
39
+ <% if entry.link %>
40
+ <a href="<%= entry.link %>"><%= entry.message %></a>
41
+ <% else %>
42
+ <%= entry.message %>
43
+ <% end %>
44
+ </td>
45
+
46
+ <td>
47
+ <pre><%= entry.code %></pre>
48
+ </td>
49
+
50
+ <td>
51
+ <a href="http://github.com/<%= git_repo %>/commit/<%= entry.git_commit %>">
52
+ <%= entry.git_commit %>
53
+ </a>
54
+ <br>
55
+ <%= entry.git_username %>
56
+ <br>
57
+ <%= entry.git_date %>
58
+ </td>
59
+
60
+ </tr>
61
+ <% end %>
62
+ </table>
63
+ </div>
64
+
65
+ </body>
66
+ </html>
@@ -0,0 +1,3 @@
1
+ module Sanelint
2
+ VERSION = "0.1.0"
3
+ end
data/lib/sanelint.rb ADDED
@@ -0,0 +1,183 @@
1
+ require "sanelint/version"
2
+
3
+ require "tempfile"
4
+ module Sanelint
5
+ class Linter < Struct.new(:root)
6
+ def call
7
+ raise "Not Implemented"
8
+ end
9
+
10
+ def lint
11
+ call
12
+ end
13
+
14
+ def output
15
+ @output ||= JSON.parse(File.read(output_file))
16
+ end
17
+
18
+ def output_file
19
+ @output_file ||= Tempfile.new(["sanelint", ".json"]).path
20
+ end
21
+ end
22
+
23
+ class Entry < Struct.new(:level, :file, :line, :message, :code, :link,
24
+ :git_commit, :git_username, :git_date)
25
+
26
+ def initialize(attrs = {})
27
+ super()
28
+
29
+ attrs.each {|k,v| send("#{k}=", v) }
30
+ end
31
+ end
32
+ end
33
+
34
+
35
+ require "brakeman"
36
+ module Sanelint
37
+ class Brakeman < Linter
38
+ def call
39
+ ::Brakeman.run(options)
40
+
41
+ ["warnings", "errors"].inject([]) do |list, type|
42
+ entries = output[type].map do |e|
43
+ Entry.new(
44
+ :level => type,
45
+ :file => e["file"],
46
+ :line => e["line"],
47
+ :message => e["message"],
48
+ :code => e["code"],
49
+ :link => e["link"]
50
+ )
51
+ end
52
+
53
+ list + entries
54
+ end
55
+ end
56
+
57
+
58
+ def options
59
+ {
60
+ :app_path => root,
61
+ :print_report => true,
62
+ :interprocedural => true,
63
+ :summary_only => true,
64
+ :output_files => [output_file]
65
+ }
66
+ end
67
+ end
68
+ end
69
+
70
+
71
+ require "rails_best_practices"
72
+ module Sanelint
73
+ class RailsBestPractices < Linter
74
+ def call
75
+ analyzer = ::RailsBestPractices::Analyzer.new(root, options)
76
+ analyzer.analyze
77
+ analyzer.output
78
+
79
+ output.map {|e| Entry.new(e) }
80
+ end
81
+
82
+ def options
83
+ {
84
+ "with-git" => true,
85
+ "format" => "html",
86
+ "template" => results_template_path,
87
+ "output-file" => output_file
88
+ }
89
+ end
90
+
91
+ def results_template_path
92
+ File.expand_path("../sanelint/rails_best_practices/results.html.erb", __FILE__)
93
+ end
94
+ end
95
+ end
96
+
97
+
98
+
99
+ module Sanelint
100
+ class Runner < Struct.new(:root)
101
+ LINTERS = [
102
+ Sanelint::RailsBestPractices,
103
+ Sanelint::Brakeman
104
+ ]
105
+
106
+ def call
107
+ run_linters
108
+ fill_missing_info
109
+ print_report
110
+ save_report
111
+ end
112
+
113
+ def run_linters
114
+ @entries = LINTERS.inject([]) do |entries, linter_klazz|
115
+ linter = linter_klazz.new(root)
116
+ entries + linter.lint
117
+ end
118
+ end
119
+
120
+ def fill_missing_info
121
+ @entries.each do |entry|
122
+ if info = blame(entry.file, entry.line)
123
+ entry.git_commit = info[:commit]
124
+ entry.git_date = info[:date]
125
+ entry.git_username = info[:user]
126
+ entry.code = info[:code]
127
+ end
128
+ end
129
+ end
130
+
131
+ def blame(file, line)
132
+ line = line.to_s.split(',').first
133
+
134
+ # taken from rails_best_practices
135
+ info = `cd #{root} && git blame -L #{line},+1 #{file}`
136
+ if m = info.strip.match(/^\^?([0-9a-f]+)\s\((.+)\s+(\d{4}-\d{2}-\d{2}).+?\)(.+)$/)
137
+ {
138
+ :commit => m[1],
139
+ :user => m[2],
140
+ :date => m[3],
141
+ :code => m[4]
142
+ }
143
+ else
144
+ nil
145
+ end
146
+ end
147
+
148
+ def git_repo
149
+ @git_repo ||= `git remote -v`[/github\.com(?:\/|:)(.+\/.+).git/, 1]
150
+ end
151
+
152
+ def print_report
153
+ long_file = @entries.map {|e| e.file.size + e.line.to_s.size }.max
154
+
155
+ puts
156
+ @entries.each do |entry|
157
+ puts "%-8s %-15s %-#{long_file+2}s %-40s" % [
158
+ entry.git_commit,
159
+ entry.git_username,
160
+ "#{entry.file}:#{entry.line}",
161
+ entry.message
162
+ ]
163
+ end
164
+ puts
165
+ end
166
+
167
+ def save_report
168
+ renderer = ERB.new(report_template)
169
+ report = renderer.result(binding)
170
+ File.open(File.join(root, "sanelint.html"), "w") {|f| f.write report }
171
+ puts "Report saved to sanelint.html"
172
+ end
173
+
174
+ def report_template
175
+ File.read(File.expand_path("../sanelint/report.html.erb", __FILE__))
176
+ end
177
+ end
178
+
179
+ def self.run!
180
+ runner = Runner.new(Dir.pwd)
181
+ runner.call
182
+ end
183
+ end
data/sanelint.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'sanelint/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "sanelint"
8
+ spec.version = Sanelint::VERSION
9
+ spec.authors = ["Tymon Tobolski"]
10
+ spec.email = ["tymon.tobolski@monterail.com"]
11
+ spec.summary = %q{Sane Ruby/Rails linter.}
12
+ spec.description = %q{Ruby/Rails linter. Sane stuff only}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "rails_best_practices"
22
+ spec.add_dependency "brakeman"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.5"
25
+ spec.add_development_dependency "rake"
26
+ end
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sanelint
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Tymon Tobolski
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-05-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails_best_practices
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: brakeman
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.5'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.5'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Ruby/Rails linter. Sane stuff only
70
+ email:
71
+ - tymon.tobolski@monterail.com
72
+ executables:
73
+ - sanelint
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - .gitignore
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - bin/sanelint
83
+ - lib/sanelint.rb
84
+ - lib/sanelint/rails_best_practices/results.html.erb
85
+ - lib/sanelint/report.html.erb
86
+ - lib/sanelint/version.rb
87
+ - sanelint.gemspec
88
+ homepage: ''
89
+ licenses:
90
+ - MIT
91
+ metadata: {}
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - '>='
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubyforge_project:
108
+ rubygems_version: 2.1.11
109
+ signing_key:
110
+ specification_version: 4
111
+ summary: Sane Ruby/Rails linter.
112
+ test_files: []