cap-taffy 0.0.2

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,287 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. spec_helper])
2
+
3
+ module CapTaffy
4
+ describe 'Db' do
5
+ context "when loaded" do
6
+ include CapistranoHelpers
7
+ include TaffyHelpers
8
+
9
+ before do
10
+ CapTaffy.send(:remove_const, "Db") rescue nil
11
+ end
12
+
13
+ it "should load in capistrano configuration instance" do;
14
+ Capistrano::Configuration.instance.expects(:load)
15
+
16
+ load 'lib/cap-taffy/db.rb'
17
+ end
18
+
19
+ it "should define :db namespace" do
20
+ Capistrano::Configuration.instance.expects(:namespace).with(:db)
21
+
22
+ load 'lib/cap-taffy/db.rb'
23
+ end
24
+
25
+ for_task :detect, :roles => :app, :in => :Db, :it => "should be defined" do
26
+ @mod.expects(:remote_database_url).returns("remote_db_url")
27
+ @mod.expects(:local_database_url).returns("local_db_url")
28
+
29
+ load 'lib/cap-taffy/db.rb'
30
+
31
+ @namespace.instance_variable_get(:@remote_database_url).should == "remote_db_url"
32
+ @namespace.instance_variable_get(:@local_database_url).should == "local_db_url"
33
+ end
34
+
35
+ def load_taffy_db # :nodoc:
36
+ with_logger do
37
+ load 'lib/cap-taffy/db.rb'
38
+ end
39
+ end
40
+
41
+ for_task :push, :roles => :app, :in => :Db, :it => "should send taps client cmd_send" do
42
+ options = {:remote_database_url => "remote", :local_database_url => "local", :port => nil, :login => "a_user", :password => "a_pass"}
43
+ @namespace.expects(:detect)
44
+ namespace_with_variables(:taps_port => nil)
45
+ db_with_expected_options(options)
46
+ @mod.expects(:tmp_pass).with(@namespace.fetch(:user)).returns(options[:password])
47
+ @mod.expects(:run).with(@namespace, options).yields(taps_client_who(:expects, :cmd_send))
48
+
49
+ load_taffy_db
50
+ end
51
+
52
+ for_task :push, :roles => :app, :in => :Db, :it => "should use cli argument for port" do
53
+ options = {:remote_database_url => "remote", :local_database_url => "local", :port => 1234, :login => "a_user", :password => "a_pass"}
54
+ @namespace.expects(:detect)
55
+ namespace_with_variables(:taps_port => 1234)
56
+ db_with_expected_options(options)
57
+ @mod.expects(:tmp_pass).with(@namespace.fetch(:user)).returns(options[:password])
58
+ @mod.expects(:run).with(@namespace, options)
59
+
60
+ load_taffy_db
61
+ end
62
+
63
+ for_task :push, :roles => :app, :in => :Db, :it => "should force 127.0.0.1 (local) for ssh local forwarding" do
64
+ options = {:remote_database_url => "remote", :local_database_url => "local", :port => 1234, :login => "a_user", :password => "a_pass"}
65
+ @namespace.expects(:detect)
66
+ namespace_with_variables(:taps_port => 1234, :local => true)
67
+ db_with_expected_options(options)
68
+ @mod.expects(:tmp_pass).with(@namespace.fetch(:user)).returns(options[:password])
69
+ @mod.expects(:run).with(@namespace, options.merge(:local => true))
70
+
71
+ load_taffy_db
72
+ end
73
+
74
+ for_task :pull, :roles => :app, :in => :Db, :it => "should send taps client cmd_receive" do
75
+ options = {:remote_database_url => "remote", :local_database_url => "local", :port => nil, :login => "a_user", :password => "a_pass"}
76
+ @namespace.expects(:detect)
77
+ namespace_with_variables(:taps_port => nil)
78
+ db_with_expected_options(options)
79
+ @mod.expects(:tmp_pass).with(@namespace.fetch(:user)).returns(options[:password])
80
+ @mod.expects(:run).with(@namespace, options).yields(taps_client_who(:expects, :cmd_receive))
81
+
82
+ load_taffy_db
83
+ end
84
+ end
85
+
86
+ context "after capistrano" do
87
+ include CapistranoHelpers
88
+ include TaffyHelpers
89
+
90
+ before do
91
+ Capistrano::Configuration.instance.expects(:namespace).with(:db)
92
+ CapTaffy.send(:remove_const, "Db") rescue nil
93
+ load 'lib/cap-taffy/db.rb'
94
+
95
+ @conf = {"test"=>
96
+ {"reconnect"=>false,
97
+ "encoding"=>"utf8",
98
+ "username"=>"root",
99
+ "adapter"=>"postgresql",
100
+ "database"=>"test_test",
101
+ "pool"=>5,
102
+ "password"=>"root",
103
+ "host"=>"localhost"}}
104
+
105
+ @options = {:remote_database_url => "remote", :local_database_url => "local", :port => nil, :login => "a_user", :password => "a_pass"}
106
+ end
107
+
108
+ it "should detect local database url" do
109
+ File.expects(:exists?).returns(true)
110
+ File.expects(:read).returns(mock())
111
+ YAML.expects(:load).returns(@conf)
112
+ env = 'test'
113
+ Parse.expects(:database_url).with(@conf, env)
114
+
115
+ Db.local_database_url(env)
116
+ end
117
+
118
+ it "should detect remote database url" do
119
+ instance = mock()
120
+ instance.stubs(:current_path).returns("/home/user/public_html/current")
121
+ instance.expects(:capture).with("cat /home/user/public_html/current/config/database.yml")
122
+ YAML.expects(:load).returns(@conf)
123
+ env = 'test'
124
+ Parse.expects(:database_url).with(@conf, env)
125
+
126
+ Db.remote_database_url(instance, env)
127
+ end
128
+
129
+ it "should create temporary password from time and user" do
130
+ Time.stubs(:now).returns("asdfasdfasdf")
131
+ user = "me"
132
+ tmp_pass = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{user}--")
133
+
134
+ Db.tmp_pass(user).should == tmp_pass
135
+ end
136
+
137
+ it "should expose a basic taps client" do
138
+ client = mock()
139
+ local_database_url = mock()
140
+ remote_url = mock()
141
+ Taps::Config.expects(:chunksize=).with(1000)
142
+ Taps::Config.expects(:database_url=).with(local_database_url)
143
+ Taps::Config.expects(:remote_url=).with(remote_url)
144
+ Taps::Config.expects(:verify_database_url)
145
+ client.expects(:do_something)
146
+
147
+ Taps::ClientSession.expects(:quickstart).yields(client)
148
+
149
+ Db.taps_client(local_database_url, remote_url) do |client|
150
+ client.do_something
151
+ end
152
+ end
153
+
154
+ it "should define default port" do
155
+ Db.default_server_port.should == 5000
156
+ end
157
+
158
+ it "should build server command" do
159
+ remote_database_url, login, password, port = @options[:remote_database_url], @options[:login], @options[:password], @options[:port]
160
+
161
+ Db.server_command(@options).should == "taps server #{remote_database_url} #{login} #{password}"
162
+ end
163
+
164
+ it "should build server command with port" do
165
+ @options[:port] = 1234
166
+ remote_database_url, login, password, port = @options[:remote_database_url], @options[:login], @options[:password], @options[:port]
167
+
168
+ Db.server_command(@options).should == "taps server #{remote_database_url} #{login} #{password} --port=#{port}"
169
+ end
170
+
171
+ it "should build server command without port if same as default port" do
172
+ @options[:port] = 5000
173
+ remote_database_url, login, password = @options[:remote_database_url], @options[:login], @options[:password]
174
+
175
+ Db.server_command(@options).should == "taps server #{remote_database_url} #{login} #{password}"
176
+ end
177
+
178
+ def parser_expects_uri_hash_to_url_with(login, password, host)
179
+ parser = mock()
180
+ Parse.expects(:new).at_least_once.returns(parser)
181
+ parser.expects(:uri_hash_to_url).
182
+ with('username' => login, 'password' => password, 'host' => host, 'scheme' => 'http', 'path' => '')
183
+ end
184
+
185
+ it "should build remote url (with some help)" do
186
+ @options[:host] = "127.0.0.1"
187
+ parser_expects_uri_hash_to_url_with(@options[:login], @options[:password], "#{@options[:host]}:#{Db.default_server_port}").returns("remote_url/")
188
+
189
+ Db.remote_url(@options)
190
+ end
191
+
192
+ it "should build remote url with different port" do
193
+ @options[:host] = "127.0.0.1"
194
+ @options[:port] = 1234
195
+ parser_expects_uri_hash_to_url_with(@options[:login], @options[:password], "#{@options[:host]}:#{@options[:port]}").returns("remote_url")
196
+
197
+ Db.remote_url(@options)
198
+ end
199
+
200
+ it "should remove trailing slash from remote url" do
201
+ @options[:host] = "127.0.0.1"
202
+ parser_expects_uri_hash_to_url_with(@options[:login], @options[:password], "#{@options[:host]}:#{Db.default_server_port}").returns("remote_url/")
203
+
204
+ Db.remote_url(@options).should == "remote_url"
205
+ end
206
+
207
+ running_db_it "should run with capistrano" do
208
+ capistrano_run_with(Db.server_command(@options))
209
+
210
+ Db.run(@capistrano, @options)
211
+ end
212
+
213
+ running_db_it "should do something to taps client" do
214
+ channel, stream, data = simulating_run_loop_with :data => ">> Listening on 0.0.0.0:5000, CTRL+C to stop\r\n" do
215
+ capistrano_run_with(Db.server_command(@options))
216
+ end
217
+ channel.expects(:close)
218
+
219
+ Db.expects(:remote_url).with(@options.merge(:host => channel[:host], :port => 5000)).returns("remote_url")
220
+ Db.expects(:taps_client).with("local", "remote_url").yields(taps_client_who(:expects, :do_something))
221
+ Db.run(@capistrano, @options) do |client|
222
+ client.do_something
223
+ end
224
+
225
+ channel[:status].should == 0
226
+ end
227
+
228
+ running_db_it "should run taffy on different port" do
229
+ @options[:port] = 1234
230
+
231
+ channel, stream, data = simulating_run_loop_with :data => ">> Listening on 0.0.0.0:1234, CTRL+C to stop\r\n" do
232
+ capistrano_run_with(Db.server_command(@options))
233
+ end
234
+ channel.expects(:close)
235
+ Db.expects(:remote_url).with(@options.merge(:host => channel[:host])).returns("remote_url")
236
+ Db.expects(:taps_client).with("local", "remote_url").yields(taps_client_who(:expects, :do_something))
237
+
238
+ Db.run(@capistrano, @options) do |client|
239
+ client.do_something
240
+ end
241
+
242
+ channel[:status].should == 0
243
+ end
244
+
245
+ running_db_it "should not do anything until taps sinatra server is running" do
246
+ simulating_run_loop_with :data => "asdfasdf" do
247
+ capistrano_run_with(Db.server_command(@options))
248
+ end
249
+
250
+ client = mock()
251
+ client.expects(:do_something).never
252
+
253
+ Db.run(@capistrano, @options) do |client|
254
+ client.do_something
255
+ end
256
+
257
+ channel, stream, data = simulating_run_loop_with :data => ">> Listening on 0.0.0.0:5000, CTRL+C to stop\r\n" do
258
+ capistrano_run_with(Db.server_command(@options))
259
+ end
260
+ channel.expects(:close)
261
+ Db.expects(:remote_url).with(@options.merge(:host => channel[:host], :port => 5000)).returns("remote_url")
262
+ Db.expects(:taps_client).with("local", "remote_url").yields(taps_client_who(:expects, :do_something))
263
+
264
+ Db.run(@capistrano, @options) do |client|
265
+ client.do_something
266
+ end
267
+
268
+ channel[:status].should == 0
269
+ end
270
+
271
+ running_db_it "should force 127.0.0.1 (local) for remote url" do
272
+ channel, stream, data = simulating_run_loop_with :data => ">> Listening on 0.0.0.0:5000, CTRL+C to stop\r\n" do
273
+ capistrano_run_with(Db.server_command(@options))
274
+ end
275
+ channel.expects(:close)
276
+
277
+ Db.expects(:remote_url).with(@options.merge(:host => '127.0.0.1', :port => 5000)).returns("remote_url")
278
+ Db.expects(:taps_client).with("local", "remote_url").yields(taps_client_who(:expects, :do_something))
279
+ Db.run(@capistrano, @options.merge(:local => true)) do |client|
280
+ client.do_something
281
+ end
282
+
283
+ channel[:status].should == 0
284
+ end
285
+ end
286
+ end
287
+ end
@@ -0,0 +1,57 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. spec_helper])
2
+ require 'lib/cap-taffy/parse'
3
+
4
+ module CapTaffy
5
+ describe Parse do
6
+ before do
7
+ @database_config = {"production"=>
8
+ {"reconnect"=>false,
9
+ "encoding"=>"utf8",
10
+ "username"=>"root",
11
+ "adapter"=>"mysql",
12
+ "database"=>"test_production",
13
+ "pool"=>5,
14
+ "password"=>"root",
15
+ "host"=>"localhost"},
16
+ "development"=>
17
+ {"username"=>"root",
18
+ "adapter"=>"sqlite3",
19
+ "database"=>"test_development",
20
+ "password"=>"root"},
21
+ "test"=>
22
+ {"reconnect"=>false,
23
+ "encoding"=>"utf8",
24
+ "username"=>"root",
25
+ "adapter"=>"postgresql",
26
+ "database"=>"test_test",
27
+ "pool"=>5,
28
+ "password"=>"root",
29
+ "host"=>"localhost"}}
30
+ end
31
+
32
+ it "should do pass-through for escape" do
33
+ Parse.new.escape("something").should == "something"
34
+ end
35
+
36
+ it "should parse database config for sqlite" do
37
+ Parse.expects(:conf_to_uri_hash).never
38
+ Parse.database_url(@database_config, 'development').should == "sqlite://test_development"
39
+ end
40
+
41
+ it "should parse database config for postgresql" do
42
+ Parse.database_url(@database_config, 'test').should == "postgres://root:root@localhost/test_test?encoding=utf8"
43
+ end
44
+
45
+ it "should parse database config for mysql" do
46
+ Parse.database_url(@database_config, 'production').should == "mysql://root:root@localhost/test_production?encoding=utf8"
47
+ end
48
+
49
+ it "should raise invalid conf if so" do
50
+ lambda { Parse.database_url(nil, nil) }.should raise_error(Parse::Invalid)
51
+ end
52
+
53
+ it "should raise invalid conf if so" do
54
+ lambda { Parse.database_url(@database_config, nil) }.should raise_error(Parse::Invalid)
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,37 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. spec_helper])
2
+
3
+ module CapTaffy
4
+ describe 'SSH' do
5
+ include CapistranoHelpers
6
+
7
+ before do
8
+ CapTaffy.send(:remove_const, "SSH") rescue nil
9
+ end
10
+
11
+ it "should load in capistrano configuration instance" do;
12
+ Capistrano::Configuration.instance.expects(:load)
13
+
14
+ load 'lib/cap-taffy/ssh.rb'
15
+ end
16
+
17
+ it "should define :db namespace" do
18
+ Capistrano::Configuration.instance.expects(:namespace).with(:ssh)
19
+
20
+ load 'lib/cap-taffy/ssh.rb'
21
+ end
22
+
23
+ def simulating_line(line, &blk)
24
+ blk.call.then.yields(line)
25
+ line
26
+ end
27
+
28
+ for_task :authorize, :in => :SSH, :it => "should authorize on each server" do
29
+ public_key = "ssh-key2\n"
30
+ File.expects(:read).with(File.expand_path(File.join(%w[~/ .ssh id_rsa.pub]))).returns(public_key)
31
+
32
+ run_with(@namespace, anything) # Don't rly wna test bash scripts
33
+
34
+ load 'lib/cap-taffy/ssh.rb'
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,4 @@
1
+ require File.join(File.dirname(__FILE__), %w[spec_helper])
2
+
3
+ describe CapTaffy do
4
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,4 @@
1
+ --colour
2
+ --format progress
3
+ --loadby mtime
4
+ --reverse
@@ -0,0 +1,179 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib cap-taffy]))
2
+
3
+ module Capistrano # :nodoc:
4
+ end
5
+
6
+ Spec::Runner.configure do |config|
7
+ # == Mock Framework
8
+ #
9
+ # RSpec uses it's own mocking framework by default. If you prefer to
10
+ # use mocha, flexmock or RR, uncomment the appropriate line:
11
+ #
12
+ config.mock_with :mocha
13
+ # config.mock_with :flexmock
14
+ # config.mock_with :rr
15
+ end
16
+
17
+ Capistrano.send(:remove_const, "Configuration") rescue nil
18
+ Capistrano.const_set("Configuration", Class.new)
19
+ Capistrano::Configuration.class_eval do
20
+ def self.instance
21
+ @instance ||= Capistrano::Configuration.new
22
+ end
23
+
24
+ def load(*args, &block)
25
+ instance_eval(&block) if block_given?
26
+ end
27
+
28
+ def namespaces
29
+ @namespaces ||= {}
30
+ end
31
+
32
+ def namespace(name, &block)
33
+ namespaces[name].instance_eval(&block)
34
+ end
35
+ end
36
+
37
+ class String # :nodoc:
38
+ def demodulize
39
+ gsub(/^.*::/, '')
40
+ end
41
+ end
42
+
43
+ module CapistranoHelpers
44
+ def self.included(base) # :nodoc:
45
+ base.extend CapistranoHelpers::ClassMethods
46
+ end
47
+
48
+ # Stubs the Capistrano Logger and yields to the block
49
+ def with_logger(&blk) # :yields:
50
+ logger_class = Class.new
51
+ logger = mock()
52
+ logger.stub_everything
53
+ logger_class.stubs(:new).returns(logger)
54
+ Capistrano.const_set("Logger", logger_class)
55
+ yield
56
+ ensure
57
+ Capistrano.send(:remove_const, "Logger") rescue nil
58
+ end
59
+
60
+ # Helper for common operations in db tasks
61
+ def db_with_expected_options(options) # :nodoc:
62
+ @namespace.stubs(:fetch).with(:user).returns(options[:login])
63
+ @namespace.instance_variable_set(:@remote_database_url, options[:remote_database_url])
64
+ @namespace.instance_variable_set(:@local_database_url, options[:local_database_url])
65
+ end
66
+
67
+ # Stubs the variables hash used by Capistrano to accept command-line parameters
68
+ def namespace_with_variables(variables) # :nodoc:
69
+ @namespace.stubs(:variables).returns(variables)
70
+ end
71
+
72
+ # Creates an expectation for the Capistrano namespace/task <tt>instance</tt> for the <tt>:run</tt> action with <tt>*args</tt>.
73
+ def run_with(instance, *args)
74
+ instance.expects(:run).with(*args)
75
+ end
76
+
77
+ # The Capistrano <tt>:run</tt> action loops with <tt>channel</tt>, <tt>stream</tt>, and <tt>data</tt> until the channel is closed.
78
+ #
79
+ # Passing in a <tt>:run</tt> expectation, modifies the expectation such that each subsequent invocation ("loop") yields <tt>channel</tt>, <tt>stream</tt>, and <tt>data</tt>
80
+ #
81
+ # ==== Parameters
82
+ #
83
+ # * <tt>:channel</tt> - A hash containing <tt>:host</tt>.
84
+ # * <tt>:stream</tt> - A stream object.
85
+ # * <tt>:data</tt> - A data object, usually a String.
86
+ def simulating_run_loop_with(options={}, &blk) # :yields:
87
+ channel = options[:channel] || {:host => "192.168.1.20"}
88
+ stream = options[:stream]
89
+ data = options[:data]
90
+
91
+ blk.call.then.yields(channel, stream, data)
92
+ [channel, stream, data]
93
+ end
94
+
95
+ module ClassMethods
96
+ # Used in specs to test Capistrano tasks.
97
+ #
98
+ #
99
+ # Code defined in the task will be executed automatically on load. (Note the <tt>yields</tt>, see Mocha#yields[http://mocha.rubyforge.org/classes/Mocha/Expectation.html#M000043])
100
+ #
101
+ # ==== Parameters
102
+ #
103
+ # * <tt>:it</tt> - The description for the current example group.
104
+ # * <tt>:in</tt> - Specifies the module under test (as well as the namespace the task is defined in). The namespace will be deduced with the downcase of <tt>:in</tt>
105
+ #
106
+ # ==== Examples
107
+ #
108
+ # for_task :detect, :roles => :app, :in => :Somewhere, :it => "should so something" do
109
+ # @namespace # refers to the current task under test (in Capistrano tasks are executed on Capistrano::Namespaces::Namespace instances)
110
+ # @mod # refers to module CapTaffy::Somewhere
111
+ # end
112
+ def for_task(task_name, options, &block)
113
+ description = options.delete(:it)
114
+ namespace = options.delete(:in)
115
+
116
+ context ":#{task_name.to_s} task" do
117
+ before do
118
+ @namespace = Capistrano::Configuration.instance.namespaces[namespace.to_s.downcase.to_sym] = mock()
119
+ @namespace.stubs(:desc)
120
+ @namespace.stubs(:task)
121
+ args = [task_name, options]
122
+ unless options.empty?
123
+ @namespace.expects(:task).with(*args).yields
124
+ else
125
+ @namespace.expects(:task).with(task_name).yields
126
+ end
127
+
128
+ @mod = Module.new # The module under test
129
+ CapTaffy.const_set(namespace, @mod)
130
+ end
131
+
132
+ it description, &block
133
+
134
+ after do
135
+ const_name = @mod.to_s.demodulize
136
+ CapTaffy.send(:remove_const, const_name)
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
142
+
143
+ module TaffyHelpers
144
+ def self.included(base) # :nodoc:
145
+ base.extend TaffyHelpers::ClassMethods
146
+ end
147
+
148
+ # A simple helper for mocking a quick object
149
+ #
150
+ # Usage:
151
+ # taps_client_who(:expects, :do_something)
152
+ def taps_client_who(method_symbol, *args)
153
+ client = mock()
154
+ client.send(method_symbol, *args)
155
+ client
156
+ end
157
+
158
+ module ClassMethods
159
+ # A wrapper for running CapTaffy::Db::run
160
+ def running_db_it(message, &blk)
161
+ context "when running db" do
162
+ before do
163
+ @capistrano = mock()
164
+ end
165
+
166
+ # See CapistranoHelpers
167
+ def capistrano_run_with(*args)
168
+ run_with(@capistrano, *args)
169
+ end
170
+
171
+ it message, &blk
172
+
173
+ after do
174
+
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
data/tasks/ann.rake ADDED
@@ -0,0 +1,80 @@
1
+
2
+ begin
3
+ require 'bones/smtp_tls'
4
+ rescue LoadError
5
+ require 'net/smtp'
6
+ end
7
+ require 'time'
8
+
9
+ namespace :ann do
10
+
11
+ # A prerequisites task that all other tasks depend upon
12
+ task :prereqs
13
+
14
+ file PROJ.ann.file do
15
+ ann = PROJ.ann
16
+ puts "Generating #{ann.file}"
17
+ File.open(ann.file,'w') do |fd|
18
+ fd.puts("#{PROJ.name} version #{PROJ.version}")
19
+ fd.puts(" by #{Array(PROJ.authors).first}") if PROJ.authors
20
+ fd.puts(" #{PROJ.url}") if PROJ.url.valid?
21
+ fd.puts(" (the \"#{PROJ.release_name}\" release)") if PROJ.release_name
22
+ fd.puts
23
+ fd.puts("== DESCRIPTION")
24
+ fd.puts
25
+ fd.puts(PROJ.description)
26
+ fd.puts
27
+ fd.puts(PROJ.changes.sub(%r/^.*$/, '== CHANGES'))
28
+ fd.puts
29
+ ann.paragraphs.each do |p|
30
+ fd.puts "== #{p.upcase}"
31
+ fd.puts
32
+ fd.puts paragraphs_of(PROJ.readme_file, p).join("\n\n")
33
+ fd.puts
34
+ end
35
+ fd.puts ann.text if ann.text
36
+ end
37
+ end
38
+
39
+ desc "Create an announcement file"
40
+ task :announcement => ['ann:prereqs', PROJ.ann.file]
41
+
42
+ desc "Send an email announcement"
43
+ task :email => ['ann:prereqs', PROJ.ann.file] do
44
+ ann = PROJ.ann
45
+ from = ann.email[:from] || Array(PROJ.authors).first || PROJ.email
46
+ to = Array(ann.email[:to])
47
+
48
+ ### build a mail header for RFC 822
49
+ rfc822msg = "From: #{from}\n"
50
+ rfc822msg << "To: #{to.join(',')}\n"
51
+ rfc822msg << "Subject: [ANN] #{PROJ.name} #{PROJ.version}"
52
+ rfc822msg << " (#{PROJ.release_name})" if PROJ.release_name
53
+ rfc822msg << "\n"
54
+ rfc822msg << "Date: #{Time.new.rfc822}\n"
55
+ rfc822msg << "Message-Id: "
56
+ rfc822msg << "<#{"%.8f" % Time.now.to_f}@#{ann.email[:domain]}>\n\n"
57
+ rfc822msg << File.read(ann.file)
58
+
59
+ params = [:server, :port, :domain, :acct, :passwd, :authtype].map do |key|
60
+ ann.email[key]
61
+ end
62
+
63
+ params[3] = PROJ.email if params[3].nil?
64
+
65
+ if params[4].nil?
66
+ STDOUT.write "Please enter your e-mail password (#{params[3]}): "
67
+ params[4] = STDIN.gets.chomp
68
+ end
69
+
70
+ ### send email
71
+ Net::SMTP.start(*params) {|smtp| smtp.sendmail(rfc822msg, from, to)}
72
+ end
73
+ end # namespace :ann
74
+
75
+ desc 'Alias to ann:announcement'
76
+ task :ann => 'ann:announcement'
77
+
78
+ CLOBBER << PROJ.ann.file
79
+
80
+ # EOF
data/tasks/bones.rake ADDED
@@ -0,0 +1,20 @@
1
+
2
+ if HAVE_BONES
3
+
4
+ namespace :bones do
5
+
6
+ desc 'Show the PROJ open struct'
7
+ task :debug do |t|
8
+ atr = if t.application.top_level_tasks.length == 2
9
+ t.application.top_level_tasks.pop
10
+ end
11
+
12
+ if atr then Bones::Debug.show_attr(PROJ, atr)
13
+ else Bones::Debug.show PROJ end
14
+ end
15
+
16
+ end # namespace :bones
17
+
18
+ end # HAVE_BONES
19
+
20
+ # EOF