config_scripts 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.rspec +2 -0
  4. data/.yardopts +1 -0
  5. data/CHANGELOG.md +17 -0
  6. data/Gemfile +4 -0
  7. data/Gemfile.lock +124 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +55 -0
  10. data/Rakefile +1 -0
  11. data/TODO.md +8 -0
  12. data/config_scripts.gemspec +31 -0
  13. data/lib/config_scripts/generators/config_script.rb +24 -0
  14. data/lib/config_scripts/generators/migrations.rb +36 -0
  15. data/lib/config_scripts/generators.rb +2 -0
  16. data/lib/config_scripts/scripts/script.rb +135 -0
  17. data/lib/config_scripts/scripts/script_history.rb +39 -0
  18. data/lib/config_scripts/scripts.rb +9 -0
  19. data/lib/config_scripts/seeds/seed_set.rb +321 -0
  20. data/lib/config_scripts/seeds/seed_type.rb +361 -0
  21. data/lib/config_scripts/seeds.rb +8 -0
  22. data/lib/config_scripts/tasks/pending_migrations.rake +11 -0
  23. data/lib/config_scripts/tasks/seeds.rake +18 -0
  24. data/lib/config_scripts/tasks.rb +12 -0
  25. data/lib/config_scripts/version.rb +4 -0
  26. data/lib/config_scripts.rb +9 -0
  27. data/spec/dummy/README.rdoc +28 -0
  28. data/spec/dummy/Rakefile +6 -0
  29. data/spec/dummy/app/assets/images/.keep +0 -0
  30. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  31. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  32. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  33. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  34. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  35. data/spec/dummy/app/mailers/.keep +0 -0
  36. data/spec/dummy/app/models/.keep +0 -0
  37. data/spec/dummy/app/models/concerns/.keep +0 -0
  38. data/spec/dummy/app/models/hair_color.rb +2 -0
  39. data/spec/dummy/app/models/person.rb +4 -0
  40. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  41. data/spec/dummy/bin/bundle +3 -0
  42. data/spec/dummy/bin/rails +4 -0
  43. data/spec/dummy/bin/rake +4 -0
  44. data/spec/dummy/config/application.rb +23 -0
  45. data/spec/dummy/config/boot.rb +5 -0
  46. data/spec/dummy/config/database.yml +25 -0
  47. data/spec/dummy/config/environment.rb +5 -0
  48. data/spec/dummy/config/environments/development.rb +29 -0
  49. data/spec/dummy/config/environments/production.rb +80 -0
  50. data/spec/dummy/config/environments/test.rb +36 -0
  51. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  52. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  53. data/spec/dummy/config/initializers/inflections.rb +16 -0
  54. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  55. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  56. data/spec/dummy/config/initializers/session_store.rb +3 -0
  57. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  58. data/spec/dummy/config/locales/en.yml +23 -0
  59. data/spec/dummy/config/routes.rb +56 -0
  60. data/spec/dummy/config.ru +4 -0
  61. data/spec/dummy/db/migrate/20140208014550_create_config_scripts.rb +7 -0
  62. data/spec/dummy/db/migrate/20140208161829_create_people.rb +9 -0
  63. data/spec/dummy/db/migrate/20140208182050_create_hair_colors.rb +9 -0
  64. data/spec/dummy/db/migrate/20140208182101_add_hair_color_to_person.rb +6 -0
  65. data/spec/dummy/db/migrate/20140208225801_add_scope_to_people.rb +6 -0
  66. data/spec/dummy/db/migrate/20140209132911_add_hex_value_to_hair_color.rb +5 -0
  67. data/spec/dummy/db/schema.rb +38 -0
  68. data/spec/dummy/lib/assets/.keep +0 -0
  69. data/spec/dummy/log/.keep +0 -0
  70. data/spec/dummy/public/404.html +58 -0
  71. data/spec/dummy/public/422.html +58 -0
  72. data/spec/dummy/public/500.html +57 -0
  73. data/spec/dummy/public/favicon.ico +0 -0
  74. data/spec/generators/config_script_spec.rb +23 -0
  75. data/spec/generators/migrations_spec.rb +23 -0
  76. data/spec/scripts/script_history_spec.rb +53 -0
  77. data/spec/scripts/script_spec.rb +282 -0
  78. data/spec/seeds/seed_set_spec.rb +371 -0
  79. data/spec/seeds/seed_type_spec.rb +439 -0
  80. data/spec/spec_helper.rb +38 -0
  81. data/templates/config_script.rb +9 -0
  82. data/templates/create_config_scripts_migration.rb +7 -0
  83. metadata +321 -0
@@ -0,0 +1,58 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The page you were looking for doesn't exist (404)</title>
5
+ <style>
6
+ body {
7
+ background-color: #EFEFEF;
8
+ color: #2E2F30;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ margin: 4em auto 0 auto;
16
+ border: 1px solid #CCC;
17
+ border-right-color: #999;
18
+ border-left-color: #999;
19
+ border-bottom-color: #BBB;
20
+ border-top: #B00100 solid 4px;
21
+ border-top-left-radius: 9px;
22
+ border-top-right-radius: 9px;
23
+ background-color: white;
24
+ padding: 7px 4em 0 4em;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 100%;
29
+ color: #730E15;
30
+ line-height: 1.5em;
31
+ }
32
+
33
+ body > p {
34
+ width: 33em;
35
+ margin: 0 auto 1em;
36
+ padding: 1em 0;
37
+ background-color: #F7F7F7;
38
+ border: 1px solid #CCC;
39
+ border-right-color: #999;
40
+ border-bottom-color: #999;
41
+ border-bottom-left-radius: 4px;
42
+ border-bottom-right-radius: 4px;
43
+ border-top-color: #DADADA;
44
+ color: #666;
45
+ box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
46
+ }
47
+ </style>
48
+ </head>
49
+
50
+ <body>
51
+ <!-- This file lives in public/404.html -->
52
+ <div class="dialog">
53
+ <h1>The page you were looking for doesn't exist.</h1>
54
+ <p>You may have mistyped the address or the page may have moved.</p>
55
+ </div>
56
+ <p>If you are the application owner check the logs for more information.</p>
57
+ </body>
58
+ </html>
@@ -0,0 +1,58 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <style>
6
+ body {
7
+ background-color: #EFEFEF;
8
+ color: #2E2F30;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ margin: 4em auto 0 auto;
16
+ border: 1px solid #CCC;
17
+ border-right-color: #999;
18
+ border-left-color: #999;
19
+ border-bottom-color: #BBB;
20
+ border-top: #B00100 solid 4px;
21
+ border-top-left-radius: 9px;
22
+ border-top-right-radius: 9px;
23
+ background-color: white;
24
+ padding: 7px 4em 0 4em;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 100%;
29
+ color: #730E15;
30
+ line-height: 1.5em;
31
+ }
32
+
33
+ body > p {
34
+ width: 33em;
35
+ margin: 0 auto 1em;
36
+ padding: 1em 0;
37
+ background-color: #F7F7F7;
38
+ border: 1px solid #CCC;
39
+ border-right-color: #999;
40
+ border-bottom-color: #999;
41
+ border-bottom-left-radius: 4px;
42
+ border-bottom-right-radius: 4px;
43
+ border-top-color: #DADADA;
44
+ color: #666;
45
+ box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
46
+ }
47
+ </style>
48
+ </head>
49
+
50
+ <body>
51
+ <!-- This file lives in public/422.html -->
52
+ <div class="dialog">
53
+ <h1>The change you wanted was rejected.</h1>
54
+ <p>Maybe you tried to change something you didn't have access to.</p>
55
+ </div>
56
+ <p>If you are the application owner check the logs for more information.</p>
57
+ </body>
58
+ </html>
@@ -0,0 +1,57 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <style>
6
+ body {
7
+ background-color: #EFEFEF;
8
+ color: #2E2F30;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ margin: 4em auto 0 auto;
16
+ border: 1px solid #CCC;
17
+ border-right-color: #999;
18
+ border-left-color: #999;
19
+ border-bottom-color: #BBB;
20
+ border-top: #B00100 solid 4px;
21
+ border-top-left-radius: 9px;
22
+ border-top-right-radius: 9px;
23
+ background-color: white;
24
+ padding: 7px 4em 0 4em;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 100%;
29
+ color: #730E15;
30
+ line-height: 1.5em;
31
+ }
32
+
33
+ body > p {
34
+ width: 33em;
35
+ margin: 0 auto 1em;
36
+ padding: 1em 0;
37
+ background-color: #F7F7F7;
38
+ border: 1px solid #CCC;
39
+ border-right-color: #999;
40
+ border-bottom-color: #999;
41
+ border-bottom-left-radius: 4px;
42
+ border-bottom-right-radius: 4px;
43
+ border-top-color: #DADADA;
44
+ color: #666;
45
+ box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
46
+ }
47
+ </style>
48
+ </head>
49
+
50
+ <body>
51
+ <!-- This file lives in public/500.html -->
52
+ <div class="dialog">
53
+ <h1>We're sorry, but something went wrong.</h1>
54
+ </div>
55
+ <p>If you are the application owner check the logs for more information.</p>
56
+ </body>
57
+ </html>
File without changes
@@ -0,0 +1,23 @@
1
+ require 'generator_spec'
2
+
3
+ describe ConfigScripts::ConfigScriptGenerator, type: :generator do
4
+ destination File.expand_path("../../../tmp", __FILE__)
5
+ arguments ['TestConfigScript']
6
+
7
+ describe "config_script" do
8
+ let(:expected_path) { "db/config_scripts/#{Time.now.to_s(:number)}_test_config_script.rb" }
9
+ before do
10
+ prepare_destination
11
+ Timecop.freeze
12
+ run_generator
13
+ end
14
+
15
+ after do
16
+ Timecop.return
17
+ end
18
+
19
+ it "creates a file in the config_scripts directory, with a config script class" do
20
+ assert_file expected_path, /class TestConfigScriptConfig < ConfigScripts::Scripts::Script/
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ describe ConfigScripts::MigrationsGenerator, type: :generator do
2
+ destination File.expand_path("../../../tmp", __FILE__)
3
+
4
+ describe "create_migrations" do
5
+ before do
6
+ prepare_destination
7
+ run_generator
8
+ end
9
+
10
+ it "creates a migration for adding the config scripts table" do
11
+ assert_file "db/migrate/#{Time.now.to_s(:number)}_create_config_scripts.rb", /create_table :config_scripts/
12
+ end
13
+
14
+ context "when running repeatedly" do
15
+ it "says that it has skipped it" do
16
+ output = capture :stderr do
17
+ run_generator
18
+ end
19
+ expect(output).to be =~ /Another migration is already named create_config_scripts/
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,53 @@
1
+ describe ConfigScripts::Scripts::ScriptHistory do
2
+ let(:klass) { ConfigScripts::Scripts::ScriptHistory }
3
+ let(:timestamp1) { 5.minutes.ago.to_s(:number) }
4
+ let(:timestamp2) { 10.minutes.ago.to_s(:number) }
5
+
6
+ describe "entries_for_timestamp" do
7
+ let!(:entry1) { klass.create(name: timestamp1) }
8
+ let!(:entry2) { klass.create(name: timestamp1) }
9
+ let!(:entry3) { klass.create(name: timestamp2) }
10
+
11
+ subject { klass.entries_for_timestamp(timestamp1) }
12
+
13
+ it "gets all the entries whose timestamp has the value given" do
14
+ expect(subject).to include entry1
15
+ expect(subject).to include entry2
16
+ end
17
+
18
+ it "does not include entries with other timestamps" do
19
+ expect(subject).not_to include entry3
20
+ end
21
+ end
22
+
23
+ describe "script_was_run?" do
24
+ let!(:entry1) { klass.create(name: timestamp2) }
25
+
26
+ context "with a timestamp that has an entry in the table" do
27
+ subject { klass.script_was_run?(timestamp2) }
28
+ it { should be_true }
29
+ end
30
+
31
+ context "with a timestamp that has no entry in the table" do
32
+ subject { klass.script_was_run?(timestamp1) }
33
+ it { should be_false }
34
+ end
35
+ end
36
+
37
+ describe "record_timestamp" do
38
+ it "adds an entry to the table" do
39
+ expect(klass.script_was_run?(timestamp1)).to be_false
40
+ klass.record_timestamp(timestamp1)
41
+ expect(klass.script_was_run?(timestamp1)).to be_true
42
+ end
43
+ end
44
+
45
+ describe "remove_timestamp" do
46
+ it "removes the entry from the table" do
47
+ klass.create(name: timestamp2)
48
+ expect(klass.script_was_run?(timestamp2)).to be_true
49
+ klass.remove_timestamp(timestamp2)
50
+ expect(klass.script_was_run?(timestamp2)).to be_false
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,282 @@
1
+ describe ConfigScripts::Scripts::Script do
2
+ let(:klass) { ConfigScripts::Scripts::Script }
3
+
4
+ describe "class methods" do
5
+ describe "script_directory" do
6
+ subject { klass.script_directory}
7
+ it "is the db/config_scripts directory" do
8
+ expect(subject).to eq Rails.root.join('db', 'config_scripts')
9
+ end
10
+ end
11
+
12
+ describe "pending_scripts" do
13
+ let!(:filename1) { "20140208150000_script_1" }
14
+ let!(:filename2) { "20140208200000_script_2" }
15
+
16
+ subject { klass.pending_scripts }
17
+
18
+ before do
19
+ Dir.stub glob: ["/tmp/#{filename1}.rb", "/tmp/#{filename2}.rb"]
20
+ ConfigScripts::Scripts::ScriptHistory.record_timestamp('20140208150000')
21
+ end
22
+
23
+ it "uses Dir to get the files" do
24
+ subject
25
+ expect(Dir).to have_received(:glob).with(File.join(klass.script_directory, "*.rb"))
26
+ end
27
+
28
+ it "includes filenames that don't have entries in the script histories" do
29
+ expect(subject).to include filename2
30
+ end
31
+
32
+ it "does not include filenames that have entries in the script history" do
33
+ expect(subject).not_to include filename1
34
+ end
35
+ end
36
+
37
+ describe "run_pending_scripts" do
38
+ class TestConfigScriptConfig < ConfigScripts::Scripts::Script; end
39
+
40
+ let!(:timestamp1) { '20140208150000' }
41
+ let!(:timestamp2) { '20140208200000' }
42
+ let!(:timestamp3) { '20140208250000' }
43
+
44
+ let(:script_filenames) { [timestamp1, timestamp2, timestamp3].collect { |stamp| "#{stamp}_test_config_script" } }
45
+
46
+ let!(:script1) { TestConfigScriptConfig.new(timestamp1) }
47
+ let!(:script2) { TestConfigScriptConfig.new(timestamp2) }
48
+ let!(:script3) { TestConfigScriptConfig.new(timestamp3) }
49
+
50
+ before do
51
+ klass.stub pending_scripts: script_filenames
52
+ klass.stub :require
53
+ klass.stub :puts
54
+ [script1, script2, script3].each do |script|
55
+ script.stub(:run)
56
+ end
57
+
58
+ TestConfigScriptConfig.stub(:new).with(timestamp1).and_return(script1)
59
+ TestConfigScriptConfig.stub(:new).with(timestamp2).and_return(script2)
60
+ TestConfigScriptConfig.stub(:new).with(timestamp3).and_return(script3)
61
+
62
+ FileUtils.mkdir_p(Rails.root.join("tmp", "cache"))
63
+ end
64
+
65
+ let(:scripts) {[
66
+ {
67
+ filename: script_filenames[0],
68
+ script: script1,
69
+ run: true
70
+ },
71
+ {
72
+ filename: script_filenames[1],
73
+ script: script2,
74
+ run: true
75
+ },
76
+ {
77
+ filename: script_filenames[2],
78
+ script: script3,
79
+ run: true
80
+ }
81
+ ]}
82
+
83
+
84
+ shared_examples "ran scripts" do
85
+ it "requires only the scripts it needs to run" do
86
+ scripts.each do |script|
87
+ path = Rails.root.join("db", "config_scripts", "#{script[:filename]}.rb")
88
+ if script[:run]
89
+ expect(klass).to have_received(:require).with(path)
90
+ else
91
+ expect(klass).not_to have_received(:require).with(path)
92
+ end
93
+ end
94
+ end
95
+
96
+ it "creates a config script for each timestamp with the appropriate class" do
97
+ scripts.each do |script|
98
+ timestamp = script[:filename].first(14)
99
+ if script[:run]
100
+ expect(TestConfigScriptConfig).to have_received(:new).with(timestamp)
101
+ else
102
+ expect(TestConfigScriptConfig).not_to have_received(:new).with(timestamp)
103
+ end
104
+ end
105
+ end
106
+
107
+ it "calls the up command on each script item" do
108
+ scripts.each do |script|
109
+ if script[:run]
110
+ expect(script[:script]).to have_received(:run).with(:up)
111
+ else
112
+ expect(script[:script]).not_to have_received(:run)
113
+ end
114
+ end
115
+ end
116
+
117
+ it "outputs the name of the scripts that it is running" do
118
+ scripts.each do |script|
119
+ if script[:run]
120
+ expect(klass).to have_received(:puts).with("Running #{script[:filename]}")
121
+ else
122
+ expect(klass).not_to have_received(:puts).with("Running #{script[:filename]}")
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ context "with no problems running the scripts" do
129
+ it_behaves_like "ran scripts"
130
+
131
+ before do
132
+ klass.run_pending_scripts
133
+ end
134
+ end
135
+
136
+ context "with a problems running the scripts" do
137
+ it_behaves_like "ran scripts"
138
+
139
+ before do
140
+ script2.stub(:run).and_raise 'Error in script'
141
+ scripts[2][:run] = false
142
+ begin
143
+ klass.run_pending_scripts
144
+ rescue
145
+ end
146
+ end
147
+ end
148
+
149
+ context "with a class name it cannot find" do
150
+ let(:bad_filename) { "20140208170000_missing_class" }
151
+
152
+ before do
153
+ scripts[1][:run] = false
154
+ scripts[2][:run] = false
155
+ klass.stub pending_scripts: [script_filenames[0], bad_filename, script_filenames[1], script_filenames[2]]
156
+ klass.run_pending_scripts
157
+ end
158
+
159
+ it_behaves_like "ran scripts"
160
+
161
+ it "requires the path for the bad script" do
162
+ path = Rails.root.join("db", "config_scripts", "#{bad_filename}.rb")
163
+ expect(klass).to have_received(:require).with(path)
164
+ end
165
+
166
+ it "outputs a name error for the missing class" do
167
+ expect(klass).to have_received(:puts).with("Aborting: could not find class MissingClassConfig")
168
+ end
169
+ end
170
+ end
171
+
172
+ describe "list_pending_scripts" do
173
+ before do
174
+ klass.stub pending_scripts: ['script1.rb', 'script2.rb']
175
+ klass.stub :puts
176
+ klass.list_pending_scripts
177
+ end
178
+
179
+ it "prints out the name of each script" do
180
+ expect(klass).to have_received(:puts).with('script1.rb')
181
+ expect(klass).to have_received(:puts).with('script2.rb')
182
+ end
183
+ end
184
+ end
185
+
186
+ describe "creating" do
187
+ let(:timestamp) { '20140101153500' }
188
+ subject { klass.new(timestamp) }
189
+
190
+ it "sets the timestamp" do
191
+ expect(subject.timestamp).to eq timestamp
192
+ end
193
+ end
194
+
195
+ describe "running" do
196
+ let(:timestamp) { 1.day.ago.to_s(:number)}
197
+ let(:script) { ConfigScripts::Scripts::Script.new(timestamp) }
198
+
199
+ describe "up" do
200
+ it "raises an exception" do
201
+ expect(lambda{script.up}).to raise_exception("Not supported")
202
+ end
203
+ end
204
+
205
+ describe "down" do
206
+ it "raises an exception" do
207
+ expect(lambda{script.down}).to raise_exception("Not supported")
208
+ end
209
+ end
210
+
211
+ describe "run" do
212
+ {up: true, down: false}.each do |direction, expect_timestamp|
213
+ describe "direction" do
214
+ before do
215
+ if !expect_timestamp
216
+ ConfigScripts::Scripts::ScriptHistory.record_timestamp(timestamp)
217
+ end
218
+
219
+ script.stub :puts
220
+
221
+ Rails.cache.write("cached_item", "cached_value")
222
+ end
223
+
224
+ context "with a success" do
225
+ before do
226
+ script.stub(direction) do
227
+ Person.create(name: 'John Doe')
228
+ end
229
+ script.run(direction)
230
+ end
231
+
232
+ it "performs the changes in the #{direction} method" do
233
+ expect(Person.count).to eq 1
234
+ expect(Person.first.name).to eq "John Doe"
235
+ end
236
+
237
+ it "cleares the cache" do
238
+ expect(Rails.cache.read("cached_item")).to be_nil
239
+ end
240
+
241
+ it "{expect_timestamp ? 'adds' : 'removes'} the timestamp" do
242
+ expect(ConfigScripts::Scripts::ScriptHistory.script_was_run?(timestamp)).to eq expect_timestamp
243
+ end
244
+ end
245
+
246
+ context "with an exception in the #{direction} method" do
247
+ before do
248
+ script.stub(direction) do
249
+ Person.create(name: 'John Doe')
250
+ raise
251
+ end
252
+ end
253
+
254
+ it "re-raises the exception" do
255
+ expect(lambda{script.run(direction)}).to raise_exception
256
+ end
257
+
258
+ it "does not persist the changes in the #{direction} method" do
259
+ script.run(direction) rescue nil
260
+ expect(Person.count).to eq 0
261
+ end
262
+
263
+ it "does not clear the cache" do
264
+ script.run(direction) rescue nil
265
+ expect(Rails.cache.read('cached_item')).to eq 'cached_value'
266
+ end
267
+
268
+ it "does not #{expect_timestamp ? 'add' : 'remove'} the timestamp" do
269
+ script.run(direction) rescue nil
270
+ expect(ConfigScripts::Scripts::ScriptHistory.script_was_run?(timestamp)).not_to eq expect_timestamp
271
+ end
272
+
273
+ it "puts an error out to the logs" do
274
+ script.run(direction) rescue nil
275
+ expect(script).to have_received(:puts).with("Error running script for ConfigScripts::Scripts::Script: ")
276
+ end
277
+ end
278
+ end
279
+ end
280
+ end
281
+ end
282
+ end