knife-github 0.0.3 → 0.0.6

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.
@@ -25,28 +25,14 @@ class Chef
25
25
 
26
26
  deps do
27
27
  require 'chef/knife/github_base'
28
-
29
28
  include Chef::Knife::GithubBase
29
+ require 'chef/knife/github_baselist'
30
+ include Chef::Knife::GithubBaseList
30
31
  end
31
32
 
32
33
  banner "knife github compare [COOKBOOK] (options)"
33
34
  category "github"
34
35
 
35
- option :fields,
36
- :long => "--fields 'NAME, NAME'",
37
- :description => "The fields to output, comma-separated"
38
-
39
- option :noheader,
40
- :long => "--noheader",
41
- :description => "Removes header from output",
42
- :boolean => true
43
-
44
- option :all,
45
- :short => "-a",
46
- :long => "--all",
47
- :description => "Get all cookbooks from github.",
48
- :boolean => true
49
-
50
36
  option :mismatch,
51
37
  :short => "-m",
52
38
  :long => "--mismatch",
@@ -54,7 +40,6 @@ class Chef
54
40
  :boolean => true
55
41
 
56
42
  def run
57
- # extend Chef::Mixin::ShellOut
58
43
  # validate base options from base module.
59
44
  validate_base_options
60
45
 
@@ -64,31 +49,31 @@ class Chef
64
49
  # Gather all repo information from github.
65
50
  get_all_repos = get_all_repos(@github_organizations.reverse)
66
51
 
52
+ # Get all chef cookbooks and versions.
53
+ cookbooks = rest.get_rest("/cookbooks?num_version=1")
67
54
 
68
- # Get all chef cookbooks and versions (hopefully chef does the error handeling).
69
- cb_and_ver = rest.get_rest("/cookbooks?num_version=1")
70
-
55
+ #Get the github link
56
+ git_link = get_repo_clone_link
71
57
 
72
58
  # Filter all repo information based on the tags that we can find
73
- all_repos = {}
74
- if config[:all]
75
- get_all_repos.each { |k,v|
76
- cookbook = k
77
- cb_and_ver[k].nil? || cb_and_ver[k]['versions'].nil? ? version = "" : version = cb_and_ver[k]['versions'][0]['version']
78
- ssh_url = v['ssh_url']
79
- gh_tag = v['latest_tag']
80
- all_repos[cookbook] = { 'name' => cookbook, 'latest_cb_tag' => version, 'ssh_url' => ssh_url, 'latest_gh_tag' => gh_tag }
81
- }
59
+ if config[:fields] || config[:fieldlist]
60
+ all_repos = get_all_repos
61
+ config[:fields] = "name" if config[:fields].nil? || config[:fields].empty?
82
62
  else
83
- cb_and_ver.each { |k,v|
84
- cookbook = k
85
- version = v['versions'][0]['version']
86
- get_all_repos[k].nil? || get_all_repos[k]['ssh_url'].nil? ? ssh_url = ui.color("ERROR: Cannot find cookbook!", :red) : ssh_url = get_all_repos[k]['ssh_url']
87
- get_all_repos[k].nil? || get_all_repos[k]['latest_tag'].nil? ? gh_tag = ui.color("ERROR: No tags!", :red) : gh_tag = get_all_repos[k]['latest_tag']
88
- all_repos[cookbook] = { 'name' => cookbook, 'latest_cb_tag' => version, 'ssh_url' => ssh_url, 'latest_gh_tag' => gh_tag }
89
- }
63
+ all_repos = {}
64
+ if config[:all]
65
+ get_all_repos.each { |k,v|
66
+ cookbooks[k].nil? || cookbooks[k]['versions'].nil? ? version = "" : version = cookbooks[k]['versions'][0]['version']
67
+ all_repos[k] = { 'name' => k, 'latest_cb_tag' => version, 'git_url' => v[git_link], 'latest_gh_tag' => v['latest_tag'] }
68
+ }
69
+ else
70
+ cookbooks.each { |k,v|
71
+ get_all_repos[k].nil? || get_all_repos[k][git_link].nil? ? gh_url = ui.color("ERROR: Cannot find cookbook!", :red) : gh_url = get_all_repos[k][git_link]
72
+ get_all_repos[k].nil? || get_all_repos[k]['latest_tag'].nil? ? gh_tag = ui.color("ERROR: No tags!", :red) : gh_tag = get_all_repos[k]['latest_tag']
73
+ all_repos[k] = { 'name' => k, 'latest_cb_tag' => v['versions'][0]['version'], 'git_url' => gh_url, 'latest_gh_tag' => gh_tag }
74
+ }
75
+ end
90
76
  end
91
-
92
77
 
93
78
  # Filter only on the cookbook name if its given on the command line
94
79
  @cookbook_name = name_args.first unless name_args.empty?
@@ -98,145 +83,15 @@ class Chef
98
83
  repos = all_repos
99
84
  end
100
85
 
86
+ columns = [ 'name,Name', 'latest_cb_tag,Tag', 'git_url,Link', 'latest_gh_tag,Tag' ]
87
+ match = [ 'latest_cb_tag', 'latest_gh_tag' ]
101
88
 
102
- # Displaying information based on the fields and repos
103
- if config[:fields]
104
- object_list = []
105
- config[:fields].split(',').each { |n| object_list << ui.color(("#{n}").strip, :bold) }
89
+ if repos.nil? || repos.empty?
90
+ Chef::Log.error("No repositories found.")
106
91
  else
107
- object_list = [
108
- ui.color('Cookbook', :bold),
109
- ui.color('Tag', :bold),
110
- ui.color('Github', :bold),
111
- ui.color('Tag', :bold)
112
- ]
113
- end
114
-
115
- columns = object_list.count
116
- object_list = [] if config[:noheader]
117
-
118
- repos.each do |k,r|
119
- if config[:fields]
120
- config[:fields].downcase.split(',').each { |n| object_list << ((r[("#{n}").strip]).to_s || 'n/a') }
121
- else
122
- next if config[:mismatch] && (r['latest_gh_tag'] == r['latest_cb_tag'])
123
- r['latest_gh_tag'] == r['latest_cb_tag'] ? color = :white : color = :yellow
124
- color = :white if config[:all]
125
-
126
- object_list << ui.color((r['name'] || 'n/a'), color)
127
- object_list << ui.color((r['latest_cb_tag'] || 'n/a'), color)
128
- object_list << ui.color((r['ssh_url'] || 'n/a'), color)
129
- object_list << ui.color((r['latest_gh_tag'] || 'n/a'), color)
130
- end
131
- end
132
-
133
- puts ui.list(object_list, :uneven_columns_across, columns)
134
-
135
- end
136
-
137
- def get_all_repos(orgs)
138
- # Parse every org and merge all into one hash
139
- repos = {}
140
- orgs.each do |org|
141
- get_repos(org).each { |repo| name = repo['name'] ; repos["#{name}"] = repo }
92
+ display_info(repos, columns, match)
142
93
  end
143
- repos
144
- end
145
-
146
-
147
94
 
148
- def get_repos(org)
149
- dns_name = get_dns_name(@github_url)
150
- file_cache = "#{ENV['HOME']}/.chef/.#{dns_name.downcase}_#{org.downcase}.cache"
151
- if File.exists?(file_cache)
152
- Chef::Log.debug("#{org} cache is created: " + (Time.now - File.ctime(file_cache)).to_i.to_s + " seconds ago.")
153
- if Time.now - File.ctime(file_cache) > @github_cache
154
- # update cache file
155
- create_cache_file(file_cache, org)
156
- end
157
- else
158
- create_cache_file(file_cache, org)
159
- end
160
- # use cache files
161
- JSON.parse(File.read(file_cache))
162
- end
163
-
164
- def create_cache_file(file_cache, org)
165
- Chef::Log.debug("Updating the cache file: #{file_cache}")
166
- result = get_repos_github(org)
167
- File.open(file_cache, 'w') { |file| file.write(JSON.pretty_generate(result)) }
168
- end
169
-
170
-
171
-
172
- def get_repos_github(org)
173
- # Get all repo's for the org from github
174
- arr = []
175
- page = 1
176
- url = @github_url + "/api/" + @github_api_version + "/orgs/" + org + "/repos"
177
- while true
178
- params = { 'page' => page }
179
- result = send_request(url, params)
180
- break if result.nil? || result.count < 1
181
- result.each { |key|
182
- if key['tags_url']
183
- tags = get_tags(key)
184
- key['tags'] = tags unless tags.nil? || tags.empty?
185
- key['latest_tag'] = tags.first['name'] unless tags.nil? || tags.empty?
186
- arr << key
187
- else
188
- arr << key
189
- end
190
- }
191
- page = page + 1
192
- end
193
- arr
194
- end
195
-
196
-
197
- def get_tags(repo)
198
- tags = send_request(repo['tags_url'])
199
- tags
200
- end
201
-
202
-
203
- def get_dns_name(url)
204
- url = url.downcase.gsub("http://","") if url.downcase.start_with?("http://")
205
- url = url.downcase.gsub("https://","") if url.downcase.start_with?("https://")
206
- url
207
- end
208
-
209
-
210
- def send_request(url, params = {})
211
- params['response'] = 'json'
212
-
213
- params_arr = []
214
- params.sort.each { |elem|
215
- params_arr << elem[0].to_s + '=' + CGI.escape(elem[1].to_s).gsub('+', '%20').gsub(' ','%20')
216
- }
217
- data = params_arr.join('&')
218
-
219
- if url.nil? || url.empty?
220
- puts "Error: Please specify a valid Github URL."
221
- exit 1
222
- end
223
-
224
- github_url = "#{url}?#{data}"
225
- # Chef::Log.debug("URL: #{github_url}")
226
-
227
- uri = URI.parse(github_url)
228
- req_body = Net::HTTP::Get.new(uri.request_uri)
229
- request = Chef::REST::RESTRequest.new("GET", uri, req_body, headers={})
230
-
231
- response = request.call
232
-
233
- if !response.is_a?(Net::HTTPOK) then
234
- puts "Error #{response.code}: #{response.message}"
235
- puts JSON.pretty_generate(JSON.parse(response.body))
236
- puts "URL: #{url}"
237
- exit 1
238
- end
239
- json = JSON.parse(response.body)
240
95
  end
241
96
 
242
97
  end
@@ -0,0 +1,335 @@
1
+ #
2
+ # Author:: Sander Botman (<sbotman@schubergphilis.com>)
3
+ # Copyright:: Copyright (c) 2013 Sander Botman.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ # ---------------------------------------------------------------------------- #
19
+ # Abstract
20
+ # ---------------------------------------------------------------------------- #
21
+ # This code is specific to our company workflow
22
+ # When a cookbook is released it is tagged to a specific version
23
+ # This version should match the cookbook version (from the metadata)
24
+ # This version is then pinned against specific environments
25
+ #
26
+ # This class expects you to have pushed all your changes to github
27
+ # It will then do the rest
28
+ #
29
+ # All modes presume you have used github download to download a cookbook or
30
+ # are creating a new cookbook
31
+ #
32
+ # There are two modes of operation
33
+ # Development (default)
34
+ #
35
+ # This will take a cookbook name
36
+ # Do some basic version checks (if the current cookbook is frozen) and
37
+ # upload it
38
+ #
39
+ # If the cookbook is frozen it will force you to choose a new version
40
+ # and update the metadata accordingly
41
+ #
42
+ # Final (-f)
43
+ #
44
+ # You will be forced to select a new version.
45
+ # You can choose via the options whether to increment the Major/minor or patch
46
+ # revision numbers
47
+ # The version will be tagged
48
+ # Uploaded to the Chef server and frozen
49
+ #
50
+ # Version numbers
51
+ #
52
+ # You can choose a specific version number by specifying it on the command
53
+ # line.
54
+ #
55
+ # If you do not specify a version, the version will be the version in your
56
+ # cookbook's metadata
57
+ #
58
+ # A warning is issued if the version is lower than the version in github
59
+ # ---------------------------------------------------------------------------- #
60
+ require 'chef/knife'
61
+
62
+ class Chef
63
+ class Knife
64
+
65
+ class GithubDeploy < Knife
66
+ deps do
67
+ require 'chef/knife/github_base'
68
+ include Chef::Knife::GithubBase
69
+ require 'chef/cookbook_loader'
70
+ require 'chef/cookbook_uploader'
71
+ end
72
+
73
+ banner "knife github deploy COOKBOOK [VERSION] (options)"
74
+ category "github"
75
+
76
+ option :final,
77
+ :short => "-f",
78
+ :long => "--final",
79
+ :description => "Bump version, make git tag and freeze",
80
+ :boolean => true,
81
+ :default => false
82
+
83
+ option :major,
84
+ :short => "-M",
85
+ :long => "--major",
86
+ :description => "In final mode, increase the major version ie. X.x.x",
87
+ :boolean => true,
88
+ :default => false
89
+
90
+ option :minor,
91
+ :short => "-m",
92
+ :long => "--minor",
93
+ :description => "In final mode, increase the minor version ie. x.X.x",
94
+ :boolean => true,
95
+ :default => false
96
+
97
+ option :patch,
98
+ :short => "-p",
99
+ :long => "--patch",
100
+ :description => "In final mode, increase the minor version ie. x.x.X (Default)",
101
+ :boolean => true,
102
+ :default => true
103
+
104
+ def run
105
+
106
+ # validate base options from base module.
107
+ validate_base_options
108
+
109
+ # Display information if debug mode is on.
110
+ display_debug_info
111
+
112
+ # Gather all repo information from github.
113
+ get_all_repos = get_all_repos(@github_organizations.reverse)
114
+
115
+ # Get all chef cookbooks and versions (hopefully chef does the error handeling).
116
+ cookbooks = rest.get_rest("/cookbooks?num_version=1")
117
+
118
+ @versions = []
119
+ cookbook_version = nil
120
+ @cookbook_name = name_args.first unless name_args.empty?
121
+ cookbook_version = name_args[1] unless name_args[1].nil?
122
+
123
+ if @cookbook_name
124
+ repo = get_all_repos.select { |k,v| v["name"] == @cookbook_name }
125
+ else
126
+ Chef::Log.error("Cookbook not in git. You must add it to git to use deploy")
127
+ exit 1
128
+ end
129
+
130
+ if repo.empty?
131
+ Chef::Log.error("Cookbook not in git. You must add it to git to use deploy")
132
+ exit 1
133
+ end
134
+
135
+ # is the cookbook in the cookbook_path?
136
+ if cookbook_path_valid?(@cookbook_name, false).nil?
137
+ Chef::Log.error("Cookbook is not in cookbook path")
138
+ ui.info("HINT: knife github download #{@cookbook_name}")
139
+ exit 1
140
+ end
141
+
142
+ # ----------------------------- #
143
+ # The version can come
144
+ # 1. From the command line
145
+ # 2. From the cookbook
146
+ # ----------------------------- #
147
+ if cookbook_version.nil?
148
+ cookbook_version = get_cookbook_version()
149
+ end
150
+ # Next check to see if the version in git is way ahead
151
+ if ! get_all_repos[@cookbook_name]['latest_tag'].nil?
152
+ cb1 = Mixlib::Versioning.parse(cookbook_version)
153
+ cb2 = Mixlib::Versioning.parse(get_all_repos[@cookbook_name]['latest_tag'])
154
+ if(cb2 > cb1)
155
+ ui.confirm "Version in github #{cb2} is greater than the version you want to deploy #{cb1} - Continue"
156
+ end
157
+ end
158
+
159
+ inChef = true
160
+ isFrozen = false
161
+ if (config[:major] || config[:minor])
162
+ config[:patch] = false
163
+ end
164
+
165
+ begin
166
+ isFrozen = rest.get_rest("cookbooks/#{@cookbook_name}/#{cookbook_version}").frozen_version?
167
+ rescue
168
+ ui.warn "#{@cookbook_name} is not yet in chef"
169
+ inChef = false
170
+ end
171
+
172
+
173
+ if config[:final]
174
+ ui.info "Using Final mode"
175
+
176
+ else
177
+ ui.info "Using Development mode"
178
+ end
179
+ ui.info "Cookbook is frozen" if isFrozen
180
+
181
+ # Might be first upload so need to catch that cookbook does not exist!
182
+ get_cookbook_chef_versions() unless ! inChef
183
+
184
+ if config[:final]
185
+ cookbook_version = up_version(cookbook_version)
186
+
187
+ if repo[@cookbook_name]['tags'].select { |k| k['name'] == cookbook_version }.empty?
188
+ ui.info("Cookbook #{cookbook_version} has no tag in Git")
189
+ ui.confirm("Shall I add a tag for you?")
190
+ set_cookbook_version(cookbook_version)
191
+ add_tag(cookbook_version)
192
+ else
193
+ checkout_tag(cookbook_version)
194
+ set_cookbook_version(cookbook_version)
195
+ end
196
+
197
+ do_commit(cookbook_version, true)
198
+ end
199
+
200
+ # In Dev mode the version of the cookbook does not need to change
201
+ # If however the cookbook is frozen, then the version has to change
202
+ if ! config[:final] && isFrozen
203
+ cookbook_version = up_version(cookbook_version)
204
+ set_cookbook_version(cookbook_version)
205
+ do_commit(cookbook_version, false)
206
+ end
207
+
208
+ # If we have gotten this far we can just upload the cookbook
209
+ cookbook_upload()
210
+
211
+ end
212
+
213
+ def up_version(version)
214
+ while true do
215
+ ui.info("Trying to deploy version #{version}")
216
+ if @versions.include?(version)
217
+ ui.info("Version #{version} is already in chef")
218
+ ui.confirm("Shall I bump the version (No to Cancel)")
219
+ version = choose_version(version)
220
+ else
221
+ break
222
+ end
223
+ end
224
+ version
225
+ end
226
+
227
+ def choose_version(version)
228
+ if version =~ /(\d+)\.(\d+)\.(\d+)/
229
+ major = $1
230
+ minor = $1
231
+ patch = $3
232
+ major = major.to_i + 1 if config[:major]
233
+ minor = minor.to_i + 1 if config[:minor]
234
+ patch = patch.to_i + 1 if config[:patch]
235
+ version = "#{major}.#{minor}.#{patch}"
236
+ Chef::Log.debug("New version is #{version}")
237
+ else
238
+ Chef::Log.error("Version is in a format I cannot auto auto-update")
239
+ exit 1
240
+ end
241
+ version
242
+ end
243
+
244
+ def cookbook_upload()
245
+ # Git meuk should not be uploaded use chefignore file instead
246
+ # FileUtils.remove_entry("#{@github_tmp}/git/#{@cookbook_name}/.git")
247
+ args = ['cookbook', 'upload', @cookbook_name ]
248
+ if config[:final]
249
+ args.push "--freeze"
250
+ end
251
+ upload = Chef::Knife::CookbookUpload.new(args)
252
+ #upload.config[:cookbook_path] = "#{@github_tmp}/git"
253
+ # plugin will throw its own errors
254
+ upload.run
255
+ end
256
+
257
+ def checkout_tag(version)
258
+ ui.info "Checking out tag #{version}"
259
+ cpath = get_cookbook_path(@cookbook_name)
260
+ Dir.chdir(cpath);
261
+ `git checkout -b #{version}`
262
+ if !$?.exitstatus == 0
263
+ ui.error("Failed to checkout branch #{version} of #{@cookbook_name}")
264
+ exit 1
265
+ end
266
+ end
267
+
268
+ def get_cookbook_chef_versions ()
269
+ cookbooks = rest.get_rest("/cookbooks/#{@cookbook_name}?num_version=all")
270
+ cookbooks[@cookbook_name]['versions'].each do |v|
271
+ @versions.push v['version']
272
+ end
273
+ end
274
+
275
+ # ---------------------------------------------------------------------- #
276
+ # Get the version number in the git version of the cookbook
277
+ # ---------------------------------------------------------------------- #
278
+ def get_cookbook_version()
279
+ version = nil
280
+ cpath = get_cookbook_path(@cookbook_name)
281
+ File.foreach("#{cpath}/metadata.rb") do |line|
282
+ if line =~ /version.*"(.*)"/i
283
+ version = $1
284
+ break
285
+ end
286
+ end
287
+ if version.nil?
288
+ Chef::Log.error("Cannot get the version for cookbook #{@cookbook_name}")
289
+ exit 1
290
+ end
291
+ version
292
+ end
293
+
294
+ def get_cookbook_path(cookbook)
295
+ return cookbook_path_valid?(cookbook, false)
296
+ end
297
+
298
+ def do_commit(version, push)
299
+ cpath = get_cookbook_path(@cookbook_name)
300
+ Dir.chdir("#{cpath}")
301
+ puts cpath
302
+ output = `git commit -a -m "Deploy #{version}" 2>&1`
303
+ if $?.exitstatus != 0
304
+ if output !~ /nothing to commit/
305
+ Chef::Log.error("Could not commit #{@cookbook_name}")
306
+ puts output
307
+ exit 1
308
+ end
309
+ end
310
+ if push
311
+ output = `git push --tags 2>&1`
312
+ if $?.exitstatus != 0
313
+ Chef::Log.error("Could not push tag for: #{@cookbook_name}")
314
+ exit 1
315
+ end
316
+ output = `git push 2>&1`
317
+ end
318
+ end
319
+
320
+
321
+ def set_cookbook_version(version)
322
+ return unless get_cookbook_version() != version
323
+ contents = ''
324
+ cpath = get_cookbook_path(@cookbook_name)
325
+ File.foreach("#{cpath}/metadata.rb") do |line|
326
+ line.gsub!(/(version[\t\s]+)(.*)/i,"\\1 \"#{version}\"\n")
327
+ contents = contents << line
328
+ end
329
+ File.open("#{cpath}/metadata.rb", 'w') {|f| f.write(contents) }
330
+ return true
331
+ end
332
+
333
+ end
334
+ end
335
+ end
@@ -0,0 +1,126 @@
1
+ #
2
+ # Author:: Sander Botman (<sbotman@schubergphilis.com>)
3
+ # Copyright:: Copyright (c) 2013 Sander Botman.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'chef/knife'
20
+
21
+ class Chef
22
+ class Knife
23
+
24
+ class GithubDiff < Knife
25
+
26
+ deps do
27
+ require 'chef/knife/github_base'
28
+
29
+ include Chef::Knife::GithubBase
30
+ end
31
+
32
+ banner "knife github diff COOKBOOK [version] (options)"
33
+ category "github"
34
+
35
+ option :all,
36
+ :short => "-a",
37
+ :long => "--all",
38
+ :description => "Diff all cookbooks from chef against github.",
39
+ :boolean => true
40
+
41
+ def run
42
+
43
+ # validate base options from base module.
44
+ validate_base_options
45
+
46
+ # Display information if debug mode is on.
47
+ display_debug_info
48
+
49
+ # Gather all repo information from github.
50
+ get_all_repos = get_all_repos(@github_organizations.reverse)
51
+
52
+ # Get all chef cookbooks and versions (hopefully chef does the error handeling).
53
+ cookbooks = rest.get_rest("/cookbooks?num_version=1")
54
+
55
+ # Get the cookbook name from the command line
56
+ @cookbook_name = name_args.first unless name_args.empty?
57
+ cookbook_version = name_args[1] unless name_args[1].nil?
58
+ if @cookbook_name
59
+ repo = get_all_repos.select { |k,v| v["name"] == @cookbook_name }
60
+ else
61
+ #repos = all_repos
62
+ Chef::Log.error("Please specify a cookbook name")
63
+ exit 1
64
+ end
65
+
66
+ if repo.empty?
67
+ Chef::Log.error("Cannot find the repository: #{} within github")
68
+ exit 1
69
+ end
70
+
71
+ github_link = (repo[@cookbook_name][(get_repo_clone_link)])
72
+ if github_link.nil? || github_link.empty?
73
+ Chef::Log.error("Cannot find the link for the repository with the name: #{@cookbook_name}")
74
+ exit 1
75
+ end
76
+ puts github_link
77
+ get_clone(github_link, @cookbook_name)
78
+ version = get_cookbook_copy(@cookbook_name, cookbook_version)
79
+ do_diff(@cookbook_name, version)
80
+ FileUtils.remove_entry(@github_tmp)
81
+ end
82
+
83
+ def do_diff(name, version)
84
+ # Check to see if there is a tag matching the version
85
+ Dir.chdir("#{@github_tmp}/git/#{name}")
86
+ if `git tag`.split("\n").include?(version)
87
+ ui.info("Tag version #{version} found, checking that out for diff")
88
+ # Tag found so checkout that tag
89
+ `git checkout -b #{version}`
90
+ if !$?.exitstatus == 0
91
+ ui.error("Failed to checkout branch #{version}")
92
+ exit 1
93
+ end
94
+ else
95
+ ui.info("Version #{version} of #{name} has no tag, using latest for diff")
96
+ end
97
+
98
+ FileUtils.remove_entry("#{@github_tmp}/git/#{name}/.git")
99
+ output = `git diff --color #{@github_tmp}/git/#{name} #{@github_tmp}/cb/#{name}-#{version} 2>&1`
100
+ if output.length == 0
101
+ ui.info("No differences found")
102
+ else
103
+ ui.msg(output)
104
+ end
105
+ end
106
+
107
+ def get_cookbook_copy(name, version)
108
+ Dir.mkdir("#{@github_tmp}/cb")
109
+ args = ['cookbook', 'download', name ]
110
+ args.push version if version
111
+ Dir.chdir("#{@github_tmp}/cb")
112
+ download = Chef::Knife::CookbookDownload.new(args)
113
+ download.config[:download_directory] = "#{@github_tmp}/cb"
114
+ download.run
115
+
116
+ Dir.entries("#{@github_tmp}/cb").each do |d|
117
+ if d =~ /#{name}-(.*)/
118
+ version = $1
119
+ end
120
+ end
121
+ return version
122
+ end
123
+
124
+ end
125
+ end
126
+ end