capnotify 0.1.6pre → 0.2.0

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/README.md CHANGED
@@ -24,7 +24,7 @@ is made.
24
24
 
25
25
  Add this line to your application's Gemfile:
26
26
 
27
- gem 'capnotify'
27
+ gem "capnotify", "~> 0.1.6pre"
28
28
 
29
29
  And then execute:
30
30
 
@@ -32,7 +32,7 @@ And then execute:
32
32
 
33
33
  Or install it yourself as:
34
34
 
35
- $ gem install capnotify
35
+ $ gem install capnotify --pre
36
36
 
37
37
  Then, in your `Capfile`, add the following line:
38
38
 
@@ -354,9 +354,14 @@ also
354
354
  * getting component by name
355
355
  * lazy components
356
356
 
357
+ This should probably be in the wiki rather than the readme.
358
+
357
359
  ## Extensions
358
360
 
359
- Need to write this.
361
+ It's possible to write extensions for Capnotify. Typically, these will be used to add new
362
+ components to long messages.
363
+
364
+ Need to write this. This will probably wind up in the wiki instead of here.
360
365
 
361
366
  ## Contributing
362
367
 
data/capnotify.gemspec CHANGED
@@ -24,5 +24,5 @@ Gem::Specification.new do |spec|
24
24
  spec.add_development_dependency "pry"
25
25
  spec.add_development_dependency "awesome_print"
26
26
 
27
- spec.add_dependency "capistrano", "~> 2.14.2"
27
+ spec.add_dependency "capistrano", "~> 2.14"
28
28
  end
data/lib/capnotify.rb CHANGED
@@ -2,6 +2,7 @@ require 'capistrano'
2
2
  require "capnotify/version"
3
3
  require 'capnotify/component'
4
4
  require 'capnotify/plugin'
5
+ require 'capnotify/plugin/message'
5
6
  require 'capnotify/plugin/overview'
6
7
  require 'capnotify/plugin/details'
7
8
 
@@ -10,20 +11,27 @@ module Capnotify
10
11
  config.load do
11
12
  Capistrano.plugin :capnotify, ::Capnotify::Plugin
12
13
 
14
+ # conditionally set a capistrano var if it hasn't been set, yet.
15
+ # this functin was ganked from the built-in capistrano deploy recipe
16
+ # since we can't count on this function being defined, we redefine here.
13
17
  def _cset(name, *args, &block)
14
18
  unless exists?(name)
15
19
  set(name, *args, &block)
16
20
  end
17
21
  end
18
22
 
19
-
20
23
  # some configuration
24
+ # The paths to the built-in templates
25
+ # Set these in your deployment recipes if you want a custom template
26
+ # These paths are used when building the deployment notification emails
21
27
  _cset :capnotify_deployment_notification_html_template_path, capnotify.built_in_template_for('default_notification.html.erb')
22
28
  _cset :capnotify_deployment_notification_text_template_path, capnotify.built_in_template_for('default_notification.txt.erb')
23
29
 
24
30
  # get the name of the user deploying
25
31
  # if using git, this will read that from your git config
26
32
  # otherwise will use the currently logged-in user's name
33
+ # TODO: Support SCM other than git.
34
+ # TODO: Support a method other than `whoami` for getting the user's name
27
35
  _cset(:deployer_username) do
28
36
  if exists?(:scm) && fetch(:scm).to_sym == :git
29
37
  `git config user.name`.chomp
@@ -33,13 +41,17 @@ module Capnotify
33
41
  end
34
42
 
35
43
  # built-in values:
44
+
45
+ # This is the list of components to use for the notification
36
46
  set :capnotify_component_list, []
37
47
 
48
+ # The name of the application. Used in pretty much every built-in message
49
+ # by default, the output should be: "STAGE APPNAME @ BRANCH"
38
50
  # override this to change the default behavior for capnotify.appname
39
51
  _cset(:capnotify_appname) do
40
- name = [ fetch(:application, nil), fetch(:stage, nil) ].compact.join(" ")
52
+ name = [ fetch(:stage, nil), fetch(:application, nil) ].compact.map{|c| c.capitalize}.join(" ")
41
53
  if fetch(:branch, nil)
42
- name = "#{ name } / #{ branch }"
54
+ name = "#{ name } @ #{ branch }"
43
55
  end
44
56
  name
45
57
  end
@@ -78,11 +90,13 @@ module Capnotify
78
90
  end
79
91
 
80
92
  # full email message to notify of deployment (html)
93
+ # when called, will compile the template and return the complete data as a string
81
94
  _cset(:capnotify_deployment_notification_html) do
82
95
  capnotify.build_template( fetch(:capnotify_deployment_notification_html_template_path) )
83
96
  end
84
97
 
85
98
  # full email message to notify of deployment (plain text)
99
+ # when called, will compile the template and return the complete data as a string
86
100
  _cset(:capnotify_deployment_notification_text) do
87
101
  data = capnotify.build_template( fetch(:capnotify_deployment_notification_text_template_path) )
88
102
 
@@ -91,15 +105,20 @@ module Capnotify
91
105
  end
92
106
 
93
107
  # before update_code, fetch the current revision
94
- # this is needed to ensure that no matter when capnotify fetches the commit logs,
108
+ # this is needed to ensure that no matter when capnotify is run, it will have the correct previous (currently deployed) revision
95
109
  # it will have the correct starting point.
96
110
  before 'deploy:update_code' do
97
111
  set :capnotify_previous_revision, fetch(:current_revision, nil) # the revision that's currently deployed at this moment
98
112
  end
99
113
 
100
- # configure the callbacks
101
114
 
102
115
  on(:load) do
116
+ # register the callbacks
117
+ # These callbacks can be disabled by setting the following variables to a truthy value:
118
+ # * capnotify_disable_deploy_hooks
119
+ # * capnotify_disable_migrate_hooks
120
+ # * capnotify_disable_maintenance_hooks
121
+
103
122
  # deploy start/complete
104
123
  unless fetch(:capnotify_disable_deploy_hooks, false)
105
124
  before('deploy') { trigger :deploy_start }
@@ -118,12 +137,15 @@ module Capnotify
118
137
  after('deploy:web:enable') { trigger :maintenance_page_down }
119
138
  end
120
139
 
140
+ # load the default plugins
141
+ # disable loading them by setting capnotify_disable_default_components to a truthy value
121
142
  unless fetch(:capnotify_disable_default_components, false)
122
- capnotify.load_plugin :capnotify_overview, Capnotify::Plugin::Overview
123
- capnotify.load_plugin :capnotify_details, Capnotify::Plugin::Details
143
+ capnotify.load_default_plugins
124
144
  end
125
145
 
126
- capnotify.print_splash
146
+ # prints out a splash screen if capnotify_show_splash is set to true
147
+ # defaults to being silent.
148
+ capnotify.print_splash if fetch(:capnotify_show_splash, false)
127
149
  end
128
150
 
129
151
  end
@@ -45,6 +45,10 @@ module Capnotify
45
45
  @content
46
46
  end
47
47
 
48
+ # FIXME: this should probably leverage Procs for rendering of different types, maybe?
49
+ # that would give a lot of power to a developer who wants a custom format for a plugin (eg XML or JSON)
50
+ # Render the content in the given format using the right built-in template. Returns the content as a string.
51
+ # In the event that there is not a valid template, return an empty string.
48
52
  def render_content(format)
49
53
  begin
50
54
  ERB.new( File.open( template_path_for(format) ).read, nil, '%<>' ).result(self.get_binding)
@@ -4,9 +4,10 @@ require 'pry'
4
4
  module Capnotify
5
5
  module Plugin
6
6
 
7
+ # output a pretty splash screen of the Capnotify logo
8
+ # this can be enabled by setting capnotify_show_splash to a truthy value:
9
+ # set :capnotify_show_splash, true
7
10
  def print_splash
8
- return if fetch(:capnotify_hide_splash, false)
9
-
10
11
  puts <<-SPLASH
11
12
  __________________
12
13
  - --|\\ Deployment /| _____ __ _ ___
@@ -21,16 +22,52 @@ module Capnotify
21
22
  # convenience method for getting the friendly app name
22
23
  # If the stage is specified (the deployment is using multistage), include that.
23
24
  # given that the application is "MyApp" and the stage is "production", this will return "MyApp production"
25
+ # if capnotify_appname is not set, it'll return an empty string
24
26
  def appname
25
27
  fetch(:capnotify_appname, "")
26
28
  end
27
29
 
28
- def load_plugin(name, mod)
29
- Capistrano.plugin name, mod
30
+ # get the name of the deploying user
31
+ # currently this only supports git.
32
+ # if reading the git user.name, fall back on `whoami`
33
+ def deployed_by
34
+ username = nil
35
+
36
+ scm = fetch(:scm, nil)
37
+
38
+ if scm
39
+ if scm.to_sym == :git
40
+ username = `git config user.name`.chomp
41
+ username = nil if $? != 0 || username.strip == ''
42
+ end
43
+ end
44
+
45
+ username || `whoami`.chomp
46
+ end
47
+
48
+ # load the default built-in plugins
49
+ # this is called automatically when capistrano is done loading
50
+ # you can disable this (and not laod any plugins by default) by setting capnotify_disable_default_components
51
+ # set :capnotify_disable_default_components, true
52
+ def load_default_plugins
53
+ capnotify.load_plugin Capnotify::Plugin::Message
54
+ capnotify.load_plugin Capnotify::Plugin::Overview
55
+ capnotify.load_plugin Capnotify::Plugin::Details
56
+ end
57
+
58
+ # given a module name, load it as a plugin
59
+ # capnotify plugins must conform to the spec. See docs for info.
60
+ # mod should be the module itself, eg:
61
+ # capnotify.load_plugin Capnotify::Plugin::Message
62
+ def load_plugin(mod)
63
+ Capistrano.plugin mod::PLUGIN_NAME, mod
30
64
 
31
- get_plugin(name).init
65
+ get_plugin(mod::PLUGIN_NAME).init
32
66
  end
33
67
 
68
+ # given a plugin name as a symbol, unload the capnotify plugin
69
+ # this will also unload any kind of capistrano plugin
70
+ # if the plugin supports the unload method, it will be called.
34
71
  def unload_plugin(name)
35
72
  p = get_plugin(name)
36
73
 
@@ -38,6 +75,7 @@ module Capnotify
38
75
  Capistrano.remove_plugin(name)
39
76
  end
40
77
 
78
+ # given a plugin name, return the plugin.
41
79
  def get_plugin(name)
42
80
  raise "Unknown plugin: #{ name }" unless Capistrano::EXTENSIONS.keys.include?(name)
43
81
  self.send(name)
@@ -2,8 +2,10 @@ module Capnotify
2
2
  module Plugin
3
3
  module Details
4
4
 
5
+ PLUGIN_NAME = :capnotify_details
6
+
5
7
  def init
6
- capnotify.components << Capnotify::Component.new(:capnotify_details) do |c|
8
+ capnotify.components << Capnotify::Component.new(PLUGIN_NAME) do |c|
7
9
  c.header = 'Deployment Details'
8
10
 
9
11
  c.content = {}
@@ -18,7 +20,7 @@ module Capnotify
18
20
  end
19
21
 
20
22
  def unload
21
- capnotify.delete_component :capnotify_details
23
+ capnotify.delete_component PLUGIN_NAME
22
24
  end
23
25
 
24
26
  end
@@ -0,0 +1,33 @@
1
+ # Capnotify built-in plugin for Custom messages in email
2
+ # This adds a "message" section that will include 'notification_msg' if it's set
3
+ # For example:
4
+ # cap deploy -s notification_msg="Just getting a hotfix deployed"
5
+ module Capnotify
6
+ module Plugin
7
+ module Message
8
+
9
+ # the plugin's name (how it's referenced once it's loaded)
10
+ PLUGIN_NAME = :capnotify_message
11
+
12
+ # initialize the plugin
13
+ def init
14
+ # add a component tagged with this plugin's name
15
+ capnotify.components << Capnotify::Component.new(PLUGIN_NAME) do |c|
16
+ # the header
17
+ c.header = 'Message'
18
+
19
+ # the content
20
+ # if notification_msg isn't set, content will be set to nil
21
+ # nil content will prevent the section from being rendered.
22
+ c.content = fetch(:notification_msg, nil)
23
+ end
24
+ end
25
+
26
+ # delete the component when this plugin is unloaded
27
+ def unload
28
+ capnotify.delete_component PLUGIN_NAME
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -2,22 +2,25 @@ module Capnotify
2
2
  module Plugin
3
3
  module Overview
4
4
 
5
+ PLUGIN_NAME = :capnotify_overview
6
+
5
7
  def init
6
- capnotify.components << Capnotify::Component.new(:capnotify_overview) do |c|
8
+ capnotify.components << Capnotify::Component.new(PLUGIN_NAME) do |c|
7
9
  c.header = 'Deployment Overview'
8
10
 
9
11
  c.content = {}
10
- c.content['Deployed by'] = 'capnotify.deployed_by'
12
+ c.content['Deployed by'] = capnotify.deployed_by
11
13
  c.content['Deployed at'] = Time.now
12
- c.content['Application'] = fetch(:application, '')
13
- c.content['Repository'] = fetch(:repository, '')
14
+ c.content['Application'] = fetch(:application, 'n/a')
15
+ c.content['Repository'] = fetch(:repository, 'n/a')
14
16
  end
15
17
  end
16
18
 
17
19
  def unload
18
- capnotify.delete_component :capnotify_overview
20
+ capnotify.delete_component PLUGIN_NAME
19
21
  end
20
22
 
23
+
21
24
  end
22
25
  end
23
26
  end
@@ -64,6 +64,7 @@
64
64
  </h1>
65
65
 
66
66
  <% capnotify.components.each do |component| %>
67
+ <% next if component.content.nil? %>
67
68
  <div class="<%= component.css_class %>">
68
69
  <h2><%= component.header %></h2>
69
70
 
@@ -1,7 +1,8 @@
1
1
  <%= capnotify.appname %> deployment completed!
2
2
 
3
3
  <% capnotify.components.each do |component| %>
4
- --- <%= @header %> ---
4
+ <% next if component.content.nil? %>
5
+ --- <%= component.header %> ---
5
6
  <%= component.render_content(:txt) %>
6
7
  <% end %>
7
8
 
@@ -1,3 +1,3 @@
1
1
  module Capnotify
2
- VERSION = "0.1.6pre"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -19,6 +19,9 @@ describe Capnotify::Plugin do
19
19
  # a plugin for testing with
20
20
  # wires up init and unload to the ProxyObject
21
21
  module MyPlugin
22
+
23
+ PLUGIN_NAME = :my_plugin
24
+
22
25
  def init
23
26
  ProxyObject.instance.call_init
24
27
  end
@@ -65,7 +68,7 @@ describe Capnotify::Plugin do
65
68
 
66
69
  it "should load the plugin into capistrano" do
67
70
  config.load do
68
- capnotify.load_plugin :my_plugin, MyPlugin
71
+ capnotify.load_plugin MyPlugin
69
72
  end
70
73
 
71
74
  Capistrano::EXTENSIONS.keys.should include(:my_plugin)
@@ -75,7 +78,7 @@ describe Capnotify::Plugin do
75
78
  ProxyObject.instance.should_receive :call_init
76
79
 
77
80
  config.load do
78
- capnotify.load_plugin :my_plugin, MyPlugin
81
+ capnotify.load_plugin MyPlugin
79
82
  end
80
83
 
81
84
  end
@@ -86,7 +89,7 @@ describe Capnotify::Plugin do
86
89
 
87
90
  before do
88
91
  config.load do
89
- capnotify.load_plugin :my_plugin, MyPlugin
92
+ capnotify.load_plugin MyPlugin
90
93
  end
91
94
  end
92
95
 
@@ -115,7 +118,7 @@ describe Capnotify::Plugin do
115
118
  context "when plugin exists" do
116
119
  before do
117
120
  config.load do
118
- capnotify.load_plugin :my_plugin, MyPlugin
121
+ capnotify.load_plugin MyPlugin
119
122
  end
120
123
  end
121
124
 
@@ -149,6 +152,44 @@ describe Capnotify::Plugin do
149
152
  lambda { capnotify.build_template( capnotify.built_in_template_for('default_notification.txt.erb') ) }.should_not raise_error
150
153
  end
151
154
 
155
+ context "when building templates with components" do
156
+
157
+ let(:html_rendered_template) { capnotify.build_template( capnotify.built_in_template_for('default_notification.html.erb') ) }
158
+ let(:text_rendered_template) { capnotify.build_template( capnotify.built_in_template_for('default_notification.txt.erb') ) }
159
+
160
+ before do
161
+ capnotify.load_default_plugins
162
+ capnotify.components.count.should > 0
163
+ end
164
+
165
+ context "html templates" do
166
+ it "should not render components with no content" do
167
+ html_rendered_template.should_not match(/Message/) # the header
168
+ end
169
+
170
+ it "should render components with content" do
171
+ config.set :notification_msg, 'ASDFASDF'
172
+
173
+ html_rendered_template.should match(/Message/) # the header
174
+ html_rendered_template.should match(/ASDFASDF/) # the content
175
+ end
176
+ end
177
+
178
+ context "text templates" do
179
+ it "should not render components with no content" do
180
+ text_rendered_template.should_not match(/Message/) # the header
181
+ end
182
+
183
+ it "should render components with content" do
184
+ config.set :notification_msg, 'ASDFASDF'
185
+
186
+ text_rendered_template.should match(/Message/) # the header
187
+ text_rendered_template.should match(/ASDFASDF/) # the content
188
+ end
189
+ end
190
+
191
+ end
192
+
152
193
  end
153
194
 
154
195
  context "#components" do
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capnotify
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6pre
5
- prerelease: 5
4
+ version: 0.2.0
5
+ prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Spike Grobstein
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-03 00:00:00.000000000 Z
12
+ date: 2013-06-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -98,7 +98,7 @@ dependencies:
98
98
  requirements:
99
99
  - - ~>
100
100
  - !ruby/object:Gem::Version
101
- version: 2.14.2
101
+ version: '2.14'
102
102
  type: :runtime
103
103
  prerelease: false
104
104
  version_requirements: !ruby/object:Gem::Requirement
@@ -106,7 +106,7 @@ dependencies:
106
106
  requirements:
107
107
  - - ~>
108
108
  - !ruby/object:Gem::Version
109
- version: 2.14.2
109
+ version: '2.14'
110
110
  description: Extensible Capistrano notification system with helpers and sensible default
111
111
  values for common notification tasks.
112
112
  email:
@@ -127,6 +127,7 @@ files:
127
127
  - lib/capnotify/component.rb
128
128
  - lib/capnotify/plugin.rb
129
129
  - lib/capnotify/plugin/details.rb
130
+ - lib/capnotify/plugin/message.rb
130
131
  - lib/capnotify/plugin/overview.rb
131
132
  - lib/capnotify/templates/_component.html.erb
132
133
  - lib/capnotify/templates/_component.txt.erb
@@ -150,12 +151,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
150
151
  - - ! '>='
151
152
  - !ruby/object:Gem::Version
152
153
  version: '0'
154
+ segments:
155
+ - 0
156
+ hash: -27722869543230501
153
157
  required_rubygems_version: !ruby/object:Gem::Requirement
154
158
  none: false
155
159
  requirements:
156
- - - ! '>'
160
+ - - ! '>='
157
161
  - !ruby/object:Gem::Version
158
- version: 1.3.1
162
+ version: '0'
163
+ segments:
164
+ - 0
165
+ hash: -27722869543230501
159
166
  requirements: []
160
167
  rubyforge_project:
161
168
  rubygems_version: 1.8.24
@@ -167,4 +174,3 @@ test_files:
167
174
  - spec/capnotify/plugin_spec.rb
168
175
  - spec/capnotify_spec.rb
169
176
  - spec/spec_helper.rb
170
- has_rdoc: