deployment_notifier 1.0.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/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Jon Wood
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,21 @@
1
+ = deployment_notifier
2
+
3
+ A plugin for Capistrano to send out notification e-mails on deployment.
4
+
5
+ I'm aware of cap_gun, but that attempts to send the e-mails locally, which is
6
+ no good in an environment where we don't have local SMTP servers.
7
+
8
+ == Note on Patches/Pull Requests
9
+
10
+ * Fork the project.
11
+ * Make your feature addition or bug fix.
12
+ * Add tests for it. This is important so I don't break it in a
13
+ future version unintentionally.
14
+ * Commit, do not mess with rakefile, version, or history.
15
+ (if you want to have your own version, that is fine but
16
+ bump version in a commit by itself I can ignore when I pull)
17
+ * Send me a pull request. Bonus points for topic branches.
18
+
19
+ == Copyright
20
+
21
+ Copyright (c) 2009 Jon Wood. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,54 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "deployment_notifier"
8
+ gem.summary = %Q{Deployment notifications for Capistrano}
9
+ gem.description = %Q{A plugin for Capistrano to send an e-mail to notify people about deployments.}
10
+ gem.email = "jon@blankpad.net"
11
+ gem.homepage = "http://github.com/jellybob/deployment_notifier"
12
+ gem.authors = ["Jon Wood"]
13
+ gem.add_development_dependency "rspec"
14
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
+ end
16
+ rescue LoadError
17
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
18
+ end
19
+
20
+ begin
21
+ require 'spec/rake/spectask'
22
+
23
+ desc "Run all specs"
24
+ Spec::Rake::SpecTask.new('spec') do |t|
25
+ t.libs = [ 'lib' ]
26
+ t.spec_files = FileList['spec/**/*_spec.rb']
27
+ end
28
+
29
+ desc "Run all specs, with coverage"
30
+ Spec::Rake::SpecTask.new('spec:coverage') do |t|
31
+ t.libs = [ 'lib' ]
32
+ t.spec_files = FileList['spec/**/*_spec.rb']
33
+ t.rcov = true
34
+ t.rcov_opts = ['--exclude', 'spec,osx\/objc,gems\/']
35
+ end
36
+ rescue LoadError
37
+ puts "RSpec and RCov are required to run tests. Install it with: sudo gem install rspec rcov"
38
+ end
39
+
40
+ task :default => :spec
41
+
42
+ require 'rake/rdoctask'
43
+ Rake::RDocTask.new do |rdoc|
44
+ if File.exist?('VERSION')
45
+ version = File.read('VERSION')
46
+ else
47
+ version = ""
48
+ end
49
+
50
+ rdoc.rdoc_dir = 'rdoc'
51
+ rdoc.title = "deployment_notifier #{version}"
52
+ rdoc.rdoc_files.include('README*')
53
+ rdoc.rdoc_files.include('lib/**/*.rb')
54
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,53 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{deployment_notifier}
8
+ s.version = "1.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Jon Wood"]
12
+ s.date = %q{2009-10-05}
13
+ s.description = %q{A plugin for Capistrano to send an e-mail to notify people about deployments.}
14
+ s.email = %q{jon@blankpad.net}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "deployment_notifier.gemspec",
27
+ "lib/blankpad/deployment_notifier.rb",
28
+ "spec/blankpad/deployment_notifier_spec.rb",
29
+ "spec/spec_helper.rb"
30
+ ]
31
+ s.homepage = %q{http://github.com/jellybob/deployment_notifier}
32
+ s.rdoc_options = ["--charset=UTF-8"]
33
+ s.require_paths = ["lib"]
34
+ s.rubygems_version = %q{1.3.5}
35
+ s.summary = %q{Deployment notifications for Capistrano}
36
+ s.test_files = [
37
+ "spec/blankpad/deployment_notifier_spec.rb",
38
+ "spec/spec_helper.rb"
39
+ ]
40
+
41
+ if s.respond_to? :specification_version then
42
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
43
+ s.specification_version = 3
44
+
45
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
46
+ s.add_development_dependency(%q<rspec>, [">= 0"])
47
+ else
48
+ s.add_dependency(%q<rspec>, [">= 0"])
49
+ end
50
+ else
51
+ s.add_dependency(%q<rspec>, [">= 0"])
52
+ end
53
+ end
@@ -0,0 +1,106 @@
1
+ require 'etc'
2
+
3
+ module Blankpad
4
+ # A Capistrano plugin to send deployment notifications
5
+ module DeploymentNotifier
6
+ VERSION = File.read(File.dirname(__FILE__) + "/../../VERSION").strip.split(".")
7
+
8
+ @@recipients = []
9
+ def self.recipients
10
+ @@recipients
11
+ end
12
+
13
+ def self.recipients=(recipients)
14
+ @@recipients = recipients
15
+ end
16
+
17
+ @@from = ""
18
+ def self.from
19
+ @@from
20
+ end
21
+
22
+ def self.from=(from)
23
+ @@from = from
24
+ end
25
+
26
+ def self.deployer
27
+ Etc.getlogin
28
+ end
29
+
30
+ # Responsible for taking the e-mail to send, and sending it using the remote
31
+ # server's sendmail command.
32
+ class Mailer
33
+ attr_reader :capistrano
34
+
35
+ def initialize(capistrano)
36
+ @capistrano = capistrano
37
+ end
38
+
39
+ # Delivers a notification e-mail
40
+ def deliver!
41
+ capistrano.run(delivery_command)
42
+ end
43
+
44
+ # Constructs the final command which will be sent run on the server.
45
+ def delivery_command
46
+ "echo -en '#{message}' | #{mta_command}"
47
+ end
48
+
49
+ def mta_command
50
+ "/usr/sbin/sendmail #{DeploymentNotifier.recipients.join(" ")}"
51
+ end
52
+
53
+ def message
54
+ Message.new(capistrano, Blankpad::DeploymentNotifier.deployer).to_s.gsub(/\n/, "\\n")
55
+ end
56
+ end
57
+
58
+ class Message
59
+ attr_reader :capistrano
60
+
61
+ def initialize(capistrano, deployer)
62
+ @capistrano = capistrano
63
+ @deployer = deployer
64
+ end
65
+
66
+ def headers
67
+ {
68
+ "Subject" => "[DEPLOY] #{capistrano[:application]} #{capistrano[:stage]}",
69
+ "From" => DeploymentNotifier.from,
70
+ "To" => DeploymentNotifier.recipients.join(", "),
71
+ "X-Mailer" => "DeploymentNotifier"
72
+ }
73
+ end
74
+
75
+ def body
76
+ body = <<EOM
77
+ #{@deployer} has deployed revision #{capistrano[:current_revision]} of #{capistrano[:application]} to #{capistrano[:stage]}
78
+
79
+ Application: #{capistrano[:application]}
80
+ Stage: #{capistrano[:stage]}
81
+ Repository: #{capistrano[:repository]}
82
+ Current Revision: #{capistrano[:current_revision]}
83
+ Previous revision: #{capistrano[:previous_revision]}
84
+ EOM
85
+ body = capistrano[:message] + "\n\n#{body}" if capistrano[:message]
86
+
87
+ body
88
+ end
89
+
90
+ def to_s
91
+ headers.collect { |key, value| "#{key}: #{value}" }.join("\n") << "\n\n#{body}"
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ if Object.const_defined?("Capistrano")
98
+ Capistrano::Configuration.instance(:must_exist).load do
99
+ namespace "deploy" do
100
+ desc "Send a notification e-mail to people who want one"
101
+ task :notify do
102
+ Blankpad::DeploymentNotifier::Mailer.new(self).deliver!
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,209 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe Blankpad::DeploymentNotifier do
4
+ describe "the version number" do
5
+ it "should not be nil" do
6
+ Blankpad::DeploymentNotifier::VERSION.should_not be_nil
7
+ end
8
+
9
+ it "should be a three element array" do
10
+ Blankpad::DeploymentNotifier::VERSION.should have(3).items
11
+ end
12
+
13
+ it "should be the same as the contents of VERSION" do
14
+ expected_version = File.read(File.dirname(__FILE__) + "/../../VERSION").strip.split(".")
15
+ Blankpad::DeploymentNotifier::VERSION.should eql(expected_version)
16
+ end
17
+ end
18
+
19
+ describe "configuration" do
20
+ it "should allow the recipients list to be set and retriveed" do
21
+ Blankpad::DeploymentNotifier.should respond_to(:recipients)
22
+ Blankpad::DeploymentNotifier.should respond_to(:recipients=)
23
+ end
24
+
25
+ it "should return the same set of recipients" do
26
+ recipients = [ "one@example.org" ]
27
+
28
+ Blankpad::DeploymentNotifier.recipients = recipients
29
+ Blankpad::DeploymentNotifier.recipients.should eql(recipients)
30
+ end
31
+
32
+ it "should allow the from address to be set and retrieved" do
33
+ from = "Example Deployer <deploy@example.org>"
34
+
35
+ Blankpad::DeploymentNotifier.from = from
36
+ Blankpad::DeploymentNotifier.from.should eql(from)
37
+ end
38
+
39
+ it "should allow the person deploying to be retrieved" do
40
+ Etc.stub!(:getlogin).and_return("jon")
41
+ Blankpad::DeploymentNotifier.deployer.should eql("jon")
42
+ end
43
+ end
44
+
45
+ describe "the mailer" do
46
+ before(:each) do
47
+ @capistrano = mock("Capistrano")
48
+ @mailer = Blankpad::DeploymentNotifier::Mailer.new(@capistrano)
49
+ end
50
+
51
+ it "should provide a way of accessing the Capistrano instance" do
52
+ @mailer.should respond_to(:capistrano)
53
+ end
54
+
55
+ it "should use the first argument as a Cap instance" do
56
+ @mailer.capistrano.should eql(@capistrano)
57
+ end
58
+
59
+ describe "mail delivery" do
60
+ it "provide a method to deliver notification e-mails" do
61
+ @mailer.should respond_to(:deliver!)
62
+ end
63
+
64
+ it "should have a method which builds the delivery command" do
65
+ @mailer.should respond_to(:delivery_command)
66
+ end
67
+
68
+ it "should run the delivery command with deliver! is called, and pass the result to run" do
69
+ @mailer.should_receive(:delivery_command).and_return("")
70
+ @capistrano.should_receive(:run).with("")
71
+
72
+ @mailer.deliver!
73
+ end
74
+
75
+ describe "the delivery command" do
76
+ it "should be made up of a message, which is piped to the MTA" do
77
+ @mailer.should_receive(:message).and_return("The message")
78
+ @mailer.should_receive(:mta_command).and_return("/usr/sbin/sendmail null@example.org")
79
+
80
+ @mailer.delivery_command.should eql("echo -en 'The message' | /usr/sbin/sendmail null@example.org")
81
+ end
82
+ end
83
+
84
+ it "should have a method to retrieve the MTA command" do
85
+ @mailer.should respond_to(:mta_command)
86
+ end
87
+
88
+ describe "the mta command" do
89
+ it "should be sendmail, followed by a space seperated list of recipients" do
90
+ Blankpad::DeploymentNotifier.recipients = %w[one@example.org two@example.org]
91
+
92
+ @mailer.mta_command.should eql('/usr/sbin/sendmail one@example.org two@example.org')
93
+ end
94
+ end
95
+
96
+ it "should have a method to retrieve the message to send" do
97
+ @mailer.should respond_to(:message)
98
+ end
99
+
100
+ describe "the message method" do
101
+ it "should create a new Message object, and return it's string representation" do
102
+ message = mock("a message")
103
+ message.should_receive(:to_s).and_return("the message to send")
104
+
105
+ Blankpad::DeploymentNotifier::Message.stub!(:new).and_return(message)
106
+ @mailer.message
107
+ end
108
+
109
+ it "should escape any newline characters" do
110
+ message = mock("a message")
111
+ message.should_receive(:to_s).and_return("the message to send\n")
112
+
113
+ Blankpad::DeploymentNotifier::Message.stub!(:new).and_return(message)
114
+ @mailer.message.should match(/\\n/)
115
+ end
116
+ end
117
+ end
118
+ end
119
+
120
+ describe "a message" do
121
+ before(:each) do
122
+ @capistrano = stub("Capistrano")
123
+ @message = Blankpad::DeploymentNotifier::Message.new(@capistrano, "deployer")
124
+ end
125
+
126
+ def add_property(name, value)
127
+ @capistrano.stub!(:[]).with(name).and_return(value)
128
+ end
129
+
130
+ it "should have a method to retreive the headers" do
131
+ @message.should respond_to(:headers)
132
+ end
133
+
134
+ describe "the message headers" do
135
+ before(:each) do
136
+ add_property(:application, "application_name")
137
+ add_property(:stage, "stage")
138
+ end
139
+
140
+ it "should set the subject to '[DEPLOY] application_name stage' by default" do
141
+ @message.headers["Subject"].should eql("[DEPLOY] application_name stage")
142
+ end
143
+
144
+ it "should set the from address to the one configured" do
145
+ Blankpad::DeploymentNotifier.from = "Deployment Notifier <deploy@example.org>"
146
+
147
+ @message.headers["From"].should eql("Deployment Notifier <deploy@example.org>")
148
+ end
149
+
150
+ it "should set the mailer to 'DeploymentNotifier'" do
151
+ @message.headers["X-Mailer"].should eql("DeploymentNotifier")
152
+ end
153
+
154
+ it "should set the to address to the recipients" do
155
+ Blankpad::DeploymentNotifier.recipients = ["One <one@example.org>", "Two <two@example.org>"]
156
+ @message.headers["To"].should eql("One <one@example.org>, Two <two@example.org>")
157
+ end
158
+ end
159
+
160
+ it "should have a method to retrieve the message body" do
161
+ @message.should respond_to(:body)
162
+ end
163
+
164
+ describe "the message body" do
165
+ properties = {
166
+ :application => "application_name",
167
+ :stage => "stage",
168
+ :repository => "git://github.com/example/example_org.git",
169
+ :current_revision => "f8ds98f0sd8f0sd8",
170
+ :previous_revision => "f9s8fsd8f0sd0sdf"
171
+ }
172
+
173
+ before(:each) do
174
+ @capistrano.stub!(:[]).and_return(nil)
175
+ properties.each do |name, value|
176
+ add_property(name, value)
177
+ end
178
+
179
+ Etc.stub!(:getlogin).and_return("deployer")
180
+ end
181
+
182
+ it "should include a summary" do
183
+ @message.body.should match(/deployer has deployed revision f8ds98f0sd8f0sd8 of application_name to stage/i)
184
+ end
185
+
186
+ properties.each do |name, value|
187
+ it "should include the #{name} property" do
188
+ @message.body.should match(/#{name.to_s.gsub("_", " ")}: #{value}/i)
189
+ end
190
+ end
191
+
192
+ it "should include the explanation when a message has been set" do
193
+ add_property :message, "Because I feel like it."
194
+
195
+ @message.body.should match(/Because I feel like it./)
196
+ end
197
+ end
198
+
199
+ it "should return the full message with headers on to_s" do
200
+ @message.stub!(:headers).and_return({"One" => "Header 1", "Two" => "Header 2"})
201
+ @message.stub!(:body).and_return("The body")
202
+
203
+ @message.to_s.should eql(%Q{One: Header 1
204
+ Two: Header 2
205
+
206
+ The body})
207
+ end
208
+ end
209
+ end
@@ -0,0 +1 @@
1
+ require 'blankpad/deployment_notifier'
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: deployment_notifier
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jon Wood
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-05 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description: A plugin for Capistrano to send an e-mail to notify people about deployments.
26
+ email: jon@blankpad.net
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - LICENSE
33
+ - README.rdoc
34
+ files:
35
+ - .document
36
+ - .gitignore
37
+ - LICENSE
38
+ - README.rdoc
39
+ - Rakefile
40
+ - VERSION
41
+ - deployment_notifier.gemspec
42
+ - lib/blankpad/deployment_notifier.rb
43
+ - spec/blankpad/deployment_notifier_spec.rb
44
+ - spec/spec_helper.rb
45
+ has_rdoc: true
46
+ homepage: http://github.com/jellybob/deployment_notifier
47
+ licenses: []
48
+
49
+ post_install_message:
50
+ rdoc_options:
51
+ - --charset=UTF-8
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ version:
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ version:
66
+ requirements: []
67
+
68
+ rubyforge_project:
69
+ rubygems_version: 1.3.5
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: Deployment notifications for Capistrano
73
+ test_files:
74
+ - spec/blankpad/deployment_notifier_spec.rb
75
+ - spec/spec_helper.rb