guard-cookstyle 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4aa7c641c016b0f1678e8a9cb3e2c71894629d52
4
+ data.tar.gz: 241418cd7783dbff5556abe1112fca1cfaaf9535
5
+ SHA512:
6
+ metadata.gz: 50d6c01f906309a8a4f36d64c986cd9957be4c4a48c4eff4275505100fe93b138894ef389f2f05e6c00945078a86b45e8c5de18e9362552545ca916d2739f6d5
7
+ data.tar.gz: d3df5e6de2cf75e3ceb56055339f6b311934e394295f9d473e819fd870918527f226348e662fd0ca3db5558a4f4527ee2124fea47de1d5af9fa09f797b90a4f3
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # CHANGELOG
2
+
3
+ ## 0.1.0
4
+
5
+ - release
data/README.md ADDED
@@ -0,0 +1,95 @@
1
+ # Guard::Cookstyle
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/guard/cookstyle`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ guard-rubocop allows you to automatically check Chef cookbook style with [Cookstyle](https://github.com/chef/cookstyle) when files are modified.
6
+
7
+ Cookstyle is a wrapper of rubocop, so most of the codes were based on [yujinakayama/guard-rubocop]((https://github.com/yujinakayama/guard-rubocop)).
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'guard-cookstyle'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ ```
20
+ $ bundle
21
+ ```
22
+
23
+ Or install it yourself as:
24
+
25
+ ```
26
+ $ gem install guard-cookstyle
27
+ ```
28
+
29
+ Add the default Guard::Cookstyle definition to your Guardfile by running:
30
+
31
+ ```
32
+ $ guard init cookstyle
33
+ ```
34
+
35
+ Rules of Rubocop definition are loaded from `.cookstyle.yml` by default.
36
+
37
+ ## Usage
38
+
39
+ Please read the [Guard usage documentation](https://github.com/guard/guard#readme).
40
+
41
+ ## Options
42
+
43
+ You can pass some options in `Guardfile` like the following example:
44
+
45
+ ```ruby
46
+ guard :cookstyle, all_on_start: false, cli: ['--format', 'clang'], cookbook_dirs: ['mycookbooks'], rubocop_config: '.rubocop.yml' do
47
+ # ...
48
+ end
49
+ ```
50
+
51
+ ### Available Options
52
+
53
+ ```ruby
54
+ all_on_start: true # Check all files at Guard startup.
55
+ # default: true
56
+ cli: '--rails' # Pass arbitrary Cookstyle CLI arguments. (almost same of RuboCop)
57
+ # An array or string is acceptable.
58
+ # default: nil
59
+ hide_stdout: false # Do not display console output (in case outputting to file).
60
+ # default: false
61
+ keep_failed: true # Keep failed files until they pass.
62
+ # default: true
63
+ notification: :failed # Display Growl notification after each run.
64
+ # true - Always notify
65
+ # false - Never notify
66
+ # :failed - Notify only when failed
67
+ # default: :failed
68
+ launchy: nil # Filename to launch using Launchy after RuboCop runs.
69
+ # default: nil
70
+ cookbook_dirs: [] # Directory of Cookbooks to check.
71
+ # default: %w[cookbooks site-cookbooks]
72
+ rubocop_config: # Rubocop Config path.
73
+ # default: '.cookstyle.yml'
74
+ ```
75
+
76
+ ### Tips
77
+
78
+ In order to use it with Rubocop, we recommend that `.cookstyle.yml` inherits `.rubocop.yml` and add cookbook specific rules.
79
+
80
+ ```
81
+ ---
82
+ inherit_from: .rubocop.yml
83
+
84
+ ... rules for cookbooks
85
+
86
+ ```
87
+
88
+ ## Contributing
89
+
90
+ Bug reports and pull requests are welcome on GitHub at https://github.com/higanworks/guard-cookstyle.
91
+
92
+
93
+ ## License
94
+
95
+ Licensed under the Apache License, Version 2.0.
@@ -0,0 +1,28 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "guard/cookstyle/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "guard-cookstyle"
8
+ spec.version = GuardCookstyleVersion.to_s
9
+ spec.authors = ['sawanoboly']
10
+ spec.email = ['sawanoboriyu@higanworks.com']
11
+
12
+ spec.summary = 'Guard plugin for Cookstyle'
13
+ spec.description = 'Guard::Cookstyle automatically checks Ruby code style with Cookstyle when files are modified.'
14
+ spec.homepage = 'https://github.com/higanworks/guard-cookstyle'
15
+ spec.license = 'Apache-2.0'
16
+
17
+ spec.files = Dir['README.md','CHANGELOG.md','guard-cookstyle.gemspec','lib/**/*']
18
+ spec.bindir = "bin"
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(/^spec\//)
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_runtime_dependency 'guard'
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.16"
26
+ spec.add_development_dependency "rake", "~> 10.0"
27
+ spec.add_development_dependency "rspec", "~> 3.0"
28
+ end
@@ -0,0 +1,100 @@
1
+ require 'guard'
2
+ require 'guard/plugin'
3
+ require "guard/cookstyle/version"
4
+ require "guard/cookstyle/monkey_patch/listen"
5
+
6
+ module Guard
7
+ class Cookstyle < Plugin
8
+ autoload :Runner, 'guard/cookstyle/runner'
9
+
10
+ attr_reader :options, :failed_paths
11
+
12
+ def initialize(options = {})
13
+ super
14
+
15
+ @options = {
16
+ all_on_start: true,
17
+ keep_failed: true,
18
+ notification: :failed,
19
+ cli: nil,
20
+ hide_stdout: false,
21
+ cookbook_dirs: %w[cookbooks site-cookbooks],
22
+ rubocop_config: '.cookstyle.yml',
23
+ }.merge(options)
24
+
25
+ @failed_paths = []
26
+ end
27
+
28
+ def start
29
+ run_all if @options[:all_on_start]
30
+ end
31
+
32
+ def run_all
33
+ UI.info 'Inspecting Chef Cookbook style of all files'
34
+ inspect_with_cookstyle
35
+ end
36
+
37
+ def run_on_additions(paths)
38
+ run_partially(paths)
39
+ end
40
+
41
+ def run_on_modifications(paths)
42
+ run_partially(paths)
43
+ end
44
+
45
+ def reload
46
+ @failed_paths = []
47
+ end
48
+
49
+ private
50
+
51
+ def run_partially(paths)
52
+ paths += @failed_paths if @options[:keep_failed]
53
+ paths = clean_paths(paths)
54
+
55
+ return if paths.empty?
56
+
57
+ displayed_paths = paths.map { |path| smart_path(path) }
58
+ UI.info "Inspecting Chef Cookbook style: #{displayed_paths.join(' ')}"
59
+
60
+ inspect_with_cookstyle(paths)
61
+ end
62
+
63
+ def inspect_with_cookstyle(paths = [])
64
+ runner = Runner.new(@options)
65
+ passed = runner.run(paths)
66
+ @failed_paths = runner.failed_paths
67
+ throw :task_has_failed unless passed
68
+ rescue StandardError => error
69
+ UI.error 'The following exception occurred while running guard-cookstyle: ' \
70
+ "#{error.backtrace.first} #{error.message} (#{error.class.name})"
71
+ end
72
+
73
+ def clean_paths(paths)
74
+ paths = paths.dup
75
+ paths.map! { |path| File.expand_path(path) }
76
+ paths.uniq!
77
+ paths.reject! do |path|
78
+ next true unless File.exist?(path)
79
+ included_in_other_path?(path, paths)
80
+ end
81
+ paths
82
+ end
83
+
84
+ def included_in_other_path?(target_path, other_paths)
85
+ dir_paths = other_paths.select { |path| File.directory?(path) }
86
+ dir_paths.delete(target_path)
87
+ dir_paths.any? do |dir_path|
88
+ target_path.start_with?(dir_path)
89
+ end
90
+ end
91
+
92
+ def smart_path(path)
93
+ if path.start_with?(Dir.pwd)
94
+ Pathname.new(path).relative_path_from(Pathname.getwd).to_s
95
+ else
96
+ path
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,13 @@
1
+ # https://github.com/guard/listen/wiki/Duplicate-directory-errors
2
+ if Gem::Version.new(2.8) < Gem::Version.new(Listen::VERSION)
3
+ require 'listen/record/symlink_detector'
4
+ module Listen
5
+ class Record
6
+ class SymlinkDetector
7
+ def _fail(_, _)
8
+ fail Error, "Don't watch locally-symlinked directory twice"
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,145 @@
1
+ require 'json'
2
+
3
+ module Guard
4
+ class Cookstyle
5
+ # This class runs `cookstyle` command, retrieves result and notifies.
6
+ # An instance of this class is intended to invoke `cookstyle` only once in its lifetime.
7
+ class Runner
8
+ def initialize(options)
9
+ @options = options
10
+ end
11
+
12
+ def run(paths = [])
13
+ command = build_command(paths)
14
+ passed = system(*command)
15
+
16
+ case @options[:notification]
17
+ when :failed
18
+ notify(passed) unless passed
19
+ when true
20
+ notify(passed)
21
+ end
22
+
23
+ open_launchy_if_needed
24
+
25
+ passed
26
+ end
27
+
28
+ def build_command(paths)
29
+ command = ['cookstyle']
30
+
31
+ if should_add_default_formatter_for_console?
32
+ command.concat(%w[--format progress]) # Keep default formatter for console.
33
+ end
34
+
35
+ command.concat(['--config', @options[:rubocop_config]])
36
+ command.concat(['--format', 'json', '--out', json_file_path])
37
+ command << '--force-exclusion'
38
+ command.concat(args_specified_by_user)
39
+
40
+ if paths.any?
41
+ command.concat(paths)
42
+ else
43
+ command.concat(@options[:cookbook_dirs])
44
+ end
45
+ command
46
+ end
47
+
48
+ def should_add_default_formatter_for_console?
49
+ !@options[:hide_stdout] && !include_formatter_for_console?(args_specified_by_user)
50
+ end
51
+
52
+ def args_specified_by_user
53
+ @args_specified_by_user ||= begin
54
+ args = @options[:cli]
55
+ case args
56
+ when Array then args
57
+ when String then args.shellsplit
58
+ when NilClass then []
59
+ else raise ArgumentError, ':cli option must be either an array or string'
60
+ end
61
+ end
62
+ end
63
+
64
+ def include_formatter_for_console?(cli_args)
65
+ index = -1
66
+ formatter_args = cli_args.group_by do |arg|
67
+ index += 1 if arg == '--format' || arg.start_with?('-f')
68
+ index
69
+ end
70
+ formatter_args.delete(-1)
71
+
72
+ formatter_args.each_value.any? do |args|
73
+ args.none? { |a| a == '--out' || a.start_with?('-o') }
74
+ end
75
+ end
76
+
77
+ def json_file_path
78
+ @json_file_path ||= begin
79
+ # Just generate random tempfile path.
80
+ basename = self.class.name.downcase.gsub('::', '_')
81
+ tempfile = Tempfile.new(basename)
82
+ tempfile.close
83
+ tempfile.path
84
+ end
85
+ end
86
+
87
+ def result
88
+ @result ||= begin
89
+ File.open(json_file_path) do |file|
90
+ # Rubinius 2.0.0.rc1 does not support `JSON.load` with 3 args.
91
+ JSON.parse(file.read, symbolize_names: true)
92
+ end
93
+ end
94
+ end
95
+
96
+ def notify(passed)
97
+ image = passed ? :success : :failed
98
+ Notifier.notify(summary_text, title: 'Cookstyle results', image: image)
99
+ end
100
+
101
+ def summary_text
102
+ summary = result[:summary]
103
+
104
+ text = pluralize(summary[:inspected_file_count], 'file')
105
+ text << ' inspected, '
106
+
107
+ offense_count = summary[:offense_count] || summary[:offence_count]
108
+ text << pluralize(offense_count, 'offense', no_for_zero: true)
109
+ text << ' detected'
110
+ end
111
+
112
+ def failed_paths
113
+ failed_files = result[:files].reject do |file|
114
+ offenses = file[:offenses] || file[:offences]
115
+ offenses.empty?
116
+ end
117
+ failed_files.map do |file|
118
+ file[:path]
119
+ end
120
+ end
121
+
122
+ def pluralize(number, thing, options = {})
123
+ text = ''
124
+
125
+ if number.zero? && options[:no_for_zero]
126
+ text = 'no'
127
+ else
128
+ text << number.to_s
129
+ end
130
+
131
+ text << " #{thing}"
132
+ text << 's' unless number == 1
133
+
134
+ text
135
+ end
136
+
137
+ def open_launchy_if_needed
138
+ return unless (output_path = @options[:launchy])
139
+ return unless File.exist?(output_path)
140
+ require 'launchy'
141
+ ::Launchy.open(output_path)
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,6 @@
1
+ group :cookbooks do
2
+ guard :cookstyle do
3
+ watch(/(cookbooks|site-cookbooks).+\.rb$/)
4
+ watch(%r{(?:.+/)?\.cookstyle(?:_todo)?\.yml$}) { |m| File.dirname(m[0]) }
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module GuardCookstyleVersion
2
+ def self.to_s
3
+ '0.1.0'
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: guard-cookstyle
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - sawanoboly
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-05-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: guard
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: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.16'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.16'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ description: Guard::Cookstyle automatically checks Ruby code style with Cookstyle
70
+ when files are modified.
71
+ email:
72
+ - sawanoboriyu@higanworks.com
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - CHANGELOG.md
78
+ - README.md
79
+ - guard-cookstyle.gemspec
80
+ - lib/guard/cookstyle.rb
81
+ - lib/guard/cookstyle/monkey_patch/listen.rb
82
+ - lib/guard/cookstyle/runner.rb
83
+ - lib/guard/cookstyle/templates/Guardfile
84
+ - lib/guard/cookstyle/version.rb
85
+ homepage: https://github.com/higanworks/guard-cookstyle
86
+ licenses:
87
+ - Apache-2.0
88
+ metadata: {}
89
+ post_install_message:
90
+ rdoc_options: []
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ requirements: []
104
+ rubyforge_project:
105
+ rubygems_version: 2.6.13
106
+ signing_key:
107
+ specification_version: 4
108
+ summary: Guard plugin for Cookstyle
109
+ test_files: []