capnotify 0.1.0pre

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.
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