knife-spork-berks 1.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/.gitignore +19 -0
  2. data/.ruby-gemset +1 -0
  3. data/.ruby-version +1 -0
  4. data/CHANGELOG.md +284 -0
  5. data/Gemfile +3 -0
  6. data/LICENSE +35 -0
  7. data/README.md +406 -0
  8. data/Rakefile +2 -0
  9. data/knife-spork-berks.gemspec +22 -0
  10. data/lib/chef/knife/spork-bump.rb +86 -0
  11. data/lib/chef/knife/spork-check.rb +149 -0
  12. data/lib/chef/knife/spork-databag-create.rb +53 -0
  13. data/lib/chef/knife/spork-databag-delete.rb +51 -0
  14. data/lib/chef/knife/spork-databag-edit.rb +54 -0
  15. data/lib/chef/knife/spork-databag-fromfile.rb +82 -0
  16. data/lib/chef/knife/spork-environment-create.rb +43 -0
  17. data/lib/chef/knife/spork-environment-delete.rb +36 -0
  18. data/lib/chef/knife/spork-environment-edit.rb +37 -0
  19. data/lib/chef/knife/spork-environment-fromfile.rb +42 -0
  20. data/lib/chef/knife/spork-info.rb +30 -0
  21. data/lib/chef/knife/spork-node-create.rb +38 -0
  22. data/lib/chef/knife/spork-node-delete.rb +38 -0
  23. data/lib/chef/knife/spork-node-edit.rb +45 -0
  24. data/lib/chef/knife/spork-node-fromfile.rb +43 -0
  25. data/lib/chef/knife/spork-node-runlistadd.rb +48 -0
  26. data/lib/chef/knife/spork-node-runlistremove.rb +42 -0
  27. data/lib/chef/knife/spork-node-runlistset.rb +42 -0
  28. data/lib/chef/knife/spork-omni.rb +107 -0
  29. data/lib/chef/knife/spork-promote.rb +166 -0
  30. data/lib/chef/knife/spork-role-create.rb +43 -0
  31. data/lib/chef/knife/spork-role-delete.rb +36 -0
  32. data/lib/chef/knife/spork-role-edit.rb +37 -0
  33. data/lib/chef/knife/spork-role-fromfile.rb +42 -0
  34. data/lib/chef/knife/spork-upload.rb +129 -0
  35. data/lib/knife-spork.rb +3 -0
  36. data/lib/knife-spork/plugins.rb +25 -0
  37. data/lib/knife-spork/plugins/campfire.rb +211 -0
  38. data/lib/knife-spork/plugins/eventinator.rb +317 -0
  39. data/lib/knife-spork/plugins/foodcritic.rb +46 -0
  40. data/lib/knife-spork/plugins/git.rb +197 -0
  41. data/lib/knife-spork/plugins/graphite.rb +25 -0
  42. data/lib/knife-spork/plugins/grove.rb +161 -0
  43. data/lib/knife-spork/plugins/hipchat.rb +131 -0
  44. data/lib/knife-spork/plugins/irccat.rb +298 -0
  45. data/lib/knife-spork/plugins/jabber.rb +129 -0
  46. data/lib/knife-spork/plugins/plugin.rb +105 -0
  47. data/lib/knife-spork/plugins/statusnet.rb +118 -0
  48. data/lib/knife-spork/runner.rb +277 -0
  49. data/plugins/Campfire.md +43 -0
  50. data/plugins/Eventinator.md +30 -0
  51. data/plugins/Foodcritic.md +53 -0
  52. data/plugins/Git.md +46 -0
  53. data/plugins/Graphite.md +30 -0
  54. data/plugins/Grove.md +31 -0
  55. data/plugins/HipChat.md +50 -0
  56. data/plugins/Irccat.md +50 -0
  57. data/plugins/Jabber.md +61 -0
  58. data/plugins/README.md +70 -0
  59. data/plugins/StatusNet.md +41 -0
  60. data/plugins/Template.md +34 -0
  61. metadata +170 -0
@@ -0,0 +1,46 @@
1
+ require 'knife-spork/plugins/plugin'
2
+
3
+ module KnifeSpork
4
+ module Plugins
5
+ class Foodcritic < Plugin
6
+ name :foodcritic
7
+ hooks :after_check, :before_upload
8
+
9
+ def perform
10
+ safe_require 'foodcritic'
11
+
12
+ if Gem::Specification.find_all_by_name("foodcritic", "~> 3.0.0").empty?
13
+ ui.fatal "The knife-spork foodcritic plugin requires foodcritic >= 3.0.0. Please install a more recent foodcritic version."
14
+ exit 1
15
+ end
16
+
17
+ tags = config.tags || []
18
+ fail_tags = config.fail_tags || ['any']
19
+ include_rules = config.include_rules || []
20
+
21
+ cookbooks.each do |cookbook|
22
+ ui.info "Running foodcritic against #{cookbook.name}@#{cookbook.version}..."
23
+
24
+ cookbook_path = cookbook.root_dir
25
+
26
+ ui.info cookbook_path
27
+
28
+ options = {:tags => tags, :fail_tags => fail_tags, :include_rules => include_rules, :cookbook_paths => [cookbook_path]}
29
+ review = ::FoodCritic::Linter.new.check(options)
30
+
31
+ if review.failed?
32
+ ui.error "Foodcritic failed!"
33
+ review.to_s.split("\n").each{ |r| ui.error r.to_s }
34
+ exit(1) if config.epic_fail
35
+ else
36
+ ui.info "Passed!"
37
+ end
38
+ end
39
+ end
40
+
41
+ def epic_fail?
42
+ config.epic_fail.nil? ? 'true' : config.epic_fail
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,197 @@
1
+ require 'knife-spork/plugins/plugin'
2
+
3
+ module KnifeSpork
4
+ module Plugins
5
+ class Git < Plugin
6
+ name :git
7
+
8
+ def perform; end
9
+
10
+ def before_bump
11
+ git_pull(environment_path) unless cookbook_path.include?(environment_path.gsub"/environments","")
12
+ git_pull_submodules(environment_path) unless cookbook_path.include?(environment_path.gsub"/environments","")
13
+ cookbooks.each do |cookbook|
14
+ git_pull(cookbook_path_for(cookbook))
15
+ git_pull_submodules(cookbook_path_for(cookbook))
16
+ end
17
+ end
18
+
19
+ def before_upload
20
+ git_pull(environment_path) unless cookbook_path.include?(environment_path.gsub"/environments","")
21
+ git_pull_submodules(environment_path) unless cookbook_path.include?(environment_path.gsub"/environments","")
22
+ cookbooks.each do |cookbook|
23
+ git_pull(cookbook_path_for(cookbook))
24
+ git_pull_submodules(cookbook_path_for(cookbook))
25
+ end
26
+ end
27
+
28
+ def before_promote
29
+ cookbooks.each do |cookbook|
30
+ git_pull(environment_path) unless cookbook_path_for(cookbook).include?(environment_path.gsub"/environments","")
31
+ git_pull_submodules(environment_path) unless cookbook_path_for(cookbook).include?(environment_path.gsub"/environments","")
32
+ git_pull(cookbook_path_for(cookbook))
33
+ git_pull_submodules(cookbook_path_for(cookbook))
34
+ end
35
+ end
36
+
37
+ def after_bump
38
+ cookbooks.each do |cookbook|
39
+ git_add(cookbook_path_for(cookbook),"metadata.rb")
40
+ end
41
+ end
42
+
43
+ def after_promote_local
44
+ environments.each do |environment|
45
+ git_add(environment_path,"#{environment}.json")
46
+ end
47
+ end
48
+
49
+ private
50
+ def git
51
+ safe_require 'git'
52
+ log = Logger.new(STDOUT)
53
+ log.level = Logger::WARN
54
+ @git ||= begin
55
+ ::Git.open('.', :log => log)
56
+ rescue
57
+ ui.error 'You are not currently in a git repository. Please ensure you are in a git repo, a repo subdirectory, or remove the git plugin from your KnifeSpork configuration!'
58
+ exit(0)
59
+ end
60
+ end
61
+
62
+ # In this case, a git pull will:
63
+ # - Stash local changes
64
+ # - Pull from the remote
65
+ # - Pop the stash
66
+ def git_pull(path)
67
+ if is_repo?(path)
68
+ ui.msg "Git: Pulling latest changes from #{path}"
69
+ output = IO.popen("git pull 2>&1")
70
+ Process.wait
71
+ exit_code = $?
72
+ if !exit_code.exitstatus == 0
73
+ ui.error "#{output.read()}\n"
74
+ exit 1
75
+ end
76
+ end
77
+ end
78
+
79
+ def git_pull_submodules(path)
80
+ if is_repo?(path)
81
+ ui.msg "Pulling latest changes from git submodules (if any)"
82
+ top_level = `cd #{path} && git rev-parse --show-toplevel 2>&1`.chomp
83
+ if is_submodule?(top_level)
84
+ top_level = get_parent_dir(top_level)
85
+ end
86
+ output = IO.popen("cd #{top_level} && git submodule foreach git pull 2>&1")
87
+ Process.wait
88
+ exit_code = $?
89
+ if !exit_code.exitstatus == 0
90
+ ui.error "#{output.read()}\n"
91
+ exit 1
92
+ end
93
+ end
94
+ end
95
+
96
+ def git_add(filepath,filename)
97
+ if is_repo?(filepath)
98
+ ui.msg "Git add'ing #{filepath}/#{filename}"
99
+ output = IO.popen("cd #{filepath} && git add #{filename}")
100
+ Process.wait
101
+ exit_code = $?
102
+ if !exit_code.exitstatus == 0
103
+ ui.error "#{output.read()}\n"
104
+ exit 1
105
+ end
106
+ end
107
+ end
108
+
109
+ # Commit changes, if any
110
+ def git_commit
111
+ begin
112
+ git.add('.')
113
+ `git ls-files --deleted`.chomp.split("\n").each{ |f| git.remove(f) }
114
+ git.commit_all "[KnifeSpork] Bumping cookbooks:\n#{cookbooks.collect{|c| " #{c.name}@#{c.version}"}.join("\n")}"
115
+ rescue ::Git::GitExecuteError; end
116
+ end
117
+
118
+ def git_push(tags = false)
119
+ begin
120
+ git.push remote, branch, tags
121
+ rescue ::Git::GitExecuteError => e
122
+ ui.error "Could not push to remote #{remote}/#{branch}. Does it exist?"
123
+ end
124
+ end
125
+
126
+ def git_tag(tag)
127
+ begin
128
+ git.add_tag(tag)
129
+ rescue ::Git::GitExecuteError => e
130
+ ui.error "Could not tag #{tag_name}. Does it already exist?"
131
+ ui.error 'You may need to delete the tag before running promote again.'
132
+ end
133
+ end
134
+
135
+ def is_repo?(path)
136
+ output = IO.popen("cd #{path} && git rev-parse --git-dir 2>&1")
137
+ Process.wait
138
+ if $? != 0
139
+ ui.warn "#{path} is not a git repo, skipping..."
140
+ return false
141
+ else
142
+ return true
143
+ end
144
+ end
145
+
146
+ def is_submodule?(path)
147
+ top_level = `cd #{path} && git rev-parse --show-toplevel 2>&1`.chomp
148
+ output = IO.popen("cd #{top_level}/.. && git rev-parse --show-toplevel 2>&1")
149
+ Process.wait
150
+ if $? != 0
151
+ return false
152
+ else
153
+ return true
154
+ end
155
+ end
156
+
157
+ def get_parent_dir(path)
158
+ top_level = path
159
+ return_code = 0
160
+ while return_code == 0
161
+ output = IO.popen("cd #{top_level}/.. && git rev-parse --show-toplevel 2>&1")
162
+ Process.wait
163
+ return_code = $?
164
+ cmd_output = output.read.chomp
165
+ #cygwin, I hate you for making me do this
166
+ if cmd_output.include?("fatal: Not a git repository")
167
+ return_code = 1
168
+ end
169
+ if return_code == 0
170
+ top_level = cmd_output
171
+ end
172
+ end
173
+ top_level
174
+ end
175
+
176
+ def remote
177
+ config.remote || 'origin'
178
+ end
179
+
180
+ def branch
181
+ config.branch || 'master'
182
+ end
183
+
184
+ def tag_name
185
+ cookbooks.collect{|c| "#{c.name}@#{c.version}"}.join('-')
186
+ end
187
+
188
+ def cookbook_path_for cookbook
189
+ if defined?(Berkshelf) and cookbook.is_a? Berkshelf::CachedCookbook
190
+ cookbook.path.to_s
191
+ else
192
+ cookbook.root_dir
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,25 @@
1
+ require 'knife-spork/plugins/plugin'
2
+
3
+ module KnifeSpork
4
+ module Plugins
5
+ class Graphite < Plugin
6
+ name :graphite
7
+ hooks :after_promote_remote
8
+
9
+ def perform
10
+ environments.each do |environment|
11
+ begin
12
+ message = "deploys.chef.#{environment} 1 #{Time.now.to_i}\n"
13
+ socket = TCPSocket.open(config.server, config.port)
14
+ socket.write(message)
15
+ rescue Exception => e
16
+ ui.error 'Graphite was unable to process the request.'
17
+ ui.error e.to_s
18
+ ensure
19
+ socket.close unless socket.nil?
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,161 @@
1
+ require 'knife-spork/plugins/plugin'
2
+
3
+ module KnifeSpork
4
+ module Plugins
5
+ class Grove < Plugin
6
+ name :grove
7
+
8
+ def perform; end
9
+
10
+ def after_upload
11
+ grove <<-EOH
12
+ #{current_user} froze the following cookbooks on Chef Server: #{cookbooks.collect{|c| "#{c.name}@#{c.version}"}.join(', ')}
13
+ EOH
14
+ end
15
+
16
+ def after_promote_remote
17
+ grove <<-EOH
18
+ #{current_user} promoted #{cookbooks.collect{|c| "#{c.name}@#{c.version}"}.join(', ')} on #{environments.collect{|e| "#{e.name}"}.join(', ')}
19
+ EOH
20
+ end
21
+
22
+ def after_environmentfromfile
23
+ grove <<-EOH
24
+ #{current_user} uploaded environment #{object_name}
25
+ EOH
26
+ end
27
+
28
+ def after_environmentedit
29
+ grove <<-EOH
30
+ #{current_user} edited environment #{object_name}
31
+ EOH
32
+ end
33
+
34
+ def after_environmentcreate
35
+ grove <<-EOH
36
+ #{current_user} created environment #{object_name}
37
+ EOH
38
+ end
39
+
40
+ def after_environmentdelete
41
+ grove <<-EOH
42
+ #{current_user} deleted environment #{object_name}
43
+ EOH
44
+ end
45
+
46
+ def after_rolefromfile
47
+ grove <<-EOH
48
+ #{current_user} uploaded role #{object_name}
49
+ EOH
50
+ end
51
+
52
+ def after_roleedit
53
+ grove <<-EOH
54
+ #{current_user} edited role #{object_name}
55
+ EOH
56
+ end
57
+
58
+ def after_rolecreate
59
+ grove <<-EOH
60
+ #{current_user} created role #{object_name}
61
+ EOH
62
+ end
63
+
64
+ def after_roledelete
65
+ grove <<-EOH
66
+ #{current_user} deleted role #{object_name}
67
+ EOH
68
+ end
69
+
70
+ def after_databagcreate
71
+ grove <<-EOH
72
+ #{current_user} created data bag #{object_name}
73
+ EOH
74
+ end
75
+
76
+ def after_databagedit
77
+ grove <<-EOH
78
+ #{current_user} edited data bag item #{object_name}:#{object_secondary_name}
79
+ EOH
80
+ end
81
+
82
+ def after_databagitemdelete
83
+ grove <<-EOH
84
+ #{current_user} edited data bag item #{object_name}:#{object_secondary_name}
85
+ EOH
86
+ end
87
+
88
+ def after_databagdelete
89
+ grove <<-EOH
90
+ #{current_user} edited data bag #{object_name}
91
+ EOH
92
+ end
93
+
94
+ def after_databagfromfile
95
+ grove <<-EOH
96
+ #{current_user} uploaded data bag item #{object_name}:#{object_secondary_name}
97
+ EOH
98
+ end
99
+
100
+ def after_nodeedit
101
+ grove <<-EOH
102
+ #{current_user} edited node #{object_name}
103
+ EOH
104
+ end
105
+
106
+ def after_nodedelete
107
+ grove <<-EOH
108
+ #{current_user} deleted node #{object_name}
109
+ EOH
110
+ end
111
+
112
+ def after_nodecreate
113
+ grove <<-EOH
114
+ #{current_user} created node #{object_name}
115
+ EOH
116
+ end
117
+
118
+ def after_nodefromfile
119
+ grove <<-EOH
120
+ #{current_user} uploaded node #{object_name}
121
+ EOH
122
+ end
123
+
124
+ def after_noderunlistadd
125
+ grove <<-EOH
126
+ #{current_user} added run_list items to #{object_name}: #{object_secondary_name}
127
+ EOH
128
+ end
129
+
130
+ def after_noderunlistremove
131
+ grove <<-EOH
132
+ #{current_user} removed run_list items from #{object_name}: #{object_secondary_name}
133
+ EOH
134
+ end
135
+
136
+ def after_noderunlistset
137
+ grove <<-EOH
138
+ #{current_user} set the run_list for #{object_name} to #{object_secondary_name}
139
+ EOH
140
+ end
141
+
142
+ private
143
+ def grove(message)
144
+ safe_require 'rest_client'
145
+
146
+ config.tokens.each do |token|
147
+ # Grove can't handle multi-line messages, so let's split by line
148
+ message.split("\n").flatten.delete_if(&:empty?).each do |line|
149
+ RestClient.post "https://grove.io/api/notice/#{token}/",
150
+ :message => line,
151
+ :service => 'knife-spork'
152
+ end
153
+ end
154
+ end
155
+
156
+ def tokens
157
+ Array(config.token || config.tokens)
158
+ end
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,131 @@
1
+ require 'knife-spork/plugins/plugin'
2
+
3
+ module KnifeSpork
4
+ module Plugins
5
+ class HipChat < Plugin
6
+ name :hipchat
7
+
8
+ def perform; end
9
+
10
+ def after_upload
11
+ hipchat "#{organization}#{current_user} uploaded the following cookbooks:\n#{cookbooks.collect{ |c| " #{c.name}@#{c.version}" }.join("\n")}"
12
+ end
13
+
14
+ def after_promote_remote
15
+ hipchat "#{organization}#{current_user} promoted the following cookbooks:\n#{cookbooks.collect{ |c| " #{c.name}@#{c.version}" }.join("\n")} to #{environments.collect{ |e| "#{e.name}" }.join(", ")}"
16
+ end
17
+
18
+ def after_environmentfromfile
19
+ hipchat "#{organization}#{current_user} uploaded environment #{object_name}"
20
+ end
21
+
22
+ def after_environmentedit
23
+ hipchat "#{organization}#{current_user} edited environment #{object_name}"
24
+ end
25
+
26
+ def after_environmentcreate
27
+ hipchat "#{organization}#{current_user} created environment #{object_name}"
28
+ end
29
+
30
+ def after_environmentdelete
31
+ hipchat "#{organization}#{current_user} deleted environment #{object_name}"
32
+ end
33
+
34
+ def after_rolefromfile
35
+ hipchat "#{organization}#{current_user} uploaded role #{object_name}"
36
+ end
37
+
38
+ def after_roleedit
39
+ hipchat "#{organization}#{current_user} edited role #{object_name}"
40
+ end
41
+
42
+ def after_rolecreate
43
+ hipchat "#{organization}#{current_user} created role #{object_name}"
44
+ end
45
+
46
+ def after_roledelete
47
+ hipchat "#{organization}#{current_user} deleted role #{object_name}"
48
+ end
49
+
50
+ def after_databagedit
51
+ hipchat "#{organization}#{current_user} edited data bag item #{object_name}:#{object_secondary_name}"
52
+ end
53
+
54
+ def after_databagcreate
55
+ hipchat "#{organization}#{current_user} created data bag #{object_name}"
56
+ end
57
+
58
+ def after_databagdelete
59
+ hipchat "#{organization}#{current_user} deleted data bag item #{object_name}"
60
+ end
61
+
62
+ def after_databagitemdelete
63
+ hipchat "#{organization}#{current_user} deleted data bag item #{object_name}:#{object_secondary_name}"
64
+ end
65
+
66
+ def after_databagfromfile
67
+ hipchat "#{organization}#{current_user} uploaded data bag item #{object_name}:#{object_secondary_name}"
68
+ end
69
+
70
+ def after_nodeedit
71
+ hipchat "#{organization}#{current_user} edited node #{object_name}"
72
+ end
73
+
74
+ def after_nodedelete
75
+ hipchat "#{organization}#{current_user} deleted node #{object_name}"
76
+ end
77
+
78
+ def after_nodecreate
79
+ hipchat "#{organization}#{current_user} created node #{object_name}"
80
+ end
81
+
82
+ def after_nodefromfile
83
+ hipchat "#{organization}#{current_user} uploaded node #{object_name}"
84
+ end
85
+
86
+ def after_noderunlistadd
87
+ hipchat "#{organization}#{current_user} added run_list items to #{object_name}: #{object_secondary_name}"
88
+ end
89
+
90
+ def after_noderunlistremove
91
+ hipchat "#{organization}#{current_user} removed run_list items from #{object_name}: #{object_secondary_name}"
92
+ end
93
+
94
+ def after_noderunlistset
95
+ hipchat "#{organization}#{current_user} set the run_list for #{object_name} to #{object_secondary_name}"
96
+ end
97
+
98
+
99
+ private
100
+ def hipchat(message)
101
+ safe_require 'hipchat'
102
+
103
+ rooms.each do |room_name|
104
+ begin
105
+ client = ::HipChat::Client.new(config.api_token)
106
+ client[room_name].send(nickname, message, :notify => notify, :color =>color)
107
+ rescue Exception => e
108
+ ui.error 'Something went wrong sending to HipChat.'
109
+ ui.error e.to_s
110
+ end
111
+ end
112
+ end
113
+
114
+ def rooms
115
+ [ config.room || config.rooms ].flatten
116
+ end
117
+
118
+ def nickname
119
+ config.nickname || 'KnifeSpork'
120
+ end
121
+
122
+ def notify
123
+ config.notify.nil? ? true : config.notify
124
+ end
125
+
126
+ def color
127
+ config.color || 'yellow'
128
+ end
129
+ end
130
+ end
131
+ end