service_template 0.5.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.
Files changed (105) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.rubocop.yml +23 -0
  4. data/.travis.yml +13 -0
  5. data/CHANGELOG.md +64 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +24 -0
  8. data/README.md +217 -0
  9. data/Rakefile +9 -0
  10. data/bin/service_template +5 -0
  11. data/lib/service_template.rb +55 -0
  12. data/lib/service_template/active_record_extensions/notifications_subscriber.rb +17 -0
  13. data/lib/service_template/active_record_extensions/seeder.rb +14 -0
  14. data/lib/service_template/active_record_extensions/stats.rb +37 -0
  15. data/lib/service_template/authentication.rb +8 -0
  16. data/lib/service_template/cli.rb +111 -0
  17. data/lib/service_template/deploy.rb +98 -0
  18. data/lib/service_template/gem_dependency.rb +37 -0
  19. data/lib/service_template/generators.rb +3 -0
  20. data/lib/service_template/generators/api_generator.rb +30 -0
  21. data/lib/service_template/generators/readme_generator.rb +47 -0
  22. data/lib/service_template/generators/scaffold_generator.rb +29 -0
  23. data/lib/service_template/generators/templates/api/app/apis/%name_tableize%_api.rb.tt +40 -0
  24. data/lib/service_template/generators/templates/api/app/models/%name_underscore%.rb.tt +2 -0
  25. data/lib/service_template/generators/templates/api/app/representers/%name_underscore%_representer.rb.tt +4 -0
  26. data/lib/service_template/generators/templates/api/spec/apis/%name_tableize%_api_spec.rb.tt +16 -0
  27. data/lib/service_template/generators/templates/api/spec/models/%name_underscore%_spec.rb.tt +9 -0
  28. data/lib/service_template/generators/templates/readme/README.md.tt +55 -0
  29. data/lib/service_template/generators/templates/readme/spec/docs/readme_spec.rb +7 -0
  30. data/lib/service_template/generators/templates/scaffold/.env.development.tt +9 -0
  31. data/lib/service_template/generators/templates/scaffold/.env.test.tt +10 -0
  32. data/lib/service_template/generators/templates/scaffold/.gitignore.tt +13 -0
  33. data/lib/service_template/generators/templates/scaffold/.rubocop.yml +24 -0
  34. data/lib/service_template/generators/templates/scaffold/.ruby-version.tt +1 -0
  35. data/lib/service_template/generators/templates/scaffold/Gemfile.tt +29 -0
  36. data/lib/service_template/generators/templates/scaffold/README.md +3 -0
  37. data/lib/service_template/generators/templates/scaffold/Rakefile +21 -0
  38. data/lib/service_template/generators/templates/scaffold/app.rb +19 -0
  39. data/lib/service_template/generators/templates/scaffold/app/apis/application_api.rb +9 -0
  40. data/lib/service_template/generators/templates/scaffold/app/apis/hello_api.rb.tt +10 -0
  41. data/lib/service_template/generators/templates/scaffold/config.ru.tt +21 -0
  42. data/lib/service_template/generators/templates/scaffold/config/database.yml.tt +19 -0
  43. data/lib/service_template/generators/templates/scaffold/config/initializers/active_record.rb +5 -0
  44. data/lib/service_template/generators/templates/scaffold/db/schema.rb +11 -0
  45. data/lib/service_template/generators/templates/scaffold/lib/.keep +0 -0
  46. data/lib/service_template/generators/templates/scaffold/log/.keep +0 -0
  47. data/lib/service_template/generators/templates/scaffold/spec/apis/hello_api_spec.rb.tt +17 -0
  48. data/lib/service_template/generators/templates/scaffold/spec/factories/.gitkeep +0 -0
  49. data/lib/service_template/generators/templates/scaffold/spec/spec_helper.rb +47 -0
  50. data/lib/service_template/grape_extenders.rb +30 -0
  51. data/lib/service_template/grape_extensions/error_formatter.rb +18 -0
  52. data/lib/service_template/grape_extensions/grape_helpers.rb +27 -0
  53. data/lib/service_template/identity.rb +45 -0
  54. data/lib/service_template/json_error.rb +24 -0
  55. data/lib/service_template/logger/log_transaction.rb +17 -0
  56. data/lib/service_template/logger/logger.rb +42 -0
  57. data/lib/service_template/logger/parseable.rb +37 -0
  58. data/lib/service_template/middleware/app_monitor.rb +17 -0
  59. data/lib/service_template/middleware/authentication.rb +32 -0
  60. data/lib/service_template/middleware/database_stats.rb +15 -0
  61. data/lib/service_template/middleware/logger.rb +67 -0
  62. data/lib/service_template/middleware/request_stats.rb +42 -0
  63. data/lib/service_template/output_formatters/entity.rb +15 -0
  64. data/lib/service_template/output_formatters/include_nil.rb +16 -0
  65. data/lib/service_template/output_formatters/json_api_representer.rb +9 -0
  66. data/lib/service_template/param_sanitizer.rb +30 -0
  67. data/lib/service_template/rspec_extensions/response_helpers.rb +46 -0
  68. data/lib/service_template/setup.rb +36 -0
  69. data/lib/service_template/sortable_api.rb +17 -0
  70. data/lib/service_template/stats.rb +43 -0
  71. data/lib/service_template/stats_d_timer.rb +26 -0
  72. data/lib/service_template/version.rb +45 -0
  73. data/lib/tasks/deploy.rake +11 -0
  74. data/lib/tasks/routes.rake +11 -0
  75. data/service_template.gemspec +42 -0
  76. data/spec/active_record_extensions/filter_by_hash_spec.rb +23 -0
  77. data/spec/active_record_extensions/seeder_spec.rb +13 -0
  78. data/spec/authentication_spec.rb +17 -0
  79. data/spec/deprecations/application_api_spec.rb +19 -0
  80. data/spec/deprecations/entity_spec.rb +9 -0
  81. data/spec/deprecations/filter_by_hash_spec.rb +9 -0
  82. data/spec/deprecations/napa_setup_spec.rb +52 -0
  83. data/spec/generators/api_generator_spec.rb +63 -0
  84. data/spec/generators/migration_generator_spec.rb +105 -0
  85. data/spec/generators/readme_generator_spec.rb +35 -0
  86. data/spec/generators/scaffold_generator_spec.rb +90 -0
  87. data/spec/grape_extenders_spec.rb +50 -0
  88. data/spec/grape_extensions/error_formatter_spec.rb +29 -0
  89. data/spec/grape_extensions/include_nil_spec.rb +23 -0
  90. data/spec/identity_spec.rb +50 -0
  91. data/spec/json_error_spec.rb +33 -0
  92. data/spec/logger/log_transaction_spec.rb +34 -0
  93. data/spec/logger/logger_spec.rb +14 -0
  94. data/spec/logger/parseable_spec.rb +16 -0
  95. data/spec/middleware/authentication_spec.rb +54 -0
  96. data/spec/middleware/database_stats_spec.rb +64 -0
  97. data/spec/middleware/request_stats_spec.rb +21 -0
  98. data/spec/sortable_api_spec.rb +56 -0
  99. data/spec/spec_helper.rb +45 -0
  100. data/spec/stats_d_timer_spec.rb +23 -0
  101. data/spec/stats_spec.rb +66 -0
  102. data/spec/version_spec.rb +40 -0
  103. data/tasks/spec.rake +9 -0
  104. data/tasks/version.rake +51 -0
  105. metadata +456 -0
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+ require 'service_template/logger/logger'
3
+
4
+ describe ServiceTemplate::Logger do
5
+ context '#response' do
6
+ it 'returns response in the expected format' do
7
+ response = ServiceTemplate::Logger.response('foo', 'bar', 'baz')
8
+
9
+ expect(response[:response][:status]).to eq('foo')
10
+ expect(response[:response][:headers]).to eq('bar')
11
+ expect(response[:response][:response]).to eq('baz')
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+ require 'service_template/logger/parseable'
3
+
4
+ describe Logging::Layouts::Parseable do
5
+ context '#format_obj' do
6
+ it 'formats text as an object' do
7
+ p = Logging::Layouts::Parseable.new
8
+ expect(p.format_obj('foobar')).to eq({ text: 'foobar' })
9
+ end
10
+
11
+ it 'does not reformat objects' do
12
+ p = Logging::Layouts::Parseable.new
13
+ expect(p.format_obj({ foo: :bar })).to eq({ foo: :bar })
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+ require 'service_template/middleware/authentication'
3
+ require 'pry'
4
+
5
+ describe ServiceTemplate::Identity do
6
+ before do
7
+ ENV['HEADER_PASSWORDS'] = 'foo'
8
+ end
9
+
10
+ context 'Authenticated Request' do
11
+ it 'allows the request to continue if given a correct password header' do
12
+ app = lambda { |env| [200, {'Content-Type' => 'application/json'}, Array.new] }
13
+ middleware = ServiceTemplate::Middleware::Authentication.new(app)
14
+ env = Rack::MockRequest.env_for('/test', {'HTTP_PASSWORD' => 'foo'})
15
+ status, headers, body = middleware.call(env)
16
+
17
+ expect(status).to eq(200)
18
+ end
19
+ end
20
+
21
+ context 'Failed Authentication Request' do
22
+ it 'returns an error message if the Password header is not supplied' do
23
+ app = lambda { |env| [200, {'Content-Type' => 'application/json'}, Array.new] }
24
+ middleware = ServiceTemplate::Middleware::Authentication.new(app)
25
+ env = Rack::MockRequest.env_for('/test')
26
+ status, headers, body = middleware.call(env)
27
+
28
+ expect(status).to eq(401)
29
+ expect(body).to eq([ServiceTemplate::JsonError.new('bad_password', 'bad password').to_json])
30
+ end
31
+
32
+ it 'returns an error message if an incorrect Password header is supplied' do
33
+ app = lambda { |env| [200, {'Content-Type' => 'application/json'}, Array.new] }
34
+ middleware = ServiceTemplate::Middleware::Authentication.new(app)
35
+ env = Rack::MockRequest.env_for('/test', {'HTTP_PASSWORD' => 'incorrect'})
36
+ status, headers, body = middleware.call(env)
37
+
38
+ expect(status).to eq(401)
39
+ expect(body).to eq([ServiceTemplate::JsonError.new('bad_password', 'bad password').to_json])
40
+ end
41
+
42
+ it 'returns an error message if HEADER_PASSWORDS is not configured' do
43
+ ENV['HEADER_PASSWORDS'] = nil
44
+
45
+ app = lambda { |env| [200, {'Content-Type' => 'application/json'}, Array.new] }
46
+ middleware = ServiceTemplate::Middleware::Authentication.new(app)
47
+ env = Rack::MockRequest.env_for('/test', {'HTTP_PASSWORD' => 'incorrect'})
48
+ status, headers, body = middleware.call(env)
49
+
50
+ expect(status).to eq(401)
51
+ expect(body).to eq([ServiceTemplate::JsonError.new('not_configured', 'password not configured').to_json])
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,64 @@
1
+ require 'active_record'
2
+ require 'spec_helper'
3
+ require 'service_template/active_record_extensions/stats'
4
+
5
+ # Delete any prevous instantiations of the emitter and set valid statsd env vars
6
+ ServiceTemplate::Stats.emitter = nil
7
+ ENV['STATSD_HOST'] = 'localhost'
8
+ ENV['STATSD_PORT'] = '8125'
9
+
10
+ ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
11
+
12
+ ActiveRecord::Schema.define(version: 1) do
13
+ create_table :foos do |t|
14
+ t.string :word
15
+ end
16
+ end
17
+
18
+ class Foo < ActiveRecord::Base
19
+ end
20
+
21
+ describe ServiceTemplate::Middleware::DatabaseStats do
22
+ before do
23
+ # Delete any prevous instantiations of the emitter and set valid statsd env vars
24
+ ServiceTemplate::Stats.emitter = nil
25
+ ENV['STATSD_HOST'] = 'localhost'
26
+ ENV['STATSD_PORT'] = '8125'
27
+
28
+ @foo = Foo.create(word: 'bar')
29
+ end
30
+
31
+ after do
32
+ middleware = ServiceTemplate::Middleware::DatabaseStats.new(@app)
33
+ env = Rack::MockRequest.env_for('/test/path')
34
+ middleware.call(env)
35
+ end
36
+
37
+ it 'should send a query_time for an insert' do
38
+ allow(ServiceTemplate::Stats.emitter).to receive(:timing).with('sql.query_time', an_instance_of(Float))
39
+ allow(ServiceTemplate::Stats.emitter).to receive(:timing).with('sql.table.foos.insert.query_time', an_instance_of(Float))
40
+
41
+ @app = lambda { |env| [200, { 'Content-Type' => 'application/json' }, Foo.create(word: 'baz')] }
42
+ end
43
+
44
+ it 'should send a query_time for a select' do
45
+ allow(ServiceTemplate::Stats.emitter).to receive(:timing).with('sql.query_time', an_instance_of(Float))
46
+ allow(ServiceTemplate::Stats.emitter).to receive(:timing).with('sql.table.foos.select.query_time', an_instance_of(Float))
47
+
48
+ @app = lambda { |env| [200, { 'Content-Type' => 'application/json' }, Foo.first] }
49
+ end
50
+
51
+ it 'should send a query_time for a delete' do
52
+ allow(ServiceTemplate::Stats.emitter).to receive(:timing).with('sql.query_time', an_instance_of(Float))
53
+ allow(ServiceTemplate::Stats.emitter).to receive(:timing).with('sql.table.foos.delete.query_time', an_instance_of(Float))
54
+
55
+ @app = lambda { |env| [200, { 'Content-Type' => 'application/json' }, @foo.delete ] }
56
+ end
57
+
58
+ it 'should send a query_time for an update' do
59
+ allow(ServiceTemplate::Stats.emitter).to receive(:timing).with('sql.query_time', an_instance_of(Float))
60
+ allow(ServiceTemplate::Stats.emitter).to receive(:timing).with('sql.table.foos.update.query_time', an_instance_of(Float))
61
+
62
+ @app = lambda { |env| [200, { 'Content-Type' => 'application/json' }, @foo.update_attributes(word: 'baz') ] }
63
+ end
64
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+ require 'service_template/middleware/request_stats'
3
+
4
+ describe ServiceTemplate::Middleware::RequestStats do
5
+ before do
6
+ # Delete any prevous instantiations of the emitter and set valid statsd env vars
7
+ ServiceTemplate::Stats.emitter = nil
8
+ ENV['STATSD_HOST'] = 'localhost'
9
+ ENV['STATSD_PORT'] = '8125'
10
+ end
11
+
12
+ it 'should send the api_response_time' do
13
+ expect(ServiceTemplate::Stats.emitter).to receive(:timing).with('response_time', an_instance_of(Float))
14
+ expect(ServiceTemplate::Stats.emitter).to receive(:timing).with('path.get.test.path.response_time', an_instance_of(Float))
15
+ app = lambda { |env| [200, { 'Content-Type' => 'application/json'}, Array.new] }
16
+ middleware = ServiceTemplate::Middleware::RequestStats.new(app)
17
+ env = Rack::MockRequest.env_for('/test/path')
18
+ middleware.call(env)
19
+ end
20
+
21
+ end
@@ -0,0 +1,56 @@
1
+ require 'active_record'
2
+ require 'spec_helper'
3
+ require 'service_template/sortable_api'
4
+
5
+ describe "SortableApi" do
6
+ describe "#sort_from_params" do
7
+ before do
8
+ build_model :foos do
9
+ integer :param1
10
+ integer :param2
11
+ end
12
+
13
+ @object1 = Foo.create(param1: 2, param2: 1)
14
+ @object2 = Foo.create(param1: 2, param2: 3)
15
+ @object3 = Foo.create(param1: 3, param2: 5)
16
+ @object4 = Foo.create(param1: 1, param2: 3)
17
+ @object5 = Foo.create(param1: 1, param2: 1)
18
+
19
+ @api = Object.new
20
+ @api.extend(ServiceTemplate::SortableApi)
21
+ @foos = Foo.scoped
22
+ end
23
+
24
+ it "returns the sortable objects if sort_param is nil" do
25
+ expect(@api.sort_from_params(@foos, nil)).to eq(@foos)
26
+ end
27
+
28
+ it "sorts by a given parameter" do
29
+ sorted = @api.sort_from_params(@foos, "param1")
30
+ expect(sorted.last).to eq(@object3)
31
+ expect(sorted.to_sql).to end_with("ORDER BY param1")
32
+ end
33
+
34
+ it "sorts by a given parameter descending if preceded by -" do
35
+ sorted = @api.sort_from_params(@foos, "-param1")
36
+ expect(sorted.first).to eq(@object3)
37
+ expect(sorted.to_sql).to end_with("ORDER BY param1 DESC")
38
+ end
39
+
40
+ it "sorts by multiple parameters in order" do
41
+ sorted = @api.sort_from_params(@foos, "param2,param1")
42
+ expect(sorted.to_a).to eq([@object5, @object1, @object4, @object2, @object3])
43
+ expect(sorted.to_sql).to end_with("ORDER BY param2, param1")
44
+
45
+ alt_sorted = @api.sort_from_params(@foos, "param1,param2")
46
+ expect(alt_sorted.to_a).to eq([@object5, @object4, @object1, @object2, @object3])
47
+ expect(alt_sorted.to_sql).to end_with("ORDER BY param1, param2")
48
+ end
49
+
50
+ it "sorts by multiple parameters, even if descending" do
51
+ sorted = @api.sort_from_params(@foos, "-param2,param1")
52
+ expect(sorted.to_a).to eq([@object3, @object4, @object2, @object5, @object1])
53
+ expect(sorted.to_sql).to end_with("ORDER BY param2 DESC, param1")
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,45 @@
1
+ ENV['RACK_ENV'] = 'test'
2
+
3
+ require 'service_template/setup'
4
+ require 'acts_as_fu'
5
+
6
+ require "codeclimate-test-reporter"
7
+ CodeClimate::TestReporter.start
8
+
9
+ ServiceTemplate.skip_initialization = true
10
+
11
+ require 'service_template'
12
+ require 'service_template/rspec_extensions/response_helpers'
13
+
14
+ # from https://gist.github.com/adamstegman/926858
15
+ RSpec.configure do |config|
16
+ config.include ServiceTemplate::RspecExtensions::ResponseHelpers
17
+
18
+ config.before(:all) { silence_output }
19
+ config.after(:all) { enable_output }
20
+
21
+ config.include ActsAsFu
22
+
23
+ config.before(:each) do
24
+ allow(ServiceTemplate).to receive(:initialize)
25
+ allow(ServiceTemplate::Logger).to receive_message_chain('logger.info').with(:service_template_deprecation_warning)
26
+ end
27
+ end
28
+
29
+ # Redirects stderr and stdout to /dev/null.
30
+ def silence_output
31
+ @orig_stderr = $stderr
32
+ @orig_stdout = $stdout
33
+
34
+ # redirect stderr and stdout to /dev/null
35
+ $stderr = File.new('/dev/null', 'w')
36
+ $stdout = File.new('/dev/null', 'w')
37
+ end
38
+
39
+ # Replace stdout and stderr so anything else is output correctly.
40
+ def enable_output
41
+ $stderr = @orig_stderr
42
+ $stdout = @orig_stdout
43
+ @orig_stderr = nil
44
+ @orig_stdout = nil
45
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+ require 'service_template/stats_d_timer'
3
+
4
+ class FooTimer
5
+ include ServiceTemplate::StatsDTimer
6
+ end
7
+
8
+ describe ServiceTemplate::StatsDTimer do
9
+ before do
10
+ # Delete any prevous instantiations of the emitter
11
+ ServiceTemplate::Stats.emitter = nil
12
+ # Stub out logging since there is no log to output to
13
+ allow(ServiceTemplate::Logger).to receive_message_chain(:logger, :warn)
14
+ end
15
+
16
+ it 'logs a timing event based on how long the block takes' do
17
+ expect(ServiceTemplate::Stats.emitter).to receive(:timing).with('foo', an_instance_of(Float))
18
+ FooTimer.report_time('foo') do
19
+ sleep(0.1)
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+ require 'service_template/stats'
3
+
4
+ describe ServiceTemplate::Stats do
5
+ before do
6
+ # Delete any prevous instantiations of the emitter
7
+ ServiceTemplate::Stats.emitter = nil
8
+ # Stub out logging since there is no log to output to
9
+ allow(ServiceTemplate::Logger).to receive_message_chain(:logger, :warn)
10
+ end
11
+
12
+ it 'should log an error if StatsD env variables are not configured' do
13
+ ENV['STATSD_HOST'] = nil
14
+ ENV['STATSD_PORT'] = nil
15
+ message = 'StatsD host and port not configured in environment variables, using default settings'
16
+ expect(ServiceTemplate::Logger.logger).to receive(:warn).with(message)
17
+ ServiceTemplate::Stats.emitter
18
+ end
19
+
20
+ it 'should default statsd to localhost port 8125 if env vars are not specified' do
21
+ ENV['STATSD_HOST'] = nil
22
+ ENV['STATSD_PORT'] = nil
23
+ expect(ServiceTemplate::Stats.emitter.host).to eq('127.0.0.1')
24
+ expect(ServiceTemplate::Stats.emitter.port).to eq(8125)
25
+ end
26
+
27
+ it 'should return a StatsD client object' do
28
+ expect(ServiceTemplate::Stats.emitter.class.name).to eq('Statsd')
29
+ end
30
+
31
+ it 'the namespace of the StatsD client object should equal the service name' do
32
+ ENV['SERVICE_NAME'] = 'my-service'
33
+ expect(ServiceTemplate::Stats.emitter.namespace).to eq("my-service.test")
34
+ end
35
+
36
+ it 'should use env variables to set statsd host and port' do
37
+ ENV['STATSD_HOST'] = 'localhost'
38
+ ENV['STATSD_PORT'] = '9000'
39
+ expect(ServiceTemplate::Stats.emitter.host).to eq('localhost')
40
+ expect(ServiceTemplate::Stats.emitter.port).to eq('9000')
41
+ end
42
+
43
+ describe '#namespace' do
44
+ it 'prepends the namespace with the STATSD_API_KEY if present' do
45
+ ENV['STATSD_API_KEY'] = 'foo'
46
+ expect(ServiceTemplate::Stats.namespace).to eq("#{ENV['STATSD_API_KEY']}.#{ServiceTemplate::Identity.name}.test")
47
+ end
48
+
49
+ it 'does not include the STATSD_API_KEY if empty' do
50
+ ENV['STATSD_API_KEY'] = nil
51
+ expect(ServiceTemplate::Stats.namespace).to eq("#{ServiceTemplate::Identity.name}.test")
52
+ end
53
+ end
54
+
55
+ describe '#path_to_key' do
56
+ it 'returns the key string with ids removed and parts joined with dots' do
57
+ method = 'GET'
58
+ path = '/foo/123/bar'
59
+ expect(ServiceTemplate::Stats.path_to_key(method, path)).to eq('get.foo._.bar')
60
+
61
+ method = 'POST'
62
+ path = '/foo'
63
+ expect(ServiceTemplate::Stats.path_to_key(method, path)).to eq('post.foo')
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+ require 'service_template/version'
3
+
4
+ describe ServiceTemplate::Version do
5
+ context '#major_bump' do
6
+ it 'should set the major revision value, and the rest should be 0' do
7
+ stub_const('ServiceTemplate::VERSION', '1.2.3')
8
+ expect(ServiceTemplate::Version.next_major).to eq('2.0.0')
9
+ end
10
+
11
+ it 'should set the major revision value, and the rest should be 0' do
12
+ stub_const('ServiceTemplate::VERSION', '5.0.0')
13
+ expect(ServiceTemplate::Version.next_major).to eq('6.0.0')
14
+ end
15
+ end
16
+
17
+ context '#minor_bump' do
18
+ it 'should set the minor revision value, leaving the major value unchanged and the patch value to 0' do
19
+ stub_const('ServiceTemplate::VERSION', '1.2.3')
20
+ expect(ServiceTemplate::Version.next_minor).to eq('1.3.0')
21
+ end
22
+
23
+ it 'should set the minor revision value, leaving the major value unchanged and the patch value to 0' do
24
+ stub_const('ServiceTemplate::VERSION', '0.5.0')
25
+ expect(ServiceTemplate::Version.next_minor).to eq('0.6.0')
26
+ end
27
+ end
28
+
29
+ context 'patch_bump' do
30
+ it 'should set the patch revision value, leaving the major and minor values unchanged' do
31
+ stub_const('ServiceTemplate::VERSION', '1.2.3')
32
+ expect(ServiceTemplate::Version.next_patch).to eq('1.2.4')
33
+ end
34
+
35
+ it 'should set the patch revision value, leaving the major and minor values unchanged' do
36
+ stub_const('ServiceTemplate::VERSION', '5.5.5')
37
+ expect(ServiceTemplate::Version.next_patch).to eq('5.5.6')
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,9 @@
1
+ desc 'Run the RSpec test suite'
2
+ task :spec do
3
+ sh *%w[
4
+ bundle exec
5
+ rspec --colour
6
+ --format documentation
7
+ --fail-fast
8
+ ]
9
+ end
@@ -0,0 +1,51 @@
1
+ desc "bump the gem version"
2
+ namespace :version do
3
+ namespace :bump do
4
+
5
+ task :major do
6
+ @new_version = ServiceTemplate::Version.next_major
7
+ execute_version_bump
8
+ end
9
+
10
+ task :minor do
11
+ @new_version = ServiceTemplate::Version.next_minor
12
+ execute_version_bump
13
+ end
14
+
15
+ task :patch do
16
+ @new_version = ServiceTemplate::Version.next_patch
17
+ execute_version_bump
18
+ end
19
+
20
+ def execute_version_bump
21
+ if !clean_staging_area?
22
+ system "git status"
23
+ raise "Unclean staging area! Be sure to commit or .gitignore everything first. See `git status` above."
24
+ else
25
+ require 'git'
26
+ git = Git.open('.')
27
+
28
+ write_update
29
+ git.add('lib/service_template/version.rb')
30
+ git.commit("Version bump: #{release_tag}")
31
+ git.add_tag(release_tag)
32
+ git.push(git.remote('upstream'), git.branch, release_tag) if git.remote('upstream')
33
+ puts "Version bumped: #{release_tag}"
34
+ end
35
+ end
36
+
37
+ def write_update
38
+ filedata = File.read('lib/service_template/version.rb')
39
+ changed_filedata = filedata.gsub("VERSION = '#{ServiceTemplate::VERSION}'\n", "VERSION = '#{@new_version}'\n")
40
+ File.open('lib/service_template/version.rb',"w"){|file| file.puts changed_filedata}
41
+ end
42
+
43
+ def clean_staging_area?
44
+ `git ls-files --deleted --modified --others --exclude-standard` == ""
45
+ end
46
+
47
+ def release_tag
48
+ "v#{@new_version}"
49
+ end
50
+ end
51
+ end