capnotify 0.1.0pre

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 1.8.7
5
+ - ree
6
+ script: bundle exec rspec spec
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in capnotify.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Spike Grobstein
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,376 @@
1
+ # Capnotify [![Build Status](https://travis-ci.org/spikegrobstein/capnotify.png)](https://travis-ci.org/spikegrobstein/capnotify)
2
+
3
+ __________________
4
+ - --|\ Deployment /| _____ __ _ ___
5
+ - ---| \ Complete / | / ___/__ ____ ___ ___ / /_(_) _/_ __
6
+ - ----| /\____________/\ | / /__/ _ `/ _ \/ _ \/ _ \/ __/ / _/ // /
7
+ - -----|/ - Capistrano - \| \___/\_,_/ .__/_//_/\___/\__/_/_/ \_, /
8
+ - ------|__________________| /_/ /___/
9
+
10
+ Standardized and robust notifications sent from your Capistrano recipes.
11
+
12
+ When dealing with large-scale deployment notifications, it's important to have
13
+ consistent language across notification media. Capnotify offers an extensible and standardized
14
+ framework for which to send notifications at different stages of your deployment,
15
+ mechanisms to extend and customize those messages as well as a collection of
16
+ built-in, predefined messages and templates.
17
+
18
+ Although currently a work in progress, Capnotify provides a solid framework to
19
+ extend for your notification needs. Until the 1.0 release, the interface can change
20
+ in drastic ways at any time. Be sure to restrict the version of the gem until a final release
21
+ is made.
22
+
23
+ ## Installation
24
+
25
+ Add this line to your application's Gemfile:
26
+
27
+ gem 'capnotify'
28
+
29
+ And then execute:
30
+
31
+ $ bundle
32
+
33
+ Or install it yourself as:
34
+
35
+ $ gem install capnotify
36
+
37
+ Then, in your `Capfile`, add the following line:
38
+
39
+ require 'capnotify'
40
+
41
+ ## Usage
42
+
43
+ The current build of Capnotify is designed to be extended and doesn't provide much in the way
44
+ of notifications out of the box. It does, however, provide a series of Capistrano callbacks
45
+ that you can hook into and leverage your existing notification system, be it IRC, Email,
46
+ Hipchat, or Grove.io.
47
+
48
+ Following are a few examples for hooking up into these callbacks.
49
+
50
+ ### Quickstart
51
+
52
+ Capnotify can be used in your current deployment recipes and is easy to implement. The
53
+ following examples will get you up and running with these callbacks.
54
+
55
+ #### Short Messages
56
+
57
+ Capnotify has some built-in short messages right out of the box. If you'd like, for example,
58
+ to send a short message notification when deployment starts and completes, it can be
59
+ done like the following:
60
+
61
+ on(:deploy_start) do
62
+ SomeLib.send_message( capnotify_deploy_start_msg )
63
+ end
64
+
65
+ on(:deploy_complete) do
66
+ SomeLib.send_message( capnotify_deploy_complete_msg )
67
+ end
68
+
69
+ In the case of the above example, replace the `SomeLib#send_message` call with your library's
70
+ function.
71
+
72
+ A full list of available callbacks and built-in messages can be found below in the
73
+ **Hooks and Callbacks** and **Messages** sections.
74
+
75
+ #### Long Messages
76
+
77
+ Capnotify also has built-in long message HTML templates and are primarily designed for
78
+ building email messages, but don't necessarily need to be used for that.
79
+
80
+ For an example of how to send an email, see the following:
81
+
82
+ on(:deploy_complete) do
83
+ MyMailer.send_mail(
84
+ :text_body => capnotify_deployment_notification_text,
85
+ :html_body => capnotify_deployment_notification_html
86
+ )
87
+ end
88
+
89
+ The `capnotify_deployment_notification_text` and `capnotify_deployment_notification_html`
90
+ Capistrano variables are lazily evaluated, and when called, will generate the deployment
91
+ notification email bodies for text or html respectively.
92
+
93
+ See the section **Built-in Templates** below for more information about templates and how
94
+ to further customize them.
95
+
96
+ ##### Components
97
+
98
+ Long messages can be further customized through the use of Components. Using the
99
+ `capnotify#components` function, you can add a `Capnotify::Component` which is a collection
100
+ of information inside the body of an email. Capnotify comes with 2 built-in components:
101
+ "Deployment Overview" and "Deployment Details" which contain the `ref`, `sha1`, deployer
102
+ username, Github URL, deployment time, and repository information about the deployment.
103
+
104
+ Some examples for extensions that could be added would be reports about deployment durations,
105
+ commit logs, information about previous deploys, or custom email messages.
106
+
107
+ A quick example of creating and appending a component to Capnotify is the following:
108
+
109
+ capnotify.components << Capnotify::Component.new(:my_component) do |c|
110
+ # this is the header that appears in the email:
111
+ c.header = 'Deployment Overview'
112
+
113
+ # initialize the content as a hash
114
+ c.content = {}
115
+
116
+ # build the collection of data
117
+ c.content['Deployed by'] = capnotify.deployed_by
118
+ c.content['Deployed at'] = Time.now
119
+ c.content['Application'] = fetch(:application, '')
120
+ c.content['Repository'] = fetch(:repository, '')
121
+ end
122
+
123
+ This above example is taken straight from the `Overview` extension that's built into
124
+ Capnotify.
125
+
126
+ This only scratched the surface of what you can do with this; for more information
127
+ on Components, see the **Components** section below.
128
+
129
+ #### More information
130
+
131
+ In addition, to take the next step and create reusable code, you can create an
132
+ Extension which can be packaged as a gem.
133
+
134
+ See **Extensions** for information on building extensions.
135
+
136
+ See **Hooks and Callbacks** for a list of available Capistrano callbacks.
137
+
138
+ See **Components** for information on creating components.
139
+
140
+ See **Built-in Templates** for information on customizing templates and replacing with
141
+ your own templates.
142
+
143
+ ## Hooks, Callbacks and Events
144
+
145
+ Capnotify provides hooks and callbacks for common, notifiable tasks in addition
146
+ to the standard Capistrano set.
147
+
148
+ ### Default Hooks
149
+
150
+ Capnotify has a series of built-in default hooks that you can use to take action when
151
+ certain events occur in your Capistrano recipes:
152
+
153
+ * `deploy_start`
154
+ * `deploy_complete`
155
+ * `migrate_start`
156
+ * `migrate_complete`
157
+ * `maintenance_page_up`
158
+ * `maintenance_page_down`
159
+
160
+ Following are descriptions of each built-in hook with a brief description, purpose and
161
+ time in which it is called, suggested associated messages
162
+ (see **Messages** sections for more information about these) and an example of how to use it.
163
+
164
+ #### deploy_start
165
+
166
+ By default he `deploy_start` hook is called immediately before the
167
+ `deploy` Capistrano task.
168
+
169
+ Suggested message: `capnotify_deploy_start_msg`
170
+
171
+ Example:
172
+
173
+ on(:deploy_start) do
174
+ MyService.notify( capnotify_deploy_start_msg )
175
+ end
176
+
177
+ #### deploy_complete
178
+
179
+ By default the `deploy_complete` hook is called immediately after the `deploy`
180
+ Capistrano task.
181
+
182
+ Suggested message: `capnotify_deploy_complete_msg`
183
+
184
+ Example:
185
+
186
+ on(:deploy_complete) do
187
+ MyService.notify( capnotify_deploy_complete_msg )
188
+ end
189
+
190
+ #### migrate_start
191
+
192
+ By default, the `migrate_start` hook is called immediately before `deploy:migrate`. This hook
193
+ is designed to be used to notify DBAs of database changes or can be used to measure the
194
+ elapsed time a migration takes.
195
+
196
+ Suggested message: `capnotify_migrate_start_msg`
197
+
198
+ Example:
199
+
200
+ on(:migrate_start) do
201
+ MyService.notify( capnotify_migrate_start_msg )
202
+ end
203
+
204
+ #### migrate_complete
205
+
206
+ By default, the `migrate_complete` hook is called immediately after `deploy:migrate` finishes.
207
+
208
+ Suggested message: `capnotify_migrate_complete_msg`
209
+
210
+ Example:
211
+
212
+ on(:migrate_complete) do
213
+ MyService.notify( capnotify_migrate_complete_msg )
214
+ end
215
+
216
+ #### maintenance_page_up
217
+
218
+ By default, the `maintenance_page_up` hook is called immediately before `deploy:web:disable`.
219
+
220
+ Suggested message: `capnotify_maintenance_up_msg`
221
+
222
+ Example:
223
+
224
+ on(:maintenance_page_up) do
225
+ MyService.notify( capnotify_maintenance_up_msg )
226
+ end
227
+
228
+ #### maintenance_page_down
229
+
230
+ By default, the `maintenance_page_down` hook is called immediately after `deploy:web:enable`.
231
+
232
+ Suggested message: `capnotify_maintenance_down_msg`
233
+
234
+ Example:
235
+
236
+ on(:maintenance_page_down) do
237
+ MyService.notify( capnotify_maintenance_down_msg )
238
+ end
239
+
240
+ ### Changing default callbacks
241
+
242
+ Because not every Capistrano configuration is the same and not every application's needs match,
243
+ Capnotify provides facilities to customize how the callbacks are called. In the event that your
244
+ recipe uses different task names than the above, you can manually call the hooks using the
245
+ `trigger` Capistrano function.
246
+
247
+ For example, if you use a `deploy:api` task for deployment, but still want to leverage the
248
+ `deploy_start` hook, you could do the following:
249
+
250
+ before('deploy:api') { trigger :deploy_start }
251
+ after('deploy:api') { trigger :deploy_complete }
252
+
253
+ These hooks do not have to be triggered only inside `before`/`after` blocks; they can be
254
+ called from anywhere by using `trigger :deploy_start`.
255
+
256
+ ### Disabling default callbacks
257
+
258
+ Setting the following Capistrano variables to `true` will disable the respective built-in
259
+ hook pairs:
260
+
261
+ * `capnotify_disable_deploy_hooks`
262
+ * `capnotify_disable_migrate_hooks`
263
+ * `capnotify_disable_maintenance_hooks`
264
+
265
+ For example:
266
+
267
+ set :capnotify_disable_deploy_hooks, true
268
+
269
+ Will disable triggering both `deploy_start` and `deploy_complete`.
270
+
271
+ These only affect the *built-in* hooks, so if you have an extension that defines its own, you
272
+ should consult that extension's documentation for ways to disable its hooks. Extension
273
+ developers are encouraged to implement the above methods in their own extensions for the sake
274
+ of consistency.
275
+
276
+ ## Built-in strings and functions
277
+
278
+ Capnotify has a collection of built-in strings for messages that can be embedded or overridden.
279
+ These are all built using the `capnotify.appname` function which contains the `application` and
280
+ optional `stage` values (eg: `MyApplication production`).
281
+
282
+ You can override these values by `set`ing the value in your recipe or extension. For example:
283
+
284
+ set :capnotify_migrate_start_msg, "Migration has just begun!"
285
+
286
+ ### capnotify.appname
287
+
288
+ The `capnotify.appname` function calls the `capnotify_appname` Capistrano variable which,
289
+ by default, combines the `application` and the optional `stage` variables. To override this,
290
+ you can do something like the following example:
291
+
292
+ set :capnotify_appname, "#{ application }/#{ branch } #{ stage.capitalize }"
293
+
294
+ That will replace the behavior of the `capnotify.appname` calls.
295
+
296
+ ### Short Messages
297
+
298
+ The following messages are built-in using Capistrano variables. They can be overridden using
299
+ the `set` command:
300
+
301
+ * `capnotify_migrate_start_msg`
302
+ * `capnotify_migrate_complete_msg`
303
+ * `capnotify_deploy_start_msg`
304
+ * `capnotify_deploy_complete_msg`
305
+ * `capnotify_maintenance_up_msg`
306
+ * `capnotify_maintenance_down_msg`
307
+
308
+ ## Built-in Templates for Long Messages
309
+
310
+ In addition to the Short Messages above, Capnotify comes with support for long-form messages
311
+ for use in emails. There are built-in ERB templates for both HTML and Text emails.
312
+
313
+ Two Capistrano variables are defined which build their associated templates when called, so
314
+ the contents of the messages can be easily overridden if you'd like.
315
+
316
+ ### capnotify_deployment_notification_html
317
+
318
+ This will generate the HTML message, designed for notifying of a completed deployment. It
319
+ will use the built-in template defined by `capnotify_deployment_notification_html_template_path`
320
+ which points to the html template in this gem's `lib/capnotify/templates` directory.
321
+
322
+ ### capnotify_deployment_notification_text
323
+
324
+ This generates a plain-text message, designed for notifying of a completed deployment. It
325
+ will use the built-in template defined by `capnotify_deployment_notification_text_template_path`
326
+ which points to the html template in this gem's `lib/capnotify/templates` directory.
327
+
328
+ ### Components
329
+
330
+ At the core of each of these templates is the concept of Components. These components allow
331
+ for the easy creation of sections in the email to put custom data and as an entry-point for
332
+ extensions to add additional information to the emails/notifications.
333
+
334
+ Each Component has a name which is used to reference it internally for working with
335
+ it directly (i.e. deleting it from the email body or making changes to it after the fact).
336
+ Outside of that, Components have the following properties:
337
+
338
+ *Work in progress...*
339
+
340
+ * header
341
+ * custom css
342
+ * custom css class
343
+ * content
344
+ * Hash
345
+ * Array
346
+ * String
347
+ * custom templates
348
+
349
+ also
350
+
351
+ * appending / prepending components
352
+ * deleting components
353
+ * inserting components
354
+ * getting component by name
355
+ * lazy components
356
+
357
+ ## Extensions
358
+
359
+ Need to write this.
360
+
361
+ ## Contributing
362
+
363
+ 1. Fork it
364
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
365
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
366
+ 4. Push to the branch (`git push origin my-new-feature`)
367
+ 5. Create new Pull Request
368
+
369
+ ## Author
370
+
371
+ Capnotify is &copy; 2013, written and maintained by Spike Grobstein and distributed under
372
+ the MIT license (included in this repository).
373
+
374
+ Homepage: https://github.com/spikegrobstein/capnotify
375
+ Spike Grobstein: me@spike.cx / http://spike.grobste.in
376
+
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/capnotify.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'capnotify/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "capnotify"
8
+ spec.version = Capnotify::VERSION
9
+ spec.authors = ["Spike Grobstein"]
10
+ spec.email = ["me@spike.cx"]
11
+ spec.description = %q{Extensible Capistrano notification system with helpers and sensible default values for common notification tasks.}
12
+ spec.summary = %q{Extensible Capistrano notification system.}
13
+ spec.homepage = "https://github.com/spikegrobstein/capnotify"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency "pry"
25
+ spec.add_development_dependency "awesome_print"
26
+
27
+ spec.add_dependency "capistrano", "~> 2.14.2"
28
+ end
@@ -0,0 +1,88 @@
1
+ module Capnotify
2
+ class Component
3
+
4
+ class TemplateUndefined < StandardError; end
5
+
6
+ attr_accessor :header, :name
7
+
8
+ # the class(s) for this component (as a string)
9
+ attr_accessor :css_class, :custom_css
10
+
11
+ # a block that will configure this instance lazily
12
+ attr_reader :builder
13
+
14
+ attr_accessor :template_path, :renderers
15
+
16
+ attr_accessor :config
17
+
18
+
19
+ def initialize(name, options={}, &block)
20
+ @name = name.to_sym
21
+
22
+ # default stuff
23
+ @template_path = File.join( File.dirname(__FILE__), 'templates' )
24
+
25
+ @renderers = {
26
+ :html => '_component.html.erb',
27
+ :txt => '_component.txt.erb'
28
+ }
29
+
30
+ @header = options[:header]
31
+ @css_class = options[:css_class] || 'section'
32
+ @custom_css = options[:custom_css]
33
+
34
+ if block_given?
35
+ @builder = block
36
+ end
37
+ end
38
+
39
+ # assign the content as new_content
40
+ def content=(new_content)
41
+ @content = new_content
42
+ end
43
+
44
+ def content
45
+ @content
46
+ end
47
+
48
+ def render_content(format)
49
+ begin
50
+ ERB.new( File.open( template_path_for(format) ).read, nil, '%<>' ).result(self.get_binding)
51
+ rescue TemplateUndefined
52
+ ''
53
+ end
54
+ end
55
+
56
+ # return the binding for this object
57
+ # this is needed when embedding ERB templates in each other
58
+ def get_binding
59
+ binding
60
+ end
61
+
62
+ # set the template path for this particular instance
63
+ # the template path is the path to the parent directory of a renderer ERB template
64
+ def template_path_for(format)
65
+ raise TemplateUndefined, "Template for #{ format } is missing!" if @renderers[format].nil?
66
+
67
+ File.join( @template_path, @renderers[format] )
68
+ end
69
+
70
+ # create renderers
71
+ # given a key for the format, provide the name of the ERB template to use to render relative to the template path
72
+ def render_for(renderers={})
73
+ @renderers = @renderers.merge(renderers)
74
+ end
75
+
76
+ # call @builder with self as a param if @builder is present
77
+ # ensure builder is nil
78
+ # then return self
79
+ def build!(config)
80
+ @builder.call(self) unless @builder.nil?
81
+
82
+ @builder = nil
83
+ @config = config
84
+
85
+ return self
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,26 @@
1
+ module Capnotify
2
+ module Plugin
3
+ module Details
4
+
5
+ def init
6
+ capnotify.components << Capnotify::Component.new(:capnotify_details) do |c|
7
+ c.header = 'Deployment Details'
8
+
9
+ c.content = {}
10
+ c.content['Branch'] = fetch(:branch, 'n/a')
11
+ c.content['Sha1'] = fetch(:latest_revision, 'n/a')
12
+ c.content['Release'] = fetch(:release_name, 'n/a')
13
+
14
+ if fetch(:github_url, nil)
15
+ c.content['WWW'] = "#{ fetch(:github_url) }/tree/#{ fetch(:latest_revision) }"
16
+ end
17
+ end
18
+ end
19
+
20
+ def unload
21
+ capnotify.delete_component :capnotify_details
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,23 @@
1
+ module Capnotify
2
+ module Plugin
3
+ module Overview
4
+
5
+ def init
6
+ capnotify.components << Capnotify::Component.new(:capnotify_overview) do |c|
7
+ c.header = 'Deployment Overview'
8
+
9
+ c.content = {}
10
+ c.content['Deployed by'] = 'capnotify.deployed_by'
11
+ c.content['Deployed at'] = Time.now
12
+ c.content['Application'] = fetch(:application, '')
13
+ c.content['Repository'] = fetch(:repository, '')
14
+ end
15
+ end
16
+
17
+ def unload
18
+ capnotify.delete_component :capnotify_overview
19
+ end
20
+
21
+ end
22
+ end
23
+ end