release_party 0.0.1

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