prodder 1.7.6 → 1.10.1
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.
- checksums.yaml +4 -4
- data/Dockerfile +23 -0
- data/Gemfile +4 -2
- data/Gemfile.lock +77 -0
- data/LICENSE.txt +5 -7
- data/README.md +174 -82
- data/compose.yml +54 -0
- data/cucumber.yml +1 -0
- data/features/commit.feature +3 -3
- data/features/dump.feature +7 -7
- data/features/step_definitions/git_steps.rb +18 -18
- data/features/step_definitions/prodder_steps.rb +26 -26
- data/features/support/env.rb +22 -10
- data/features/support/prodder__blog_prod.sql +1 -0
- data/lib/prodder/cli.rb +0 -2
- data/lib/prodder/pg.rb +10 -9
- data/lib/prodder/prodder.rake +15 -11
- data/lib/prodder/project.rb +1 -4
- data/lib/prodder/version.rb +1 -1
- data/prodder-1.8.2.gem +0 -0
- data/prodder.gemspec +6 -4
- metadata +26 -11
- data/.gitignore +0 -23
- data/.travis.yml +0 -45
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
Given 'a
|
|
1
|
+
Given 'a {string} git repository' do |project|
|
|
2
2
|
fixture_repo = File.join(@prodder_root, 'features', 'support', "#{project}.git")
|
|
3
3
|
unless File.directory? fixture_repo
|
|
4
4
|
raise "Cannot initialize repo for project #{project}; expected fixture at: #{fixture_repo}"
|
|
5
5
|
end
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
if File.exist? File.join(
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
run_command_and_stop "mkdir -p repos"
|
|
8
|
+
if File.exist? File.join(expand_path('.'), "repos", "#{project}.git")
|
|
9
|
+
run_command_and_stop "chmod -R a+w repos/#{project}.git"
|
|
10
|
+
run_command_and_stop "rm -rf repos/#{project}.git"
|
|
11
11
|
end
|
|
12
|
-
|
|
12
|
+
run_command_and_stop "cp -pR #{fixture_repo} repos/#{project}.git"
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
Given 'I deleted the
|
|
16
|
-
|
|
15
|
+
Given 'I deleted the {string} git repository' do |project|
|
|
16
|
+
run_command_and_stop "rm -rf repos/#{project}.git"
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
Given 'the
|
|
20
|
-
|
|
19
|
+
Given 'the {string} git repository does not allow pushing to it' do |project|
|
|
20
|
+
run_command_and_stop "chmod -R a-w repos/#{project}.git"
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
Given 'a new commit is already in the
|
|
23
|
+
Given 'a new commit is already in the {string} git repository' do |project|
|
|
24
24
|
commit_to_remote project
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
-
Then 'the new commit should be in the workspace copy of the
|
|
28
|
-
|
|
27
|
+
Then 'the new commit should be in the workspace copy of the {string} repository' do |project|
|
|
28
|
+
expect("prodder-workspace/#{project}/README").to have_file_content(/Also read this!/)
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
Then(/^(\d+) commits? by "([^"]+)" should be in the "([^"]+)" repository$/) do |n, author, project|
|
|
@@ -35,14 +35,14 @@ Then(/^(\d+) commits? by "([^"]+)" should be in the "([^"]+)" repository$/) do |
|
|
|
35
35
|
end
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
-
Then 'the file
|
|
39
|
-
|
|
38
|
+
Then 'the file {string} should now be tracked' do |filename|
|
|
39
|
+
in_current_directory do
|
|
40
40
|
git = Prodder::Git.new(File.expand_path("prodder-workspace/blog"), nil)
|
|
41
41
|
expect(git).to be_tracked(filename)
|
|
42
42
|
end
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
-
Then 'the latest commit should have changed
|
|
45
|
+
Then 'the latest commit should have changed {string} to contain {string}' do |filename, content|
|
|
46
46
|
in_workspace('blog') do
|
|
47
47
|
changed = `git show --name-only HEAD | grep #{filename}`.split("\n")
|
|
48
48
|
expect(changed).to_not be_empty
|
|
@@ -52,7 +52,7 @@ Then 'the latest commit should have changed "$file" to contain "$content"' do |f
|
|
|
52
52
|
end
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
-
Then 'the latest commit should not have changed
|
|
55
|
+
Then 'the latest commit should not have changed {string}' do |filename|
|
|
56
56
|
in_workspace('blog') do
|
|
57
57
|
changed = `git show --name-only HEAD | grep #{filename}`.split("\n")
|
|
58
58
|
expect(changed).to be_empty
|
|
@@ -60,7 +60,7 @@ Then 'the latest commit should not have changed "$filename"' do |filename|
|
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
Then 'the new commit should be in the remote repository' do
|
|
63
|
-
|
|
63
|
+
in_current_directory do
|
|
64
64
|
latest = `git --git-dir="./repos/blog.git" log | grep prodder`.split("\n")
|
|
65
65
|
expect(latest).to_not be_empty
|
|
66
66
|
end
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
Given 'the
|
|
1
|
+
Given 'the {string} key is missing from {string}' do |key, filename|
|
|
2
2
|
# Eh, good enough!
|
|
3
3
|
path = File.join @aruba_root, filename
|
|
4
4
|
contents = File.read path
|
|
5
5
|
File.open(path, 'w') { |f| f.write contents.sub(/^\s+name: \w+$/, '') }
|
|
6
6
|
end
|
|
7
7
|
|
|
8
|
-
Given 'the
|
|
8
|
+
Given 'the {string} role can not read from the "blog" database\'s tables' do |role|
|
|
9
9
|
Prodder::PG.new.psql('prodder__blog_prod', 'REVOKE SELECT ON ALL TABLES IN SCHEMA public FROM prodder;')
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
Given 'I add an index to table
|
|
12
|
+
Given 'I add an index to table {string} on column {string} in the {string} project\'s database' do |table, column, project|
|
|
13
13
|
Prodder::PG.new.psql "prodder__#{project}_prod", "CREATE INDEX test_index ON #{table} (#{column});"
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
Given 'I add a custom parameter
|
|
16
|
+
Given 'I add a custom parameter {string} with value {string} in the {string} project\'s database' do |parameter, value, project|
|
|
17
17
|
Prodder::PG.new.psql "prodder__#{project}_prod", "ALTER DATABASE prodder__#{project}_prod SET #{parameter} = '#{value}';"
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
Given 'I add a foreign key from table
|
|
20
|
+
Given 'I add a foreign key from table {string} and column {string} to table {string} and column {string} in the {string} project\'s database' do |table1, column1, table2, column2, project|
|
|
21
21
|
Prodder::PG.new.psql "prodder__#{project}_prod", "ALTER TABLE #{table1} ADD CONSTRAINT fk_authors FOREIGN KEY (#{column1}) REFERENCES #{table2} (#{column2});"
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
Given
|
|
24
|
+
Given /^no-op versions of these bins are available on my PATH: (.+)$/ do |bins|
|
|
25
25
|
paths = bins.split(/,\s*/).map { |bin|
|
|
26
26
|
File.join(@aruba_root, "stub-#{bin}").tap do |dir|
|
|
27
27
|
FileUtils.mkdir_p dir
|
|
@@ -29,49 +29,49 @@ Given 'no-op versions of these bins are available on my PATH: $bins' do |bins|
|
|
|
29
29
|
end
|
|
30
30
|
}.join(File::PATH_SEPARATOR)
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
set_environment_variable 'PATH', "#{paths}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
Given '
|
|
35
|
+
Given '{string} is not available on my PATH' do |bin|
|
|
36
36
|
path = ENV['PATH'].split(File::PATH_SEPARATOR)
|
|
37
37
|
dirs = path.select { |dir| File.exist? File.join(dir, bin) }
|
|
38
|
-
|
|
38
|
+
set_environment_variable 'PATH', path.reject { |dir| dirs.include?(dir) }.join(File::PATH_SEPARATOR)
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
When 'I create a new table
|
|
41
|
+
When 'I create a new table {string} in the {string} database' do |table, project|
|
|
42
42
|
pg = Prodder::PG.new
|
|
43
43
|
pg.psql "prodder__#{project}_prod", "CREATE TABLE #{table} ( id SERIAL PRIMARY KEY );"
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
When 'I add a new author
|
|
46
|
+
When 'I add a new author {string} to the {string} database' do |author, project|
|
|
47
47
|
pg = Prodder::PG.new
|
|
48
48
|
pg.psql "prodder__#{project}_prod", "INSERT INTO authors (name) VALUES ('#{author}');"
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
-
When 'I add a
|
|
51
|
+
When 'I add a {string} schema to the {string} project\'s database' do |name, project|
|
|
52
52
|
pg = Prodder::PG.new
|
|
53
53
|
pg.psql "prodder__#{project}_prod", "CREATE SCHEMA #{name} AUTHORIZATION prodder CREATE TABLE #{name}.providers ( id SERIAL PRIMARY KEY );"
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
-
When 'I grant all permissions on table
|
|
56
|
+
When 'I grant all permissions on table {string} in the {string} database to {string}' do |table, project, role|
|
|
57
57
|
pg = Prodder::PG.new
|
|
58
58
|
pg.psql "prodder__#{project}_prod", "GRANT ALL ON #{table} TO #{role}"
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
Then 'the output should contain the example config contents' do
|
|
62
|
-
|
|
62
|
+
expect(last_command_started).to have_output(an_output_string_including(Prodder::Config.example_contents))
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
Then /^the workspace file "([^"]*)" should match \/([^\/]*)\/$/ do |file, partial_content|
|
|
66
|
-
|
|
66
|
+
expect("prodder-workspace/#{file}").to have_file_content(/#{partial_content}/)
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
Then /^the workspace file "([^"]*)" should not match \/([^\/]*)\/$/ do |file, partial_content|
|
|
70
|
-
|
|
70
|
+
expect("prodder-workspace/#{file}").not_to have_file_content(/#{partial_content}/)
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
Then /^the workspace file "([^"]*)" should not exist$/ do |file|
|
|
74
|
-
|
|
74
|
+
expect("prodder-workspace/#{file}").not_to be_an_existing_file
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
Given(/a prodder config in "([^"]*)" with projects?: (.*)/) do |filename, projects|
|
|
@@ -100,51 +100,51 @@ Given(/a prodder config in "([^"]*)" with projects?: (.*)/) do |filename, projec
|
|
|
100
100
|
write_file filename, contents
|
|
101
101
|
end
|
|
102
102
|
|
|
103
|
-
Given 'the
|
|
103
|
+
Given 'the {string} file {string} contains:' do |project, filename, contents|
|
|
104
104
|
write_file "prodder-workspace/#{project}/#{filename}", contents
|
|
105
105
|
end
|
|
106
106
|
|
|
107
|
-
Given 'the prodder config in
|
|
107
|
+
Given 'the prodder config in {string} says to read the {string} seed tables from {string}' do |filename, project, seeds|
|
|
108
108
|
update_config filename do |config|
|
|
109
109
|
config[project]['db']['tables'] = seeds
|
|
110
110
|
end
|
|
111
111
|
end
|
|
112
112
|
|
|
113
|
-
Given 'the prodder config in
|
|
113
|
+
Given 'the prodder config in {string} excludes the table {string} from the dump of {string}' do |filename, table, project|
|
|
114
114
|
update_config filename do |config|
|
|
115
115
|
config[project]['db']['exclude_tables'] ||= []
|
|
116
116
|
config[project]['db']['exclude_tables'].push table
|
|
117
117
|
end
|
|
118
118
|
end
|
|
119
119
|
|
|
120
|
-
Given 'the prodder config in
|
|
120
|
+
Given 'the prodder config in {string} excludes the schema {string} from the dump of {string}' do |filename, schema, project|
|
|
121
121
|
update_config filename do |config|
|
|
122
122
|
config[project]['db']['exclude_schemas'] ||= []
|
|
123
123
|
config[project]['db']['exclude_schemas'].push schema
|
|
124
124
|
end
|
|
125
125
|
end
|
|
126
126
|
|
|
127
|
-
Given 'the prodder config in
|
|
127
|
+
Given 'the prodder config in {string} does not include a quality check file for the {string} project' do |filename, project|
|
|
128
128
|
update_config filename do |config|
|
|
129
129
|
config[project].delete 'quality_check_file'
|
|
130
130
|
end
|
|
131
131
|
end
|
|
132
132
|
|
|
133
|
-
Given 'the prodder config in
|
|
133
|
+
Given 'the prodder config in {string} does not include a permissions file for the {string} project' do |filename, project|
|
|
134
134
|
update_config filename do |config|
|
|
135
135
|
config[project]['permissions'].delete 'file'
|
|
136
136
|
end
|
|
137
137
|
end
|
|
138
138
|
|
|
139
|
-
Given 'the prodder config in
|
|
139
|
+
Given 'the prodder config in {string} does not include permissions for the {string} project' do |filename, project|
|
|
140
140
|
update_config filename do |config|
|
|
141
141
|
config[project].delete 'permissions'
|
|
142
142
|
end
|
|
143
143
|
end
|
|
144
144
|
|
|
145
|
-
Given 'the
|
|
145
|
+
Given 'the {string} file {string} does not exist' do |project, filename|
|
|
146
146
|
begin
|
|
147
|
-
|
|
147
|
+
remove "prodder-workspace/#{project}/#{filename}"
|
|
148
148
|
rescue Errno::ENOENT
|
|
149
149
|
end
|
|
150
150
|
end
|
data/features/support/env.rb
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
require 'cucumber'
|
|
2
2
|
require 'aruba/cucumber'
|
|
3
3
|
|
|
4
|
-
$LOAD_PATH.unshift File.expand_path('../../lib',
|
|
4
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __dir__)
|
|
5
5
|
require 'prodder'
|
|
6
6
|
|
|
7
|
+
# Configure Aruba to find the prodder executable
|
|
8
|
+
Aruba.configure do |config|
|
|
9
|
+
config.command_search_paths << File.expand_path('../../bin', __dir__)
|
|
10
|
+
config.exit_timeout = 10
|
|
11
|
+
config.io_wait_timeout = 10
|
|
12
|
+
end
|
|
13
|
+
|
|
7
14
|
module ProdderHelpers
|
|
8
15
|
def strip_leading(string)
|
|
9
16
|
leading = string.scan(/^\s*/).min_by &:length
|
|
@@ -11,21 +18,21 @@ module ProdderHelpers
|
|
|
11
18
|
end
|
|
12
19
|
|
|
13
20
|
def in_workspace(name, &block)
|
|
14
|
-
|
|
21
|
+
in_current_directory { Dir.chdir("prodder-workspace/#{name}", &block) }
|
|
15
22
|
end
|
|
16
23
|
|
|
17
24
|
def commit_to_remote(project)
|
|
18
25
|
@dirs = ['tmp', 'aruba']
|
|
19
|
-
|
|
26
|
+
run_command_and_stop "git clone repos/#{project}.git tmp-extra-commit-#{project}"
|
|
20
27
|
cd "tmp-extra-commit-#{project}"
|
|
21
28
|
|
|
22
29
|
append_to_file "README", 'Also read this!'
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
30
|
+
run_command_and_stop 'git add README'
|
|
31
|
+
run_command_and_stop 'git -c user.email="test@example.com" -c user.name="Test User" commit -m "Second commit"'
|
|
32
|
+
run_command_and_stop "git push origin master"
|
|
26
33
|
|
|
27
34
|
cd '..'
|
|
28
|
-
|
|
35
|
+
run_command_and_stop "rm -rf tmp-extra-commit-#{project}"
|
|
29
36
|
end
|
|
30
37
|
|
|
31
38
|
def update_config(filename, &block)
|
|
@@ -90,7 +97,7 @@ module ProdderHelpers
|
|
|
90
97
|
end
|
|
91
98
|
|
|
92
99
|
def self.fixture_dbs
|
|
93
|
-
@fixture_dbs ||= Dir[File.join(
|
|
100
|
+
@fixture_dbs ||= Dir[File.join(__dir__, '*.sql')].map do |sql|
|
|
94
101
|
db = File.basename(sql).sub('.sql', '')
|
|
95
102
|
[db, File.read(sql)]
|
|
96
103
|
end
|
|
@@ -100,10 +107,15 @@ end
|
|
|
100
107
|
World ProdderHelpers
|
|
101
108
|
|
|
102
109
|
Before do
|
|
103
|
-
@prodder_root = File.expand_path('../..',
|
|
110
|
+
@prodder_root = File.expand_path('../..', __dir__)
|
|
104
111
|
@aruba_root = File.join(@prodder_root, 'tmp', 'aruba')
|
|
105
|
-
@aruba_timeout_seconds = 10
|
|
106
112
|
Dir.chdir @prodder_root
|
|
113
|
+
|
|
114
|
+
# Configure git for tests that create commits
|
|
115
|
+
set_environment_variable 'GIT_AUTHOR_NAME', 'Test User'
|
|
116
|
+
set_environment_variable 'GIT_AUTHOR_EMAIL', 'test@example.com'
|
|
117
|
+
set_environment_variable 'GIT_COMMITTER_NAME', 'Test User'
|
|
118
|
+
set_environment_variable 'GIT_COMMITTER_EMAIL', 'test@example.com'
|
|
107
119
|
end
|
|
108
120
|
|
|
109
121
|
After('@restore-perms') do
|
data/lib/prodder/cli.rb
CHANGED
data/lib/prodder/pg.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require 'open3'
|
|
2
2
|
require 'pg'
|
|
3
|
+
require 'set'
|
|
3
4
|
|
|
4
5
|
module Prodder
|
|
5
6
|
class PG
|
|
@@ -69,11 +70,12 @@ module Prodder
|
|
|
69
70
|
end
|
|
70
71
|
end
|
|
71
72
|
|
|
72
|
-
def dump_structure(db_name, filename, options
|
|
73
|
+
def dump_structure(db_name, filename, **options)
|
|
73
74
|
arguments = [
|
|
74
75
|
'--schema-only',
|
|
75
76
|
'--no-privileges',
|
|
76
77
|
'--no-owner',
|
|
78
|
+
'--restrict-key', 'prodder',
|
|
77
79
|
'--host', credentials['host'],
|
|
78
80
|
'--username', credentials['user']
|
|
79
81
|
]
|
|
@@ -95,6 +97,7 @@ module Prodder
|
|
|
95
97
|
'--no-privileges',
|
|
96
98
|
'--no-owner',
|
|
97
99
|
'--disable-triggers',
|
|
100
|
+
'--restrict-key', 'prodder',
|
|
98
101
|
'--host', credentials['host'],
|
|
99
102
|
'--username', credentials['user'],
|
|
100
103
|
*tables.map { |table| ['--table', table] }.flatten,
|
|
@@ -102,12 +105,12 @@ module Prodder
|
|
|
102
105
|
]
|
|
103
106
|
end
|
|
104
107
|
|
|
105
|
-
def dump_permissions(db_name, filename, options
|
|
108
|
+
def dump_permissions(db_name, filename, **options)
|
|
106
109
|
perm_out_sql = ""
|
|
107
110
|
user_list = []
|
|
108
111
|
|
|
109
|
-
perm_out_sql << dump_db_access_control(db_name, user_list, options)
|
|
110
|
-
perm_out_sql.prepend pg_dumpall
|
|
112
|
+
perm_out_sql << dump_db_access_control(db_name, user_list, **options)
|
|
113
|
+
perm_out_sql.prepend pg_dumpall(db_name, user_list, **options)
|
|
111
114
|
|
|
112
115
|
perm_out_sql.prepend(alter_role_function)
|
|
113
116
|
perm_out_sql.prepend(create_role_function)
|
|
@@ -125,9 +128,8 @@ module Prodder
|
|
|
125
128
|
ACL_REVOKE = /^REVOKE /
|
|
126
129
|
DEFAULT_PRIVILEGES = /^ALTER DEFAULT PRIVILEGES /
|
|
127
130
|
SET_OBJECT_OWNERSHIP = /.* OWNER TO /
|
|
128
|
-
SEARCH_PATH = /SET search_path = .*/
|
|
129
131
|
|
|
130
|
-
def dump_db_access_control(db_name, user_list, options)
|
|
132
|
+
def dump_db_access_control(db_name, user_list, **options)
|
|
131
133
|
perm_out_sql = ""
|
|
132
134
|
arguments = [
|
|
133
135
|
'--schema-only',
|
|
@@ -153,8 +155,7 @@ module Prodder
|
|
|
153
155
|
if line.match(ACL_GRANT) ||
|
|
154
156
|
line.match(ACL_REVOKE) ||
|
|
155
157
|
line.match(DEFAULT_PRIVILEGES) ||
|
|
156
|
-
line.match(SET_OBJECT_OWNERSHIP)
|
|
157
|
-
line.match(SEARCH_PATH)
|
|
158
|
+
line.match(SET_OBJECT_OWNERSHIP)
|
|
158
159
|
|
|
159
160
|
unless irrelevant_login_roles.include?(line.match(/ (\S*);$/)[1])
|
|
160
161
|
perm_out_sql << line
|
|
@@ -219,7 +220,7 @@ module Prodder
|
|
|
219
220
|
end
|
|
220
221
|
end
|
|
221
222
|
|
|
222
|
-
def pg_dumpall(db_name, user_list, options)
|
|
223
|
+
def pg_dumpall(db_name, user_list, **options)
|
|
223
224
|
white_list = options[:included_users] || []
|
|
224
225
|
irrelevant_login_roles = irrelevant_login_roles(db_name, white_list).map { |user| user['oid'] }
|
|
225
226
|
|
data/lib/prodder/prodder.rake
CHANGED
|
@@ -169,7 +169,7 @@ namespace :db do
|
|
|
169
169
|
end
|
|
170
170
|
as("superuser", in: environments) do
|
|
171
171
|
ActiveRecord::Tasks::DatabaseTasks.create_current
|
|
172
|
-
|
|
172
|
+
Rails.configuration.database_configuration.each do |env, config|
|
|
173
173
|
if environments.include?(env) && config["migration_user"] && config['database']
|
|
174
174
|
set_psql_env config
|
|
175
175
|
`psql --no-psqlrc --command "ALTER DATABASE #{config['database']} OWNER TO #{config['migration_user']}" #{Shellwords.escape(config['database'])}`
|
|
@@ -182,7 +182,7 @@ namespace :db do
|
|
|
182
182
|
task :all => dependencies do
|
|
183
183
|
as("superuser") do
|
|
184
184
|
ActiveRecord::Tasks::DatabaseTasks.create_all
|
|
185
|
-
|
|
185
|
+
Rails.configuration.database_configuration.each do |env, config|
|
|
186
186
|
if config["migration_user"] && config['database']
|
|
187
187
|
set_psql_env config
|
|
188
188
|
`psql --no-psqlrc --command "ALTER DATABASE #{config['database']} OWNER TO #{config['migration_user']}" #{Shellwords.escape(config['database'])}`
|
|
@@ -204,7 +204,7 @@ namespace :db do
|
|
|
204
204
|
desc "Load db/structure.sql into the current environment's database"
|
|
205
205
|
task :load => dependencies do
|
|
206
206
|
as("superuser", in: ENV['RAILS_ENV'] || Rails.env) do
|
|
207
|
-
config = ActiveRecord::Base.configurations
|
|
207
|
+
config = ActiveRecord::Base.configurations.find_db_config(ENV['RAILS_ENV'] || Rails.env).configuration_hash.with_indifferent_access
|
|
208
208
|
set_psql_env config
|
|
209
209
|
puts "Loading db/structure.sql into database '#{config['database']}'"
|
|
210
210
|
`psql --no-psqlrc -f db/structure.sql #{Shellwords.escape(config['database'])}`
|
|
@@ -217,7 +217,7 @@ namespace :db do
|
|
|
217
217
|
task :seed => dependencies do
|
|
218
218
|
if File.exist?('db/seeds.sql')
|
|
219
219
|
as("superuser", in: ENV['RAILS_ENV'] || Rails.env) do
|
|
220
|
-
config = ActiveRecord::Base.configurations
|
|
220
|
+
config = ActiveRecord::Base.configurations.find_db_config(ENV['RAILS_ENV'] || Rails.env).configuration_hash.with_indifferent_access
|
|
221
221
|
set_psql_env config
|
|
222
222
|
puts "Loading db/seeds.sql into database '#{config['database']}'"
|
|
223
223
|
`psql --no-psqlrc -f db/seeds.sql #{Shellwords.escape(config['database'])}`
|
|
@@ -232,7 +232,7 @@ namespace :db do
|
|
|
232
232
|
task :quality_check => dependencies do
|
|
233
233
|
if File.exist?('db/quality_checks.sql')
|
|
234
234
|
as("superuser", in: ENV['RAILS_ENV'] || Rails.env) do
|
|
235
|
-
config = ActiveRecord::Base.configurations
|
|
235
|
+
config = ActiveRecord::Base.configurations.find_db_config(ENV['RAILS_ENV'] || Rails.env).configuration_hash.with_indifferent_access
|
|
236
236
|
set_psql_env config
|
|
237
237
|
puts "Loading db/quality_checks.sql into database '#{config['database']}'"
|
|
238
238
|
`psql --no-psqlrc -f db/quality_checks.sql #{Shellwords.escape(config['database'])}`
|
|
@@ -247,7 +247,7 @@ namespace :db do
|
|
|
247
247
|
task :permission => dependencies do
|
|
248
248
|
if File.exist?('db/permissions.sql')
|
|
249
249
|
as("superuser", in: ENV['RAILS_ENV'] || Rails.env) do
|
|
250
|
-
config = ActiveRecord::Base.configurations
|
|
250
|
+
config = ActiveRecord::Base.configurations.find_db_config(ENV['RAILS_ENV'] || Rails.env).configuration_hash.with_indifferent_access
|
|
251
251
|
set_psql_env config
|
|
252
252
|
puts "Loading db/permissions.sql into database '#{config['database']}'"
|
|
253
253
|
result = ActiveRecord::Base.connection.execute(<<-SQL).first
|
|
@@ -268,7 +268,7 @@ namespace :db do
|
|
|
268
268
|
task :settings => dependencies do
|
|
269
269
|
if File.exist?('db/settings.sql')
|
|
270
270
|
as("superuser", in: ENV['RAILS_ENV'] || Rails.env) do
|
|
271
|
-
config = ActiveRecord::Base.configurations
|
|
271
|
+
config = ActiveRecord::Base.configurations.find_db_config(ENV['RAILS_ENV'] || Rails.env).configuration_hash.with_indifferent_access
|
|
272
272
|
set_psql_env config
|
|
273
273
|
puts "Loading db/settings.sql into database '#{config['database']}'"
|
|
274
274
|
result = ActiveRecord::Base.connection.execute(<<-SQL).first
|
|
@@ -362,19 +362,22 @@ namespace :db do
|
|
|
362
362
|
|
|
363
363
|
def as(user, opts = {}, &block)
|
|
364
364
|
if File.exist?('db/permissions.sql')
|
|
365
|
-
|
|
365
|
+
configs = ActiveRecord::Base.configurations.configs_for
|
|
366
|
+
config = configs.map { |c| [c.env_name, c.configuration_hash] }.to_h.with_indifferent_access
|
|
367
|
+
config_was = config.deep_dup
|
|
368
|
+
|
|
366
369
|
in_env = Array(opts[:in]) || config.keys
|
|
367
370
|
if config.all? { |env, config_hash| in_env.include?(env) ? config_hash[user] : true }
|
|
368
371
|
disconnect
|
|
369
372
|
config.each { |env, config_hash| config_hash["username"] = config_hash[user] if in_env.include?(env) }
|
|
370
|
-
ActiveRecord::Base.configurations = config
|
|
373
|
+
ActiveRecord::Base.configurations = ActiveRecord::DatabaseConfigurations.new(config)
|
|
371
374
|
end
|
|
372
375
|
else
|
|
373
376
|
puts "No permissions file (db/permissions.sql) found, running everything in context of user"
|
|
374
377
|
end
|
|
375
378
|
yield
|
|
376
379
|
ensure
|
|
377
|
-
ActiveRecord::Base.configurations = config_was if config_was
|
|
380
|
+
ActiveRecord::Base.configurations = ActiveRecord::DatabaseConfigurations.new(config_was) if config_was
|
|
378
381
|
in_env.each { |env| ActiveRecord::Base.establish_connection(env.intern) } if in_env
|
|
379
382
|
end
|
|
380
383
|
|
|
@@ -393,5 +396,6 @@ end
|
|
|
393
396
|
|
|
394
397
|
# Yes, I really want migrations to run against the test DB.
|
|
395
398
|
Rake::Task['db:migrate'].actions.unshift(proc {
|
|
396
|
-
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations
|
|
399
|
+
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations.find_db_config(ENV['RAILS_ENV'] || Rails.env))
|
|
400
|
+
|
|
397
401
|
})
|
data/lib/prodder/project.rb
CHANGED
|
@@ -45,11 +45,8 @@ module Prodder
|
|
|
45
45
|
contents = File.readlines(structure_file_name)
|
|
46
46
|
rgx = /^\-\- .* Type: INDEX; |^\-\- .* Type: TRIGGER; |^\-\- .* Type: FK CONSTRAINT; /
|
|
47
47
|
structure, *quality = contents.slice_before(rgx).to_a
|
|
48
|
-
# the first search path setting for constraints gets left over
|
|
49
|
-
# in the structure, so we need to *attempt* to grab that
|
|
50
|
-
quality_checks = (structure.grep(/SET search_path/).last || '') + quality.join
|
|
51
48
|
|
|
52
|
-
File.open(quality_check_file_name, 'w') { |f| f.write(
|
|
49
|
+
File.open(quality_check_file_name, 'w') { |f| f.write(quality.join) }
|
|
53
50
|
File.open(structure_file_name, 'w') { |f| f.write(structure.join) }
|
|
54
51
|
end
|
|
55
52
|
|
data/lib/prodder/version.rb
CHANGED
data/prodder-1.8.2.gem
ADDED
|
Binary file
|
data/prodder.gemspec
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
|
2
|
-
|
|
2
|
+
$LOAD_PATH.unshift(File.expand_path("lib", __dir__))
|
|
3
3
|
require "prodder/version"
|
|
4
4
|
|
|
5
5
|
Gem::Specification.new do |s|
|
|
@@ -12,11 +12,13 @@ Gem::Specification.new do |s|
|
|
|
12
12
|
s.summary = "Maintain your Rails apps' structure, seed and quality_checks files using production dumps"
|
|
13
13
|
s.description = "Migrations suck long-term. Now you can kill them routinely."
|
|
14
14
|
|
|
15
|
-
s.files =
|
|
16
|
-
s.test_files =
|
|
17
|
-
s.executables =
|
|
15
|
+
s.files = Dir.glob("{lib,bin,features}/**/*") + Dir.glob("*").reject { |f| File.directory?(f) }
|
|
16
|
+
s.test_files = Dir.glob("{test,spec,features}/**/*")
|
|
17
|
+
s.executables = Dir.glob("bin/*").map { |f| File.basename(f) }
|
|
18
18
|
s.require_paths = ["lib"]
|
|
19
19
|
|
|
20
|
+
s.required_ruby_version = ">= 2.7.0"
|
|
21
|
+
|
|
20
22
|
# These dependencies do not match the Gemfile's for a reason.
|
|
21
23
|
# These are the only dependencies necessary to satisfy inclusion of this
|
|
22
24
|
# gem in a Rails application; any dependencies necessary to run prodder
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: prodder
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.10.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kyle Hargraves
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-02-09 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: deject
|
|
@@ -32,13 +32,15 @@ executables:
|
|
|
32
32
|
extensions: []
|
|
33
33
|
extra_rdoc_files: []
|
|
34
34
|
files:
|
|
35
|
-
-
|
|
36
|
-
- ".travis.yml"
|
|
35
|
+
- Dockerfile
|
|
37
36
|
- Gemfile
|
|
37
|
+
- Gemfile.lock
|
|
38
38
|
- LICENSE.txt
|
|
39
39
|
- README.md
|
|
40
40
|
- Rakefile
|
|
41
41
|
- bin/prodder
|
|
42
|
+
- compose.yml
|
|
43
|
+
- cucumber.yml
|
|
42
44
|
- features/commit.feature
|
|
43
45
|
- features/dump.feature
|
|
44
46
|
- features/init.feature
|
|
@@ -59,6 +61,7 @@ files:
|
|
|
59
61
|
- lib/prodder/project.rb
|
|
60
62
|
- lib/prodder/railtie.rb
|
|
61
63
|
- lib/prodder/version.rb
|
|
64
|
+
- prodder-1.8.2.gem
|
|
62
65
|
- prodder.gemspec
|
|
63
66
|
- spec/config_spec.rb
|
|
64
67
|
- spec/spec_helper.rb
|
|
@@ -66,7 +69,7 @@ homepage: https://github.com/enova/prodder
|
|
|
66
69
|
licenses:
|
|
67
70
|
- MIT
|
|
68
71
|
metadata: {}
|
|
69
|
-
post_install_message:
|
|
72
|
+
post_install_message:
|
|
70
73
|
rdoc_options: []
|
|
71
74
|
require_paths:
|
|
72
75
|
- lib
|
|
@@ -74,17 +77,29 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
74
77
|
requirements:
|
|
75
78
|
- - ">="
|
|
76
79
|
- !ruby/object:Gem::Version
|
|
77
|
-
version:
|
|
80
|
+
version: 2.7.0
|
|
78
81
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
79
82
|
requirements:
|
|
80
83
|
- - ">="
|
|
81
84
|
- !ruby/object:Gem::Version
|
|
82
85
|
version: '0'
|
|
83
86
|
requirements: []
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
signing_key:
|
|
87
|
+
rubygems_version: 3.3.26
|
|
88
|
+
signing_key:
|
|
87
89
|
specification_version: 4
|
|
88
90
|
summary: Maintain your Rails apps' structure, seed and quality_checks files using
|
|
89
91
|
production dumps
|
|
90
|
-
test_files:
|
|
92
|
+
test_files:
|
|
93
|
+
- spec/config_spec.rb
|
|
94
|
+
- spec/spec_helper.rb
|
|
95
|
+
- features/commit.feature
|
|
96
|
+
- features/dump.feature
|
|
97
|
+
- features/init.feature
|
|
98
|
+
- features/lint.feature
|
|
99
|
+
- features/prodder.feature
|
|
100
|
+
- features/push.feature
|
|
101
|
+
- features/step_definitions/git_steps.rb
|
|
102
|
+
- features/step_definitions/prodder_steps.rb
|
|
103
|
+
- features/support/blog.git.tgz
|
|
104
|
+
- features/support/env.rb
|
|
105
|
+
- features/support/prodder__blog_prod.sql
|
data/.gitignore
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
Gemfile.lock
|
|
2
|
-
*.gem
|
|
3
|
-
*.rbc
|
|
4
|
-
.bundle
|
|
5
|
-
.config
|
|
6
|
-
coverage
|
|
7
|
-
InstalledFiles
|
|
8
|
-
lib/bundler/man
|
|
9
|
-
pkg
|
|
10
|
-
rdoc
|
|
11
|
-
spec/reports
|
|
12
|
-
test/tmp
|
|
13
|
-
test/version_tmp
|
|
14
|
-
tmp
|
|
15
|
-
|
|
16
|
-
# YARD artifacts
|
|
17
|
-
.yardoc
|
|
18
|
-
_yardoc
|
|
19
|
-
doc/
|
|
20
|
-
|
|
21
|
-
nc.yml
|
|
22
|
-
prodder-workspace/
|
|
23
|
-
features/support/blog.git
|