knife-github 0.0.7 → 0.0.8

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.
@@ -90,8 +90,8 @@ module KnifeGithubCleanup
90
90
  cookbook = File.join(cookbook_path.first,repo)
91
91
  if File.exists?(cookbook)
92
92
  if repo_status_clean?(repo, cookbook)
93
- # delete the repo
94
- ui.info("Processing [D] #{repo}")
93
+ # delete the repo
94
+ ui.info("Processing [ DELETE ] #{repo}")
95
95
  FileUtils.remove_entry(cookbook)
96
96
  end
97
97
  else
@@ -103,13 +103,13 @@ module KnifeGithubCleanup
103
103
  shell_out!("git fetch", :cwd => cookbook)
104
104
  status = shell_out!("git status", :cwd => cookbook)
105
105
  unless status.stdout == "# On branch master\nnothing to commit (working directory clean)\n"
106
- ui.info("Processing [C] #{repo} (Action needed!)")
106
+ ui.info("Processing [ COMMIT ] #{repo} (Action needed!)")
107
107
  status.stdout.lines.each { |l| puts l.sub( /^/, " ") }
108
108
  return false
109
109
  end
110
110
  log = shell_out!("git log --branches --not --remotes --simplify-by-decoration --decorate --oneline", :cwd => cookbook)
111
111
  unless log.stdout.empty?
112
- ui.info("Processing [B] #{repo} (Action needed!)")
112
+ ui.info("Processing [ BRANCH ] #{repo} (Action needed!)")
113
113
  ui.info(" Please check your branches, one of them has unsaved changes")
114
114
  log.stdout.lines.each { |l| puts l.sub( /^/, " ") }
115
115
  return false
@@ -75,29 +75,31 @@ class Chef
75
75
  end
76
76
  end
77
77
 
78
- def repo_clone(repo, cookbook)
78
+ def repo_clone(repo, cookbook_name)
79
79
  if repo.nil? || repo.empty?
80
- ui.info("Processing [?] #{cookbook}")
81
- Chef::Log.info("Cannot find the repository: #{cookbook} within github")
80
+ ui.info("Processing [ UNKNOWN ] #{cookbook_name}")
81
+ Chef::Log.info("Cannot find the repository: #{cookbook_name} within github")
82
82
  return nil
83
83
  end
84
84
 
85
85
  repo_link = get_repo_clone_link()
86
- if repo[cookbook].nil? || repo[cookbook][repo_link].nil? || repo[cookbook][repo_link].empty?
87
- ui.info("Processing [?] #{cookbook}")
88
- Chef::Log.info("Cannot find the link for the repository with the name: #{cookbook}")
86
+ if repo[cookbook_name].nil? || repo[cookbook_name][repo_link].nil? || repo[cookbook_name][repo_link].empty?
87
+ ui.info("Processing [ UNKNOWN ] #{cookbook_name}")
88
+ Chef::Log.info("Cannot find the link for the repository with the name: #{cookbook_name}")
89
89
  return nil
90
90
  end
91
91
 
92
- github_url = repo[cookbook][repo_link]
93
- cookbook_path = cookbook_path_valid?(cookbook, true)
94
- unless cookbook_path.nil?
95
- ui.info("Processing [C] #{cookbook}")
92
+ github_url = repo[cookbook_name][repo_link]
93
+ cookbook_path = get_cookbook_path(cookbook_name)
94
+ if File.exists?(cookbook_path)
95
+ ui.info("Processing [ SKIP ] #{cookbook_name}")
96
+ Chef::Log.info("Path to #{cookbook_path} already exists, skipping.")
97
+ else
98
+ ui.info("Processing [ CLONE ] #{cookbook_name}")
96
99
  Chef::Log.info("Cloning repository to: #{cookbook_path}")
97
100
  shell_out!("git clone #{github_url} #{cookbook_path}")
98
101
  end
99
102
  end
100
-
101
103
 
102
104
  end
103
105
  end
@@ -0,0 +1,11 @@
1
+ require 'mixlib/config'
2
+ module Github
3
+ module Config
4
+ extend Mixlib::Config
5
+ config_strict_mode true
6
+ config_context :knife do
7
+ configurable :github_url
8
+ configurable :github_organizations
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,236 @@
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
+
20
+ #
21
+ #
22
+ # BE AWARE THIS COMMAND IS STILL UNDER HEAVY DEVELOPMENT!
23
+ #
24
+ #
25
+ require 'chef/knife'
26
+
27
+ module KnifeGithubCreate
28
+ class GithubCreate < Chef::Knife
29
+
30
+ deps do
31
+ require 'chef/knife/github_base'
32
+ include Chef::Knife::GithubBase
33
+ require 'chef/mixin/shell_out'
34
+ end
35
+
36
+ banner "knife github create STRING (options)"
37
+ category "github"
38
+
39
+ option :github_token,
40
+ :short => "-t",
41
+ :long => "--github_token",
42
+ :description => "Your github token for OAuth authentication"
43
+
44
+ option :github_user_repo,
45
+ :short => "-U",
46
+ :long => "--github_user_repo",
47
+ :description => "Create the repo within your user environment",
48
+ :boolean => true
49
+
50
+ def run
51
+ extend Chef::Mixin::ShellOut
52
+
53
+ # validate base options from base module.
54
+ validate_base_options
55
+
56
+ # Display information if debug mode is on.
57
+ display_debug_info
58
+
59
+ # Get the name_args from the command line
60
+ name = name_args.first
61
+
62
+ # Get the organization name from config
63
+ org = locate_config_value('github_organizations').first
64
+
65
+ if name.nil? || name.empty?
66
+ Chef::Log.error("Please specify a repository name")
67
+ exit 1
68
+ end
69
+
70
+ if config[:github_user_repo]
71
+ url = @github_url + "/api/" + @github_api_version + "/user/repos"
72
+ Chef::Log.debug("Creating repository in user environment")
73
+ else
74
+ url = @github_url + "/api/" + @github_api_version + "/orgs/#{org}/repos"
75
+ Chef::Log.debug("Creating repository in organization: #{org}")
76
+ end
77
+
78
+ # Get token information
79
+ token = get_github_token()
80
+
81
+ # Get body data for post
82
+ body = get_body_json(name)
83
+
84
+ # Creating the repository
85
+ Chef::Log.debug("Creating the github repository")
86
+ repo = post_request(url, body, token)
87
+
88
+ Chef::Log.debug("Creating the local repository based on template")
89
+ create_cookbook(name)
90
+
91
+ cookbook_path = get_cookbook_path(name)
92
+
93
+ # Updating README.md if needed.
94
+ update_readme(cookbook_path)
95
+
96
+ # Updateing metadata.rb if needed.
97
+ update_metadata(cookbook_path)
98
+
99
+ github_ssh_url = repo['ssh_url']
100
+
101
+ shell_out!("git init", :cwd => cookbook_path )
102
+ shell_out!("git add .", :cwd => cookbook_path )
103
+ shell_out!("git commit -m 'creating initial cookbook structure from the knife-github plugin' ", :cwd => cookbook_path )
104
+ shell_out!("git remote add origin #{github_ssh_url} ", :cwd => cookbook_path )
105
+ shell_out!("git push -u origin master", :cwd => cookbook_path )
106
+ end
107
+
108
+ # Set the username in README.md
109
+ # @param name [String] cookbook path
110
+ def update_readme(cookbook_path)
111
+ contents = ''
112
+ username = get_username
113
+ readme = File.join(cookbook_path, "README.md")
114
+ File.foreach(readme) do |line|
115
+ line.gsub!(/TODO: List authors/,"#{username}\n")
116
+ contents = contents << line
117
+ end
118
+ File.open(readme, 'w') {|f| f.write(contents) }
119
+ return nil
120
+ end
121
+
122
+ # Set the username and email in metadata.rb
123
+ # @param name [String] cookbook path
124
+ def update_metadata(cookbook_path)
125
+ contents = ''
126
+ username = get_username
127
+ email = get_useremail
128
+ metadata = File.join(cookbook_path, "metadata.rb")
129
+ File.foreach(metadata) do |line|
130
+ line.gsub!(/YOUR_COMPANY_NAME/,username) if username
131
+ line.gsub!(/YOUR_EMAIL/,email) if email
132
+ contents = contents << line
133
+ end
134
+ File.open(metadata, 'w') {|f| f.write(contents) }
135
+ return nil
136
+ end
137
+
138
+ # Get the username from passwd file or git config
139
+ # @param nil
140
+ def get_username()
141
+ username = ENV['USER']
142
+ passwd_user = %x(getent passwd #{username} | cut -d ':' -f 5).chomp
143
+ username = passwd_user if passwd_user
144
+ git_user_name = %x(git config user.name).strip
145
+ username = git_user_name if git_user_name
146
+ username
147
+ end
148
+
149
+ # Get the email from passwd file or git config
150
+ # @param nil
151
+ def get_useremail()
152
+ email = nil
153
+ git_user_email = %x(git config user.email).strip
154
+ email = git_user_email if git_user_email
155
+ email
156
+ end
157
+
158
+ # Create the cookbook template for upload
159
+ # @param name [String] cookbook name
160
+ def create_cookbook(cookbook_name)
161
+ args = [ cookbook_name ]
162
+ create = Chef::Knife::CookbookCreate.new(args)
163
+ create.run
164
+ end
165
+
166
+ # Create the json body with repo config for POST information
167
+ # @param name [String] cookbook name
168
+ def get_body_json(cookbook_name)
169
+ body = {
170
+ "name" => cookbook_name,
171
+ "description" => "We should ask for an description",
172
+ "private" => false,
173
+ "has_issues" => true,
174
+ "has_wiki" => true,
175
+ "has_downloads" => true
176
+ }.to_json
177
+ end
178
+
179
+ # Get the OAuth authentication token from config or command line
180
+ # @param nil
181
+ def get_github_token()
182
+ token = locate_config_value('github_token')
183
+ if token.nil? || token.empty?
184
+ Chef::Log.error("Please specify a github token")
185
+ exit 1
186
+ end
187
+ token
188
+ end
189
+
190
+ # Post Get the OAuth authentication token from config or command line
191
+ # @param url [String] target url (organization or user)
192
+ # body [JSON] json data with repo configuration
193
+ # token [String] token sring
194
+ def post_request(url, body, token)
195
+
196
+ if @github_ssl_verify_mode == "verify_none"
197
+ config[:ssl_verify_mode] = :verify_none
198
+ elsif @github_ssl_verify_mode == "verify_peer"
199
+ config[:ssl_verify_mode] = :verify_peer
200
+ end
201
+
202
+ Chef::Log.debug("URL: " + url.to_s)
203
+
204
+ uri = URI.parse(url)
205
+ http = Net::HTTP.new(uri.host,uri.port)
206
+ if uri.scheme == "https"
207
+ http.use_ssl = true
208
+ if @github_ssl_verify_mode == "verify_none"
209
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
210
+ else
211
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
212
+ end
213
+ end
214
+
215
+ req = Net::HTTP::Post.new(uri.path, initheader = {"Authorization" => "token #{token}"})
216
+ req.body = body
217
+ response = http.request(req)
218
+
219
+ unless response.code == "201" then
220
+ puts "Error #{response.code}: #{response.message}"
221
+ puts JSON.pretty_generate(JSON.parse(response.body))
222
+ puts "URL: #{url}"
223
+ exit 1
224
+ end
225
+
226
+ begin
227
+ json = JSON.parse(response.body)
228
+ rescue
229
+ ui.warn "The result on the RESTRequest is not in json format"
230
+ ui.warn "Output: " + response.body
231
+ exit 1
232
+ end
233
+ json
234
+ end
235
+ end
236
+ end
@@ -122,9 +122,9 @@ class Chef
122
122
  end
123
123
 
124
124
  # is the cookbook in the cookbook_path?
125
- if cookbook_path_valid?(@cookbook_name, false).nil?
125
+ if get_cookbook_path(@cookbook_name).nil?
126
126
  Chef::Log.error("Cookbook is not in cookbook path")
127
- ui.info("HINT: knife github clone #{@cookbook_name}")
127
+ ui.info("HINT: knife github clone #{@cookbook_name}")
128
128
  exit 1
129
129
  end
130
130
 
@@ -236,13 +236,20 @@ class Chef
236
236
  major = $1
237
237
  minor = $2
238
238
  patch = $3
239
- major = major.to_i + 1 if config[:major]
240
- minor = minor.to_i + 1 if config[:minor]
239
+ if config[:major]
240
+ major = major.to_i + 1
241
+ minor = 0
242
+ patch = 0
243
+ end
244
+ if config[:minor]
245
+ minor = minor.to_i + 1
246
+ patch = 0
247
+ end
241
248
  patch = patch.to_i + 1 if config[:patch]
242
249
  version = "#{major}.#{minor}.#{patch}"
243
250
  Chef::Log.debug("New version is #{version}")
244
251
  else
245
- Chef::Log.error("Version is in a format I cannot auto auto-update")
252
+ Chef::Log.error("Version is in a format I cannot auto-update")
246
253
  exit 1
247
254
  end
248
255
  version
@@ -258,7 +265,7 @@ class Chef
258
265
  args.push "--freeze"
259
266
  end
260
267
  upload = Chef::Knife::CookbookUpload.new(args)
261
- #upload.config[:cookbook_path] = "#{@github_tmp}/git"
268
+ # upload.config[:cookbook_path] = "#{@github_tmp}/git"
262
269
  # plugin will throw its own errors
263
270
  upload.run
264
271
  end
@@ -269,8 +276,8 @@ class Chef
269
276
  # @param version [String] Version
270
277
  def checkout_tag(version)
271
278
  ui.info "Checking out tag #{version}"
272
- cpath = get_cookbook_path(@cookbook_name)
273
- Dir.chdir(cpath);
279
+ cookbook_path = get_cookbook_path(@cookbook_name)
280
+ Dir.chdir(cookbook_path);
274
281
  `git checkout -b #{version}`
275
282
  if !$?.exitstatus == 0
276
283
  ui.error("Failed to checkout branch #{version} of #{@cookbook_name}")
@@ -286,39 +293,13 @@ class Chef
286
293
  end
287
294
  end
288
295
 
289
- # Get the version number in the git version of the cookbook
290
- # @param version [String] Version
291
- def get_cookbook_version()
292
- version = nil
293
- cpath = get_cookbook_path(@cookbook_name)
294
- File.foreach("#{cpath}/metadata.rb") do |line|
295
- if line =~ /version.*"(.*)"/i
296
- version = $1
297
- break
298
- end
299
- end
300
- if version.nil?
301
- Chef::Log.error("Cannot get the version for cookbook #{@cookbook_name}")
302
- exit 1
303
- end
304
- version
305
- end
306
-
307
- # Determine if the current cookbook path is valid and that there
308
- # is a cookbook of the correct name in there
309
- # @param cookbook [String] cookbook name
310
- # @return [String] Path to cookbook
311
- def get_cookbook_path(cookbook)
312
- return cookbook_path_valid?(cookbook, false)
313
- end
314
296
 
315
297
  # Commit changes in git
316
298
  # @param version [String] cookbook version
317
299
  # @param push [Bool] true is the cookbook should also be pushed
318
300
  def do_commit(version, push)
319
- cpath = get_cookbook_path(@cookbook_name)
320
- Dir.chdir("#{cpath}")
321
- puts cpath
301
+ cookbook_path = get_cookbook_path(@cookbook_path)
302
+ Dir.chdir("#{cookbook_path}")
322
303
  output = `git commit -a -m "Deploy #{version}" 2>&1`
323
304
  if $?.exitstatus != 0
324
305
  if output !~ /nothing to commit/
@@ -343,12 +324,12 @@ class Chef
343
324
  def set_cookbook_version(version)
344
325
  return unless get_cookbook_version() != version
345
326
  contents = ''
346
- cpath = get_cookbook_path(@cookbook_name)
347
- File.foreach("#{cpath}/metadata.rb") do |line|
327
+ cookbook_path = get_cookbook_path(@cookbook_name)
328
+ File.foreach("#{cookbook_path}/metadata.rb") do |line|
348
329
  line.gsub!(/(version[\t\s]+)(.*)/i,"\\1 \"#{version}\"\n")
349
330
  contents = contents << line
350
331
  end
351
- File.open("#{cpath}/metadata.rb", 'w') {|f| f.write(contents) }
332
+ File.open("#{cookbook_path}/metadata.rb", 'w') {|f| f.write(contents) }
352
333
  return true
353
334
  end
354
335
 
@@ -88,8 +88,8 @@ class Chef
88
88
  if config[:github]
89
89
  get_clone(github_link, @cookbook_name)
90
90
  else # Copy downloaded version to #{@github_tmp}/git
91
- cpath = cookbook_path_valid?(@cookbook_name, false)
92
- if cpath.nil?
91
+ cookbook_path = get_cookbook_path(@cookbook_name)
92
+ if cookbook_path.nil?
93
93
  Chef::Log.error("Cannot find any local repository with the name: #{@cookbook_name}")
94
94
  Chef::Log.error("Please use the option -g if you want to diff the github repository")
95
95
  exit 1
@@ -98,7 +98,7 @@ class Chef
98
98
  if ! File.exists?(tpath)
99
99
  FileUtils.makedirs(tpath)
100
100
  end
101
- FileUtils.cp_r cpath, tpath
101
+ FileUtils.cp_r cookbook_path, tpath
102
102
  end
103
103
 
104
104
  version = get_cookbook_copy(@cookbook_name, cookbook_version)