release_party 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ require 'release_party/release_party'
@@ -0,0 +1,57 @@
1
+ require File.join(File.dirname(__FILE__), 'release_file')
2
+
3
+ class Environment
4
+
5
+ def initialize
6
+ @attributes = {}
7
+ load_defaults
8
+ end
9
+
10
+ def method_missing(method_id, *args, &block)
11
+ case method_id.to_s
12
+ when /\A(.*)=\Z/
13
+ @attributes[$1.to_sym] = args.first
14
+
15
+ when /\A(.*)\?\Z/
16
+ @attributes.key?($1.to_sym)
17
+
18
+ else
19
+ unless @attributes.key?(method_id)
20
+ raise ArgumentError, "No value for #{method_id} defined"
21
+ end
22
+ value = @attributes[method_id.to_sym]
23
+ return value.call if value.is_a?(Proc)
24
+ value
25
+
26
+ end
27
+ end
28
+
29
+ def load_release_file
30
+ # Process the Releasefile and merge the attributes loaded
31
+ release_file = ReleaseFile.new
32
+ @attributes = @attributes.merge release_file.attributes
33
+ end
34
+
35
+ def load_capistrano_defaults(cap_config)
36
+ # General cap info
37
+ self.user = cap_config.fetch(:user, `git config user.name`.chomp)
38
+ self.branch = cap_config.fetch(:branch, 'master')
39
+ self.stage = cap_config.fetch(:stage, 'staging')
40
+ self.repository = cap_config.fetch(:repository, nil)
41
+ self.domain = cap_config.fetch(:domain, nil)
42
+ self.display_name = cap_config.fetch(:display_name, 'Release Party')
43
+ end
44
+
45
+ def load_defaults
46
+ self.from_address = 'Release Party <releaseparty@noreply.org>'
47
+ self.smtp_address = 'localhost'
48
+ self.smtp_port = 25
49
+ self.subject = Proc.new {"A release of #{display_name} was released to #{domain}"}
50
+ self.finished_stories = []
51
+ self.known_bugs = []
52
+ self.send_email = true
53
+ self.template_engine = :haml
54
+ self.deliver_stories = false
55
+ end
56
+
57
+ end
@@ -0,0 +1,22 @@
1
+ class ReleaseFile
2
+
3
+ RELEASE_FILE = 'Releasefile'
4
+
5
+ attr_reader :attributes
6
+
7
+ def initialize
8
+ @attributes = {}
9
+
10
+ capfile_path = File.join(Dir.pwd, RELEASE_FILE)
11
+ if File.exists?(capfile_path)
12
+ eval File.read(capfile_path)
13
+ else
14
+ puts "Warning: No #{RELEASE_FILE} found, you should put one in your project root."
15
+ end
16
+ end
17
+
18
+ def method_missing(method_id, *args, &block)
19
+ @attributes[method_id.to_sym] = args.first || block
20
+ end
21
+
22
+ end
@@ -0,0 +1,202 @@
1
+ require 'capistrano'
2
+ require 'pivotal-tracker'
3
+ require 'mail'
4
+ require 'grit'
5
+
6
+ require File.join(File.dirname(__FILE__), 'environment')
7
+
8
+ module Capistrano::ReleaseParty
9
+
10
+ def self.extended(configuration)
11
+ configuration.load do
12
+
13
+ after 'deploy', 'release_party:finished'
14
+
15
+ namespace 'release_party' do
16
+ task 'started' do
17
+ @env = Environment.new
18
+
19
+ # Record when the release began
20
+ @env.release_started = Time.now
21
+
22
+ @env.load_capistrano_defaults(self)
23
+ @env.load_release_file
24
+
25
+ announce "beginning deployment, project details obtained."
26
+
27
+ load_git_progress @env
28
+ load_tracker_progress @env
29
+ end
30
+
31
+ task 'finished' do
32
+ raise ArgumentError, "Release finished without being started" if @env.nil?
33
+
34
+ begin
35
+ announce "celebrating release, deployment finished successfully!"
36
+
37
+ # Record when the release finished
38
+ @env.release_finished = Time.now
39
+
40
+
41
+ # Do pivotal story delivery
42
+ if @env.deliver_stories
43
+ commit_tracker_progress @env
44
+ end
45
+
46
+ # Send an email notification
47
+ if @env.send_email
48
+ body = load_email_content @env
49
+ deliver_notification(@env, body)
50
+ end
51
+
52
+ #rescue ArgumentError => error
53
+ # puts "ERROR: #{error.message}"
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ def commit_tracker_progress(env)
61
+ # Go through each finished story id we've seen in the git repo
62
+ # and deliver each story that is marked as finished
63
+ env.finished_store_ids.each do |story_id|
64
+
65
+ end
66
+ end
67
+
68
+ def load_git_progress(env)
69
+ #repo = Grit::Repo.new(Dir.pwd)
70
+ repo = Grit::Repo.new("/Users/john/Projects/breeze")
71
+ config = Grit::Config.new(repo)
72
+
73
+ feature_branch = config.fetch('gitflow.prefix.feature', 'feature/')
74
+ release_branch = config.fetch('gitflow.prefix.release', 'release/')
75
+ puts "Feature branch: #{feature_branch}"
76
+ puts "Release branch: #{release_branch}"
77
+
78
+ # Find the last release
79
+ latest_release = \
80
+ repo.commits('master').find do |commit|
81
+ commit.message =~ /\AMerge branch '#{release_branch}(\d+)/
82
+ end
83
+ latest_release_tag = $1
84
+
85
+ puts "Commit: #{latest_release} #{latest_release.message}"
86
+ previous_release = \
87
+ repo.commits('master', 100).find do |commit|
88
+ if commit.message =~ /\AMerge branch '#{release_branch}(\d+)/
89
+ latest_release_tag != $1
90
+ end
91
+ end
92
+ previous_release_tag = $1
93
+ puts "Commit: #{previous_release} #{previous_release.message}"
94
+
95
+ env.finished_story_ids =
96
+ repo.commits('develop').collect do |commit|
97
+ $1 if commit.message =~ /\AMerge branch '#{feature_branch}(\d+)/
98
+ end.compact
99
+ puts env.finished_story_ids
100
+ end
101
+
102
+ def load_email_content(env)
103
+ arguments_required env, :template_engine, :template
104
+
105
+ template = env.template
106
+ raise ArgumentError, "Missing template file #{template}" unless File.exists?(template)
107
+
108
+ engine = \
109
+ case env.template_engine
110
+ when :haml
111
+ load_haml
112
+ Haml::Engine.new(File.read(template))
113
+
114
+ when :erb
115
+ load_erb
116
+ ERB.new(File.read(template))
117
+
118
+ else
119
+ raise ArgumentError, "Unsupported template engine #{env.template_engine}"
120
+ end
121
+
122
+ engine.render env
123
+ end
124
+
125
+ def load_tracker_progress(env)
126
+ arguments_required env, :project_id, :project_api_key
127
+
128
+ PivotalTracker::Client.token = env.project_api_key
129
+
130
+ begin
131
+ env.project = PivotalTracker::Project.find(env.project_id)
132
+ rescue RestClient::Request::Unauthorized => e
133
+ puts 'Unable to authenticate with pivotal, perhaps your API key is wrong.' +
134
+ "Message: #{e.message}"
135
+ end
136
+
137
+ env.instance_eval do
138
+ self.finished_stories = \
139
+ project.stories.all(:state => 'finished')
140
+ self.known_bugs = \
141
+ project.stories.all(:state => ['unstarted', 'started'], :story_type => 'bug')
142
+ end
143
+ end
144
+
145
+ def deliver_notification(env, body)
146
+ arguments_required env,
147
+ :smtp_address, :smtp_port, :smtp_domain, :from_address,
148
+ :email_notification_to, :subject
149
+
150
+ Mail.defaults do
151
+ delivery_method :smtp,
152
+ :address => env.smtp_address,
153
+ :port => env.smtp_port,
154
+ :domain => env.smtp_domain
155
+ end
156
+ announce "delivering deployment notice to #{env.email_notification_to.inspect}"
157
+ Mail.deliver do
158
+ from env.from_address
159
+ to env.email_notification_to
160
+ subject env.subject
161
+ html_part do
162
+ content_type 'text/html; charset=UTF-8'
163
+ body body
164
+ end
165
+ end
166
+ announce "deployment notice sent!"
167
+ end
168
+
169
+ def announce(message)
170
+ puts "ReleaseParty: #{message}"
171
+ end
172
+
173
+ def arguments_required(env, *arguments)
174
+ missing = arguments.reject do |argument|
175
+ env.send("#{argument}?".to_sym)
176
+ end
177
+ unless missing.empty?
178
+ raise ArgumentError, "Parameters #{missing.join(', ')} must be defined"
179
+ end
180
+ end
181
+
182
+ def load_haml
183
+ require 'haml'
184
+ rescue LoadError => error
185
+ raise ArgumentError,
186
+ 'Unable to load HAML, you need to make sure the haml gem is installed '
187
+ 'if it is specified as the template engine'
188
+ end
189
+
190
+ def load_erb
191
+ require 'erb'
192
+ rescue LoadError => error
193
+ raise ArgumentError,
194
+ 'Unable to load ERB, you need to make sure the erb gem is installed '
195
+ 'if it is specified as the template engine'
196
+ end
197
+
198
+ end
199
+
200
+ if Capistrano::Configuration.instance
201
+ Capistrano::Configuration.instance.extend(Capistrano::Configuration.instance)
202
+ end
metadata ADDED
@@ -0,0 +1,163 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: release_party
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - John Barker
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-05-18 00:00:00 +08:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: capistrano
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 23
30
+ segments:
31
+ - 2
32
+ - 6
33
+ - 0
34
+ version: 2.6.0
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: pivotal-tracker
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 23
46
+ segments:
47
+ - 0
48
+ - 2
49
+ - 0
50
+ version: 0.2.0
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: grit
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 29
62
+ segments:
63
+ - 2
64
+ - 4
65
+ - 1
66
+ version: 2.4.1
67
+ type: :runtime
68
+ version_requirements: *id003
69
+ - !ruby/object:Gem::Dependency
70
+ name: mail
71
+ prerelease: false
72
+ requirement: &id004 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ hash: 11
78
+ segments:
79
+ - 2
80
+ - 1
81
+ - 0
82
+ version: 2.1.0
83
+ type: :runtime
84
+ version_requirements: *id004
85
+ - !ruby/object:Gem::Dependency
86
+ name: capistrano_colors
87
+ prerelease: false
88
+ requirement: &id005 !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ hash: 3
94
+ segments:
95
+ - 0
96
+ version: "0"
97
+ type: :runtime
98
+ version_requirements: *id005
99
+ - !ruby/object:Gem::Dependency
100
+ name: colored
101
+ prerelease: false
102
+ requirement: &id006 !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ hash: 3
108
+ segments:
109
+ - 0
110
+ version: "0"
111
+ type: :runtime
112
+ version_requirements: *id006
113
+ description: Perform a number of common post deployment tasks such as delivering pivotal stories, sending out a release email, notifying campfire.
114
+ email: jebarker@gmail.com
115
+ executables: []
116
+
117
+ extensions: []
118
+
119
+ extra_rdoc_files: []
120
+
121
+ files:
122
+ - lib/release_party/environment.rb
123
+ - lib/release_party/release_file.rb
124
+ - lib/release_party/release_party.rb
125
+ - lib/release_party.rb
126
+ has_rdoc: true
127
+ homepage:
128
+ licenses: []
129
+
130
+ post_install_message:
131
+ rdoc_options: []
132
+
133
+ require_paths:
134
+ - lib
135
+ required_ruby_version: !ruby/object:Gem::Requirement
136
+ none: false
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ hash: 3
141
+ segments:
142
+ - 0
143
+ version: "0"
144
+ required_rubygems_version: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ">"
148
+ - !ruby/object:Gem::Version
149
+ hash: 25
150
+ segments:
151
+ - 1
152
+ - 3
153
+ - 1
154
+ version: 1.3.1
155
+ requirements: []
156
+
157
+ rubyforge_project:
158
+ rubygems_version: 1.6.2
159
+ signing_key:
160
+ specification_version: 3
161
+ summary: Celebrate releases
162
+ test_files: []
163
+