tern 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/MIT-LICENSE +20 -0
- data/README.markdown +189 -0
- data/Rakefile +2 -0
- data/bin/tern +6 -0
- data/lib/tern.rb +207 -0
- data/lib/tern/app.rb +65 -0
- data/lib/tern/generators/change.sql +4 -0
- data/lib/tern/generators/new/alterations/.empty_directory +0 -0
- data/lib/tern/generators/new/alterations/001_create_people.sql.example +16 -0
- data/lib/tern/generators/new/config.yml.tt +15 -0
- data/lib/tern/generators/new/definitions/sequence.yml +18 -0
- data/lib/tern/generators/new/definitions/ultimate_answer.sql.example +7 -0
- data/spec/projects/alterations/alterations/001_create_people.sql +8 -0
- data/spec/projects/alterations/alterations/002_create_animals.sql +8 -0
- data/spec/projects/alterations/alterations/003_create_plants.sql +8 -0
- data/spec/projects/alterations/config.yml +15 -0
- data/spec/projects/alterations/definitions/sequence.yml +18 -0
- data/spec/projects/alterations/definitions/ultimate_answer.sql.example +7 -0
- data/spec/projects/definitions/alterations/001_create_people.sql.example +16 -0
- data/spec/projects/definitions/config.yml +15 -0
- data/spec/projects/definitions/definitions/sequence.yml +19 -0
- data/spec/projects/definitions/definitions/ultimate_answer.sql +7 -0
- data/spec/projects/dependencies_1/alterations/001_create_widgets.sql +9 -0
- data/spec/projects/dependencies_1/config.yml +15 -0
- data/spec/projects/dependencies_1/definitions/sequence.yml +19 -0
- data/spec/projects/dependencies_1/definitions/ultimate_answer.sql.example +7 -0
- data/spec/projects/dependencies_1/definitions/widgets_view.sql +5 -0
- data/spec/projects/dependencies_2/alterations/001_create_widgets.sql +9 -0
- data/spec/projects/dependencies_2/config.yml +15 -0
- data/spec/projects/dependencies_2/definitions/sequence.yml +18 -0
- data/spec/projects/dependencies_2/definitions/ultimate_answer.sql.example +7 -0
- data/spec/projects/duplicated_alteration/alterations/001_create_people.sql +8 -0
- data/spec/projects/duplicated_alteration/alterations/002_create_animals.sql +8 -0
- data/spec/projects/duplicated_alteration/alterations/002_create_plants.sql +8 -0
- data/spec/projects/duplicated_alteration/config.yml +15 -0
- data/spec/projects/duplicated_alteration/definitions/sequence.yml +18 -0
- data/spec/projects/duplicated_alteration/definitions/ultimate_answer.sql.example +7 -0
- data/spec/projects/irreversible_alterations/alterations/001_create_people.sql +8 -0
- data/spec/projects/irreversible_alterations/alterations/002_create_animals.sql +4 -0
- data/spec/projects/irreversible_alterations/alterations/003_create_plants.sql +8 -0
- data/spec/projects/irreversible_alterations/config.yml +15 -0
- data/spec/projects/irreversible_alterations/definitions/sequence.yml +18 -0
- data/spec/projects/irreversible_alterations/definitions/ultimate_answer.sql.example +7 -0
- data/spec/projects/missing_alteration/alterations/001_create_people.sql +8 -0
- data/spec/projects/missing_alteration/alterations/003_create_plants.sql +8 -0
- data/spec/projects/missing_alteration/config.yml +15 -0
- data/spec/projects/missing_alteration/definitions/sequence.yml +18 -0
- data/spec/projects/missing_alteration/definitions/ultimate_answer.sql.example +7 -0
- data/spec/projects/multiple_sequences/alterations/001_create_people.sql.example +16 -0
- data/spec/projects/multiple_sequences/config.yml +15 -0
- data/spec/projects/multiple_sequences/definitions/create_view_a.sql +5 -0
- data/spec/projects/multiple_sequences/definitions/create_view_b.sql +5 -0
- data/spec/projects/multiple_sequences/definitions/sequence.yml +21 -0
- data/spec/projects/multiple_sequences/definitions/ultimate_answer.sql.example +7 -0
- data/spec/projects/new/alterations/001_create_people.sql.example +16 -0
- data/spec/projects/new/config.yml +15 -0
- data/spec/projects/new/definitions/sequence.yml +18 -0
- data/spec/projects/new/definitions/ultimate_answer.sql.example +7 -0
- data/spec/projects/no_alterations/alterations/001_create_people.sql.example +16 -0
- data/spec/projects/no_alterations/config.yml +15 -0
- data/spec/projects/no_alterations/definitions/sequence.yml +18 -0
- data/spec/projects/no_alterations/definitions/ultimate_answer.sql.example +7 -0
- data/spec/tern_spec.rb +215 -0
- data/tern.gemspec +23 -0
- metadata +174 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
# Put the relative path to your definition files in the sequence they should run.
|
2
|
+
#
|
3
|
+
# Most definitions should go in the default list. These will be dropped and
|
4
|
+
# recreated every migration.
|
5
|
+
#
|
6
|
+
# Definitions that should not automatically be dropped and created can be put in
|
7
|
+
# different lists. This is useful for definitions that make take prohibitively
|
8
|
+
# to drop and create every migration such as check constraints.
|
9
|
+
#
|
10
|
+
# Run alternative sequences by specifying sequences in order to migrate command.
|
11
|
+
# Example: rake migrate sequences=expensive,default
|
12
|
+
#
|
13
|
+
# default:
|
14
|
+
# - ultimate_answer.sql
|
15
|
+
# expensive:
|
16
|
+
# - super_slow_check_constraint.sql
|
17
|
+
|
18
|
+
default: []
|
@@ -0,0 +1,15 @@
|
|
1
|
+
alterations:
|
2
|
+
table: tern_alterations
|
3
|
+
column: version
|
4
|
+
definitions:
|
5
|
+
table: tern_definitions
|
6
|
+
environments:
|
7
|
+
development:
|
8
|
+
adapter: postgres
|
9
|
+
database: tern_test_development
|
10
|
+
test:
|
11
|
+
adapter: postgres
|
12
|
+
database: tern_test_test
|
13
|
+
production:
|
14
|
+
adapter: postgres
|
15
|
+
database: tern_test_production
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Put the relative path to your definition files in the sequence they should run.
|
2
|
+
#
|
3
|
+
# Most definitions should go in the default list. These will be dropped and
|
4
|
+
# recreated every migration.
|
5
|
+
#
|
6
|
+
# Definitions that should not automatically be dropped and created can be put in
|
7
|
+
# different lists. This is useful for definitions that make take prohibitively
|
8
|
+
# to drop and create every migration such as check constraints.
|
9
|
+
#
|
10
|
+
# Run alternative sequences by specifying sequences in order to migrate command.
|
11
|
+
# Example: rake migrate sequences=expensive,default
|
12
|
+
#
|
13
|
+
# default:
|
14
|
+
# - ultimate_answer.sql
|
15
|
+
# expensive:
|
16
|
+
# - super_slow_check_constraint.sql
|
17
|
+
|
18
|
+
default: []
|
@@ -0,0 +1,15 @@
|
|
1
|
+
alterations:
|
2
|
+
table: tern_alterations
|
3
|
+
column: version
|
4
|
+
definitions:
|
5
|
+
table: tern_definitions
|
6
|
+
environments:
|
7
|
+
development:
|
8
|
+
adapter: postgres
|
9
|
+
database: tern_test_development
|
10
|
+
test:
|
11
|
+
adapter: postgres
|
12
|
+
database: tern_test_test
|
13
|
+
production:
|
14
|
+
adapter: postgres
|
15
|
+
database: tern_test_production
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# Put the relative path to your definition files in the sequence they should run.
|
2
|
+
#
|
3
|
+
# Most definitions should go in the default list. These will be dropped and
|
4
|
+
# recreated every migration.
|
5
|
+
#
|
6
|
+
# Definitions that should not automatically be dropped and created can be put in
|
7
|
+
# different lists. This is useful for definitions that make take prohibitively
|
8
|
+
# to drop and create every migration such as check constraints.
|
9
|
+
#
|
10
|
+
# Run alternative sequences by specifying sequences in order to migrate command.
|
11
|
+
# Example: rake migrate sequences=expensive,default
|
12
|
+
#
|
13
|
+
# default:
|
14
|
+
# - ultimate_answer.sql
|
15
|
+
# expensive:
|
16
|
+
# - super_slow_check_constraint.sql
|
17
|
+
|
18
|
+
default:
|
19
|
+
- create_view_b.sql
|
20
|
+
expensive:
|
21
|
+
- create_view_a.sql
|
@@ -0,0 +1,15 @@
|
|
1
|
+
alterations:
|
2
|
+
table: tern_alterations
|
3
|
+
column: version
|
4
|
+
definitions:
|
5
|
+
table: tern_definitions
|
6
|
+
environments:
|
7
|
+
development:
|
8
|
+
adapter: postgres
|
9
|
+
database: tern_test_development
|
10
|
+
test:
|
11
|
+
adapter: postgres
|
12
|
+
database: tern_test_test
|
13
|
+
production:
|
14
|
+
adapter: postgres
|
15
|
+
database: tern_test_production
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Put the relative path to your definition files in the sequence they should run.
|
2
|
+
#
|
3
|
+
# Most definitions should go in the default list. These will be dropped and
|
4
|
+
# recreated every migration.
|
5
|
+
#
|
6
|
+
# Definitions that should not automatically be dropped and created can be put in
|
7
|
+
# different lists. This is useful for definitions that make take prohibitively
|
8
|
+
# to drop and create every migration such as check constraints.
|
9
|
+
#
|
10
|
+
# Run alternative sequences by specifying sequences in order to migrate command.
|
11
|
+
# Example: rake migrate sequences=expensive,default
|
12
|
+
#
|
13
|
+
# default:
|
14
|
+
# - ultimate_answer.sql
|
15
|
+
# expensive:
|
16
|
+
# - super_slow_check_constraint.sql
|
17
|
+
|
18
|
+
default: []
|
@@ -0,0 +1,15 @@
|
|
1
|
+
alterations:
|
2
|
+
table: tern_alterations
|
3
|
+
column: version
|
4
|
+
definitions:
|
5
|
+
table: tern_definitions
|
6
|
+
environments:
|
7
|
+
development:
|
8
|
+
adapter: postgres
|
9
|
+
database: tern_test_development
|
10
|
+
test:
|
11
|
+
adapter: postgres
|
12
|
+
database: tern_test_test
|
13
|
+
production:
|
14
|
+
adapter: postgres
|
15
|
+
database: tern_test_production
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Put the relative path to your definition files in the sequence they should run.
|
2
|
+
#
|
3
|
+
# Most definitions should go in the default list. These will be dropped and
|
4
|
+
# recreated every migration.
|
5
|
+
#
|
6
|
+
# Definitions that should not automatically be dropped and created can be put in
|
7
|
+
# different lists. This is useful for definitions that make take prohibitively
|
8
|
+
# to drop and create every migration such as check constraints.
|
9
|
+
#
|
10
|
+
# Run alternative sequences by specifying sequences in order to migrate command.
|
11
|
+
# Example: rake migrate sequences=expensive,default
|
12
|
+
#
|
13
|
+
# default:
|
14
|
+
# - ultimate_answer.sql
|
15
|
+
# expensive:
|
16
|
+
# - super_slow_check_constraint.sql
|
17
|
+
|
18
|
+
default: []
|
data/spec/tern_spec.rb
ADDED
@@ -0,0 +1,215 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'sequel'
|
4
|
+
require 'tern'
|
5
|
+
|
6
|
+
$tmpdir = 'spec/tmp/' + Time.now.strftime("%Y-%m-%d-%H-%M-%S")
|
7
|
+
FileUtils.mkdir_p $tmpdir
|
8
|
+
|
9
|
+
RSpec.configure do |config|
|
10
|
+
def tern(args="")
|
11
|
+
lib = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
12
|
+
bin = File.expand_path(File.join(File.dirname(__FILE__), '..', 'bin', 'tern'))
|
13
|
+
`ruby -I #{lib} #{bin} #{args}`
|
14
|
+
end
|
15
|
+
|
16
|
+
def tern_migrate(path, args="")
|
17
|
+
Dir.chdir(path) do
|
18
|
+
tern "migrate #{args}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def tern_generate(path, args="")
|
23
|
+
Dir.chdir(path) do
|
24
|
+
tern "generate #{args}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def tmpdir
|
29
|
+
$tmpdir
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "Change" do
|
34
|
+
describe "parse" do
|
35
|
+
it "splits on SPLIT_MARKER" do
|
36
|
+
::Change.parse("create #{::Change::SPLIT_MARKER} drop").should == ["create ", " drop"]
|
37
|
+
end
|
38
|
+
|
39
|
+
it "returns entire string as create if no SPLIT_MARKER not found" do
|
40
|
+
::Change.parse("create").should == ["create", nil]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "tern" do
|
46
|
+
it "displays task list when called without arguments" do
|
47
|
+
tern.should match(/Tasks/)
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "new" do
|
51
|
+
it "creates a new project at path" do
|
52
|
+
Dir.chdir(tmpdir) do
|
53
|
+
tern "new tern_spec"
|
54
|
+
File.exist?("tern_spec").should be_true
|
55
|
+
File.exist?("tern_spec/alterations").should be_true
|
56
|
+
File.exist?("tern_spec/definitions").should be_true
|
57
|
+
File.exist?("tern_spec/config.yml").should be_true
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "generate" do
|
63
|
+
before(:each) do |example|
|
64
|
+
@project_path = File.expand_path(File.join(tmpdir, example.object_id.to_s))
|
65
|
+
tern "new #{@project_path}"
|
66
|
+
end
|
67
|
+
|
68
|
+
it "prints an error message if config.yml is not found" do
|
69
|
+
tern_generate("spec/tmp", "alteration create_people").should match(/This directory does not appear to be a Tern project. config.yml not found./)
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "alteration" do
|
73
|
+
it "creates alteration file with next available number prefixing name" do
|
74
|
+
tern_generate(@project_path, "alteration create_widgets")
|
75
|
+
File.exist?(File.join(@project_path, "alterations", "001_create_widgets.sql")).should be_true
|
76
|
+
tern_generate(@project_path, "alteration create_sprockets")
|
77
|
+
File.exist?(File.join(@project_path, "alterations", "002_create_sprockets.sql")).should be_true
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "definition" do
|
82
|
+
it "creates definition file" do
|
83
|
+
tern_generate(@project_path, "definition create_a_view")
|
84
|
+
File.exist?(File.join(@project_path, "definitions", "create_a_view.sql")).should be_true
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "migrate" do
|
90
|
+
before(:each) do
|
91
|
+
`createdb tern_test_development`
|
92
|
+
@dev_db = Sequel.connect :adapter => :postgres, :database => 'tern_test_development'
|
93
|
+
end
|
94
|
+
|
95
|
+
after(:each) do
|
96
|
+
@dev_db.disconnect
|
97
|
+
`dropdb tern_test_development`
|
98
|
+
end
|
99
|
+
|
100
|
+
it "prints an error message if config.yml is not found" do
|
101
|
+
tern_migrate("spec/tmp").should match(/This directory does not appear to be a Tern project. config.yml not found./)
|
102
|
+
end
|
103
|
+
|
104
|
+
it "works without any alterations" do
|
105
|
+
tern_migrate("spec/projects/no_alterations").should be_empty
|
106
|
+
end
|
107
|
+
|
108
|
+
it "creates definitions table on first run" do
|
109
|
+
tern_migrate "spec/projects/new"
|
110
|
+
@dev_db.tables.should include(:tern_definitions)
|
111
|
+
end
|
112
|
+
|
113
|
+
it "creates alterations table on first run" do
|
114
|
+
tern_migrate "spec/projects/new"
|
115
|
+
@dev_db.tables.should include(:tern_alterations)
|
116
|
+
end
|
117
|
+
|
118
|
+
it "applies alterations" do
|
119
|
+
tern_migrate "spec/projects/alterations"
|
120
|
+
@dev_db.tables.should include(:people, :animals, :plants)
|
121
|
+
end
|
122
|
+
|
123
|
+
it "applies alterations to version n" do
|
124
|
+
tern_migrate "spec/projects/alterations", "-a 1"
|
125
|
+
@dev_db.tables.should include(:people)
|
126
|
+
tern_migrate "spec/projects/alterations", "-a 3"
|
127
|
+
@dev_db.tables.should include(:people, :animals, :plants)
|
128
|
+
end
|
129
|
+
|
130
|
+
it "reverts all alterations" do
|
131
|
+
tern_migrate "spec/projects/alterations"
|
132
|
+
tern_migrate "spec/projects/alterations", "-a 0"
|
133
|
+
@dev_db.tables.should_not include(:people, :animals, :plants)
|
134
|
+
end
|
135
|
+
|
136
|
+
it "reverts alterations to version n" do
|
137
|
+
tern_migrate "spec/projects/alterations"
|
138
|
+
tern_migrate "spec/projects/alterations", "-a 1"
|
139
|
+
@dev_db.tables.should include(:people)
|
140
|
+
@dev_db.tables.should_not include(:animals, :plants)
|
141
|
+
end
|
142
|
+
|
143
|
+
it "prints an error message when attempting to revert an irreversible alteration" do
|
144
|
+
tern_migrate "spec/projects/irreversible_alterations"
|
145
|
+
tern_migrate("spec/projects/irreversible_alterations", "-a 0").should match /Alteration 002 is irreversible/
|
146
|
+
end
|
147
|
+
|
148
|
+
it "prints an error message when missing alteration" do
|
149
|
+
tern_migrate("spec/projects/missing_alteration").should match /Alteration 002 is missing/
|
150
|
+
end
|
151
|
+
|
152
|
+
it "prints an error message when alteration version is duplicated" do
|
153
|
+
tern_migrate("spec/projects/duplicated_alteration").should match /Alteration 002 is duplicated/
|
154
|
+
end
|
155
|
+
|
156
|
+
it "uses environment parameter" do
|
157
|
+
`createdb tern_test_test`
|
158
|
+
test_db = Sequel.connect :adapter => :postgres, :database => 'tern_test_test'
|
159
|
+
|
160
|
+
tern_migrate "spec/projects/new", "-e test"
|
161
|
+
test_db.tables.should include(:tern_definitions)
|
162
|
+
@dev_db.tables.should_not include(:tern_definitions)
|
163
|
+
|
164
|
+
test_db.disconnect
|
165
|
+
`dropdb tern_test_test`
|
166
|
+
end
|
167
|
+
|
168
|
+
it "creates definitions" do
|
169
|
+
tern_migrate "spec/projects/definitions"
|
170
|
+
@dev_db.get{ultimate_answer{}}.should == 42
|
171
|
+
end
|
172
|
+
|
173
|
+
it "drops definitions" do
|
174
|
+
tern_migrate "spec/projects/definitions"
|
175
|
+
tern_migrate "spec/projects/new"
|
176
|
+
expect { @dev_db.get{ultimate_answer{}} }.to raise_error(Sequel::DatabaseError)
|
177
|
+
end
|
178
|
+
|
179
|
+
it "creates definitions after alterations" do
|
180
|
+
tern_migrate "spec/projects/dependencies_1"
|
181
|
+
@dev_db.tables.should include(:widgets)
|
182
|
+
expect { @dev_db[:widgets_view].all }.to_not raise_error(Sequel::DatabaseError)
|
183
|
+
end
|
184
|
+
|
185
|
+
it "drops existing definitions" do
|
186
|
+
tern_migrate "spec/projects/dependencies_1"
|
187
|
+
tern_migrate "spec/projects/dependencies_2"
|
188
|
+
expect { @dev_db[:widgets_view].all }.to raise_error(Sequel::DatabaseError)
|
189
|
+
end
|
190
|
+
|
191
|
+
context "multiple definition sequences" do
|
192
|
+
it "creates specified definition sequences in order" do
|
193
|
+
tern_migrate "spec/projects/multiple_sequences", "-d expensive default"
|
194
|
+
expect { @dev_db[:a].all }.to_not raise_error(Sequel::DatabaseError)
|
195
|
+
expect { @dev_db[:b].all }.to_not raise_error(Sequel::DatabaseError)
|
196
|
+
end
|
197
|
+
|
198
|
+
it "creates specified definition sequence" do
|
199
|
+
tern_migrate "spec/projects/multiple_sequences", "-d expensive"
|
200
|
+
expect { @dev_db[:a].all }.to_not raise_error(Sequel::DatabaseError)
|
201
|
+
end
|
202
|
+
|
203
|
+
it "ignores unspecified definition sequences" do
|
204
|
+
tern_migrate "spec/projects/multiple_sequences", "-d expensive"
|
205
|
+
expect { @dev_db[:b].all }.to raise_error(Sequel::DatabaseError)
|
206
|
+
end
|
207
|
+
|
208
|
+
it "removes specified definition sequence from database that does not exist in definitions" do
|
209
|
+
tern_migrate "spec/projects/multiple_sequences", "-d expensive"
|
210
|
+
tern_migrate "spec/projects/new", "-d expensive"
|
211
|
+
expect { @dev_db[:a].all }.to raise_error(Sequel::DatabaseError)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|