tern 0.6.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.
- 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
|