chef-taste 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,14 @@
1
+ AllCops:
2
+ Excludes:
3
+ - vendor/**
4
+ - test/**
5
+ Documentation:
6
+ Enabled: false
7
+ SignalException:
8
+ EnforcedStyle: only_raise
9
+ Encoding:
10
+ Enabled: false
11
+ LineLength:
12
+ Max: 120
13
+ MethodLength:
14
+ Max: 20
@@ -0,0 +1,5 @@
1
+ rvm:
2
+ - 1.9.3
3
+ - 2.0.0
4
+ script:
5
+ - bundle exec rubocop
data/README.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Chef::Taste
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/chef-taste.png)](http://badge.fury.io/rb/chef-taste)
4
+ [![Build Status](https://travis-ci.org/arangamani/chef-taste.png?branch=master)](https://travis-ci.org/arangamani/chef-taste)
5
+ [![Dependency Status](https://gemnasium.com/arangamani/chef-taste.png)](https://gemnasium.com/arangamani/chef-taste)
6
+ [![Code Climate](https://codeclimate.com/github/arangamani/chef-taste.png)](https://codeclimate.com/github/arangamani/chef-taste)
7
+
3
8
  Chef Taste is a simple command line utility to check a cookbook's dependency status.
4
9
  It will list the dependent cookbooks in a tabular format with the version information,
5
10
  status, and the changelog (if possible) for out-of-date cookbooks.
@@ -40,7 +45,13 @@ finding the tags being used and the latest tag and displaying a compare view tha
40
45
  compares these two tags. This URL is then shortened using goo.gl URL shortener to fit the table.
41
46
 
42
47
  The details are obtained only for cookbooks available in the community site. Other cookbooks are
43
- displayed but will simply have `N/A` in their details.
48
+ displayed but will simply be empty in the details column.
49
+
50
+ ### Display Format
51
+
52
+ Two display formats are supported: table and json
53
+ 1. The table format will display the dependency status as an ASCII table
54
+ 2. The json format will display the dependency status as a JSON object
44
55
 
45
56
  ### Examples
46
57
 
@@ -57,7 +68,7 @@ kannanmanickam@mac fried_rice$ taste
57
68
  | ntp | ~> 1.4.0 | 1.4.0 | 1.5.0 | ✖ | http://goo.gl/qsfgwA |
58
69
  | swap | = 0.3.5 | 0.3.5 | 0.3.6 | ✖ | http://goo.gl/vZtUQJ |
59
70
  | windows | >= 0.0.0 | 1.11.0 | 1.11.0 | ✔ | |
60
- | awesome_cb | >= 0.0.0 | N/A | N/A | N/A | |
71
+ | awesome_cb | >= 0.0.0 | | | | |
61
72
  +------------+-------------+--------+--------+--------+----------------------+
62
73
  Status: out-of-date ( ✖ )
63
74
  ```
@@ -65,21 +76,36 @@ Status: out-of-date ( ✖ )
65
76
  #### 2. noodles cookbook
66
77
 
67
78
  ```bash
68
- kannanmanickam@mac noodles$ taste
69
- +---------+-------------+--------+--------+--------+----------------------+
70
- | Name | Requirement | Used | Latest | Status | Changelog |
71
- +---------+-------------+--------+--------+--------+----------------------+
72
- | mysql | ~> 3.0.12 | 3.0.12 | 3.0.12 | ✔ | |
73
- | apache2 | ~> 1.7.0 | 1.7.0 | 1.8.4 | ✖ | http://goo.gl/9ejcpi |
74
- | windows | >= 0.0.0 | 1.11.0 | 1.11.0 | ✔ | |
75
- +---------+-------------+--------+--------+--------+----------------------+
76
- Status: out-of-date ( ✖ )
79
+ kannanmanickam@mac noodles$ taste --format json
80
+ {
81
+ "mysql": {
82
+ "requirement": "~> 3.0.12",
83
+ "used": "3.0.12",
84
+ "latest": "4.0.4",
85
+ "status": "out-of-date",
86
+ "changelog": "http://goo.gl/e1nBfW"
87
+ },
88
+ "apache2": {
89
+ "requirement": "~> 1.7.0",
90
+ "used": "1.7.0",
91
+ "latest": "1.8.4",
92
+ "status": "out-of-date",
93
+ "changelog": "http://goo.gl/9ejcpi"
94
+ },
95
+ "windows": {
96
+ "requirement": ">= 0.0.0",
97
+ "used": "1.11.0",
98
+ "latest": "1.11.0",
99
+ "status": "up-to-date",
100
+ "changelog": null
101
+ }
102
+ }
77
103
  ```
78
104
 
79
105
  #### 3. curry cookbook
80
106
 
81
107
  ```bash
82
- kannanmanickam@mac curry$ taste
108
+ kannanmanickam@mac curry$ taste --format table
83
109
  +-----------------+-------------+-------+--------+--------+-----------+
84
110
  | Name | Requirement | Used | Latest | Status | Changelog |
85
111
  +-----------------+-------------+-------+--------+--------+-----------+
data/bin/taste CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
- $:.push File.expand_path("../../lib", __FILE__)
2
+ $LOAD_PATH.push File.expand_path('../../lib', __FILE__)
3
3
  require 'chef/taste'
4
4
 
5
5
  Chef::Taste::Cli.start
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rubocop", "~> 0.14"
22
23
  spec.add_development_dependency "rake"
23
24
 
24
25
  spec.add_dependency "solve", "~> 0.8.0"
@@ -27,5 +28,5 @@ Gem::Specification.new do |spec|
27
28
  spec.add_dependency "terminal-table", "~> 1.4.5"
28
29
  spec.add_dependency "googl", "~> 0.6.3"
29
30
  spec.add_dependency "octokit", "~> 2.5.0"
30
- spec.add_dependency "colorize", "~> 0.5.8"
31
+ spec.add_dependency "colorize", "~> 0.6.0"
31
32
  end
@@ -39,9 +39,11 @@ module Chef
39
39
  # @return [String] the goo.gl shortened URL for the changelog
40
40
  #
41
41
  def compute(dep)
42
+ # The source url is of the form https://HOSTING_PROVIDER/USER/REPO
43
+ matched = dep.source_url.match(%r(^(https?:\/\/)?(.*?)\/(.*?)\/(.*?)$))
42
44
  changelog_url =
43
- if dep.source_url =~ /^(https?:\/\/)?github.com\/(.*)\/(.*)$/
44
- GithubChangelog.new("#{$2}/#{$3}", dep.version_used, dep.latest).compute
45
+ if matched[2] == 'github.com'
46
+ GithubChangelog.new("#{matched[3]}/#{matched[4]}", dep.version_used, dep.latest).compute
45
47
  else
46
48
  nil
47
49
  end
@@ -85,8 +87,8 @@ module Chef
85
87
  to_tag = nil
86
88
  tags.each do |tag|
87
89
  tag_name = tag.name
88
- from_tag = tag_name if tag_name =~ /v?#{from_version}/
89
- to_tag = tag_name if tag_name =~ /v?#{to_version}/
90
+ from_tag = tag_name if tag_name =~ /^v?#{from_version}$/
91
+ to_tag = tag_name if tag_name =~ /^v?#{to_version}$/
90
92
  end
91
93
  compare_url(from_tag, to_tag) if from_tag && to_tag
92
94
  end
@@ -33,13 +33,24 @@ module Chef
33
33
  # The default task
34
34
  default_task :check
35
35
 
36
+ method_option :format, type: :string,
37
+ desc: 'The format to use for display',
38
+ enum: %w(table json),
39
+ default: 'table',
40
+ aliases: '-t'
36
41
  desc 'check', 'Check status of dependent cookbooks'
37
42
  # The check command
38
43
  def check
39
44
  dependencies = DependencyChecker.check
40
- Display.print(dependencies)
45
+ if dependencies.empty?
46
+ puts 'No dependent cookbooks'.yellow
47
+ else
48
+ Display.print(dependencies, options[:format])
49
+ end
41
50
  rescue NotACookbookError
42
- puts "The path is not a cookbook path".red
51
+ puts 'The path is not a cookbook path'.red
52
+ rescue UnsupportedDisplayFormatError
53
+ puts 'The display format is not supported'.red
43
54
  end
44
55
  end
45
56
  end
@@ -61,12 +61,26 @@ module Chef
61
61
  def initialize(name, requirement)
62
62
  @name = name
63
63
  @requirement = requirement
64
- @version_used = 'N/A'
65
- @latest = 'N/A'
66
- @status = 'N/A'
64
+ @version_used = nil
65
+ @latest = nil
66
+ @status = nil
67
67
  @source_url = nil
68
68
  @changelog = nil
69
69
  end
70
+
71
+ # Converts the dependency option to a hash
72
+ #
73
+ # @return [Hash] the hash representation of the dependency object
74
+ #
75
+ def to_hash
76
+ {}.tap do |hash|
77
+ hash[:requirement] = requirement
78
+ hash[:used] = version_used
79
+ hash[:latest] = latest
80
+ hash[:status] = status
81
+ hash[:changelog] = changelog
82
+ end
83
+ end
70
84
  end
71
85
  end
72
86
  end
@@ -40,7 +40,7 @@ module Chef
40
40
  # @raise NotACookbook the current/given path is not a cookbook
41
41
  #
42
42
  def check(path = Dir.pwd)
43
- raise NotACookbookError, "Path is not a cookbook" unless File.exists?(File.join(path, 'metadata.rb'))
43
+ raise NotACookbookError, 'Path is not a cookbook' unless File.exists?(File.join(path, 'metadata.rb'))
44
44
  ridley = Ridley::Chef::Cookbook::Metadata.from_file(File.join(path, 'metadata.rb'))
45
45
  dependencies =
46
46
  ridley.dependencies.map do |name, version|
@@ -57,24 +57,35 @@ module Chef
57
57
  #
58
58
  def populate_fields(dependencies)
59
59
  rest = Berkshelf::CommunityREST.new
60
- dependencies.each do |dep|
60
+ dependencies.each do |dependency|
61
61
  # Skip cookbooks that are not available in the community site. It might be an external cookbook.
62
- #
63
- next unless cookbook_exists?(dep.name)
62
+ next unless cookbook_exists?(dependency.name)
63
+
64
+ dependency.latest = rest.latest_version(dependency.name)
64
65
 
65
- dep.latest = rest.latest_version(dep.name)
66
66
  # Obtain the version used based on the version constraint
67
- #
68
- dep.version_used = rest.satisfy(dep.name, dep.requirement)
69
- dep.source_url = rest.get(dep.name).body['external_url']
67
+ dependency.version_used = rest.satisfy(dependency.name, dependency.requirement)
68
+ dependency.source_url = rest.get(dependency.name).body['external_url']
69
+
70
+ # Calculate the status and changelog based on the version being used and the latest version
71
+ update_status(dependency)
72
+ end
73
+ end
70
74
 
71
- # Calculate the status based on the version being used and the latest version
72
- #
73
- if Solve::Version.new(dep.version_used).eql?(Solve::Version.new(dep.latest))
74
- dep.status = TICK_MARK
75
+ # Updates the status of the dependency based on the version used and the latest version available in the
76
+ # community site. It also obtains the changelog of the dependency is out-of-date
77
+ #
78
+ # @param dependency [Dependency] the cookbook dependency
79
+ #
80
+ def update_status(dependency)
81
+ if dependency.version_used && dependency.latest
82
+ used_version = Solve::Version.new(dependency.version_used)
83
+ latest_version = Solve::Version.new(dependency.latest)
84
+ if used_version.eql?(latest_version)
85
+ dependency.status = 'up-to-date'
75
86
  else
76
- dep.status = X_MARK
77
- dep.changelog = Changelog.compute(dep)
87
+ dependency.status = 'out-of-date'
88
+ dependency.changelog = Changelog.compute(dependency)
78
89
  end
79
90
  end
80
91
  end
@@ -30,51 +30,99 @@ module Chef
30
30
  # Displays the status of the dependency cookbooks
31
31
  #
32
32
  class Display
33
+ class << self
34
+ # Prints the status of dependent cookbooks in specified format
35
+ #
36
+ # @param dependencies [Array<Dependency>] list of cookbook dependency objects
37
+ # @param format [String] the format used for display
38
+ #
39
+ def print(dependencies, format)
40
+ case format
41
+ when 'table'
42
+ TableDisplay.print(dependencies)
43
+ when'json'
44
+ JSONDisplay.print(dependencies)
45
+ else
46
+ raise UnsupportedDisplayFormatError, "Display format '#{format}' is not supported"
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ # Displays the cookbook dependency status in a table format
53
+ #
54
+ class TableDisplay
33
55
  class << self
34
56
  # Prints the status of dependent cookbooks as a table
35
57
  #
36
58
  # @param dependencies [Array<Dependency>] list of cookbook dependency objects
37
59
  #
38
60
  def print(dependencies)
39
- if dependencies.empty?
40
- puts "No dependent cookbooks"
41
- else
42
- rows = []
43
- headings = [
44
- 'Name',
45
- 'Requirement',
46
- 'Used',
47
- 'Latest',
48
- 'Status',
49
- 'Changelog'
61
+ rows = []
62
+ headings = %w(Name Requirement Used Latest Status Changelog)
63
+ dependencies.each do |dependency|
64
+ status_symbol, color = status_to_symbol_and_color(dependency.status)
65
+ rows << [
66
+ dependency.name,
67
+ dependency.requirement,
68
+ dependency.version_used,
69
+ dependency.latest,
70
+ { value: status_symbol.send(color), alignment: :center },
71
+ dependency.changelog
50
72
  ]
51
- dependencies.each do |dependency|
52
- color =
53
- if dependency.status == TICK_MARK
54
- 'green'
55
- elsif dependency.status == X_MARK
56
- 'red'
57
- else
58
- 'white'
59
- end
60
- rows << [
61
- dependency.name,
62
- dependency.requirement,
63
- dependency.version_used,
64
- dependency.latest,
65
- {:value => dependency.status.send(color), :alignment => :center},
66
- dependency.changelog
67
- ]
68
- end
73
+ end
74
+
75
+ # If any of the cookbook is out-of-date
76
+ table = Terminal::Table.new headings: headings, rows: rows
77
+ puts table
78
+ if dependencies.any? { |dep| dep.status == 'out-of-date' }
79
+ puts "Status: out-of-date ( #{X_MARK} )".red
80
+ else
81
+ puts "Status: up-to-date ( #{TICK_MARK} )".green
82
+ end
83
+ end
84
+
85
+ # Given the status of the cookbook, this method will convert it to the unicode symbol
86
+ # and color. The up-to-date cookbook will receive a green color TICK mark whereas
87
+ # the out-of-date cookbook will receive a red color 'X' mark.
88
+ #
89
+ # @param status [String] the status of the cookbook
90
+ #
91
+ # @return [String, String] status symbol and color
92
+ #
93
+ def status_to_symbol_and_color(status)
94
+ case status
95
+ when 'up-to-date'
96
+ return TICK_MARK, 'green'
97
+ when'out-of-date'
98
+ return X_MARK, 'red'
99
+ else
100
+ return '', 'white'
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ # Displays the cookbook dependency status in JSON format
107
+ #
108
+ class JSONDisplay
109
+ class << self
110
+ # Prints the status of dependent in JSON
111
+ #
112
+ # @param dependencies [Array<Dependency>] list of cookbook dependency objects
113
+ #
114
+ def print(dependencies)
115
+ puts JSON.pretty_generate(dependencies_hash(dependencies))
116
+ end
69
117
 
70
- # If any of the cookbook is out-of-date
71
- out_of_date = dependencies.any? { |dep| dep.status == X_MARK }
72
- table = Terminal::Table.new headings: headings, rows: rows
73
- puts table
74
- if out_of_date
75
- puts "Status: out-of-date ( #{X_MARK} )".red
76
- else
77
- puts "Status: up-to-date ( #{TICK_MARK} )".green
118
+ # Converts the dependency objects to JSON object
119
+ #
120
+ # @param dependencies [Array<Dependency>] list of cookbook dependency objects
121
+ #
122
+ def dependencies_hash(dependencies)
123
+ {}.tap do |hash|
124
+ dependencies.each do |dependency|
125
+ hash[dependency.name] = dependency.to_hash
78
126
  end
79
127
  end
80
128
  end
@@ -28,5 +28,9 @@ module Chef
28
28
  # The current/given path is not a cookbook
29
29
  #
30
30
  class NotACookbookError < StandardError; end
31
+
32
+ # The given display type is not supported
33
+ #
34
+ class UnsupportedDisplayFormatError < ArgumentError; end
31
35
  end
32
36
  end
@@ -30,6 +30,6 @@ module Chef
30
30
  #
31
31
  module Taste
32
32
  # The version string
33
- VERSION = "1.0.0"
33
+ VERSION = '1.1.0'
34
34
  end
35
35
  end
@@ -3,6 +3,6 @@
3
3
  # Recipe:: default
4
4
  #
5
5
  # Copyright (C) 2013 YOUR_NAME
6
- #
6
+ #
7
7
  # All rights reserved - Do Not Redistribute
8
8
  #
@@ -8,5 +8,6 @@ version '0.1.0'
8
8
 
9
9
  depends 'ntp', '~> 1.4.0'
10
10
  depends 'swap', '= 0.3.5'
11
+ depends 'marker', '~> 0.1.0'
11
12
  depends 'windows'
12
13
  depends 'awesome_cb'
@@ -3,6 +3,6 @@
3
3
  # Recipe:: default
4
4
  #
5
5
  # Copyright (C) 2013 YOUR_NAME
6
- #
6
+ #
7
7
  # All rights reserved - Do Not Redistribute
8
8
  #
@@ -3,6 +3,6 @@
3
3
  # Recipe:: default
4
4
  #
5
5
  # Copyright (C) 2013 YOUR_NAME
6
- #
6
+ #
7
7
  # All rights reserved - Do Not Redistribute
8
8
  #
@@ -5,4 +5,3 @@ license 'All rights reserved'
5
5
  description 'Installs/Configures water'
6
6
  long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
7
7
  version '0.1.0'
8
-
@@ -3,6 +3,6 @@
3
3
  # Recipe:: default
4
4
  #
5
5
  # Copyright (C) 2013 YOUR_NAME
6
- #
6
+ #
7
7
  # All rights reserved - Do Not Redistribute
8
8
  #
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chef-taste
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-10-27 00:00:00.000000000 Z
12
+ date: 2013-11-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -27,6 +27,22 @@ dependencies:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
29
  version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rubocop
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '0.14'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '0.14'
30
46
  - !ruby/object:Gem::Dependency
31
47
  name: rake
32
48
  requirement: !ruby/object:Gem::Requirement
@@ -146,7 +162,7 @@ dependencies:
146
162
  requirements:
147
163
  - - ~>
148
164
  - !ruby/object:Gem::Version
149
- version: 0.5.8
165
+ version: 0.6.0
150
166
  type: :runtime
151
167
  prerelease: false
152
168
  version_requirements: !ruby/object:Gem::Requirement
@@ -154,7 +170,7 @@ dependencies:
154
170
  requirements:
155
171
  - - ~>
156
172
  - !ruby/object:Gem::Version
157
- version: 0.5.8
173
+ version: 0.6.0
158
174
  description: This gem checks if updated versions of dependent cookbooks are available
159
175
  for the cookbook
160
176
  email:
@@ -165,6 +181,8 @@ extensions: []
165
181
  extra_rdoc_files: []
166
182
  files:
167
183
  - .gitignore
184
+ - .rubocop.yml
185
+ - .travis.yml
168
186
  - Gemfile
169
187
  - LICENSE.txt
170
188
  - README.md
@@ -237,12 +255,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
237
255
  - - ! '>='
238
256
  - !ruby/object:Gem::Version
239
257
  version: '0'
258
+ segments:
259
+ - 0
260
+ hash: -3889125353596550255
240
261
  required_rubygems_version: !ruby/object:Gem::Requirement
241
262
  none: false
242
263
  requirements:
243
264
  - - ! '>='
244
265
  - !ruby/object:Gem::Version
245
266
  version: '0'
267
+ segments:
268
+ - 0
269
+ hash: -3889125353596550255
246
270
  requirements: []
247
271
  rubyforge_project:
248
272
  rubygems_version: 1.8.23
@@ -294,4 +318,3 @@ test_files:
294
318
  - test/cookbooks/water/chefignore
295
319
  - test/cookbooks/water/metadata.rb
296
320
  - test/cookbooks/water/recipes/default.rb
297
- has_rdoc: