guard-cookstyle 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: 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: []