culturecode_stagehand 0.1.4 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/stagehand/cache.rb +12 -0
- data/lib/stagehand/configuration.rb +6 -0
- data/lib/stagehand/{helpers.rb → database.rb} +36 -19
- data/lib/stagehand/engine.rb +3 -1
- data/lib/stagehand/key.rb +23 -0
- data/lib/stagehand/production.rb +1 -2
- data/lib/stagehand/schema/statements.rb +5 -3
- data/lib/stagehand/schema.rb +29 -18
- data/lib/stagehand/staging/auditor.rb +64 -0
- data/lib/stagehand/staging/checklist.rb +71 -49
- data/lib/stagehand/staging/synchronizer.rb +12 -0
- data/lib/stagehand/staging.rb +1 -0
- data/lib/stagehand/version.rb +1 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 80028dbb24f83c131a67022d24ab3c84dc64edb7
|
4
|
+
data.tar.gz: c307e846e18fafc50f6987e9208b2dd6601d753c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8e1f6ceba25e85f6dd598b2b6ce52ca9c36e09af45ed327a7ef56a5799c8a57b2e9d76f2d8aa7d52c32783de0008c78adfc8900847127a15bea19cb6c6d76c32
|
7
|
+
data.tar.gz: d1c21179ad1014dd99208ca1936ab57306aaa76a6ecb070d3fb4306dd606649afc632f5005972388e767ebfddd5586820a917000f79690507361145dbf66c562
|
@@ -19,6 +19,12 @@ module Stagehand
|
|
19
19
|
def ghost_mode?
|
20
20
|
!!Rails.configuration.x.stagehand.ghost_mode
|
21
21
|
end
|
22
|
+
|
23
|
+
# Returns true if the production and staging connections are the same.
|
24
|
+
# Use case: Front-end devs may not have a second database set up as they are only concerned with the front end
|
25
|
+
def single_connection?
|
26
|
+
staging_connection_name == production_connection_name
|
27
|
+
end
|
22
28
|
end
|
23
29
|
|
24
30
|
# EXCEPTIONS
|
@@ -1,30 +1,24 @@
|
|
1
1
|
module Stagehand
|
2
|
-
module
|
2
|
+
module Database
|
3
3
|
extend self
|
4
4
|
|
5
|
-
|
6
|
-
case staging_record
|
7
|
-
when Staging::CommitEntry
|
8
|
-
id = staging_record.record_id || staging_record.id
|
9
|
-
table_name = staging_record.table_name || staging_record.class.table_name
|
10
|
-
when ActiveRecord::Base
|
11
|
-
id = staging_record.id
|
12
|
-
table_name = staging_record.class.table_name
|
13
|
-
else
|
14
|
-
id = staging_record
|
15
|
-
table_name = options[:table_name]
|
16
|
-
end
|
5
|
+
@@connection_name_stack = [Rails.env.to_sym]
|
17
6
|
|
18
|
-
|
7
|
+
def connected_to_production?
|
8
|
+
current_connection_name == Configuration.production_connection_name
|
9
|
+
end
|
19
10
|
|
20
|
-
|
11
|
+
def connected_to_staging?
|
12
|
+
current_connection_name == Configuration.staging_connection_name
|
21
13
|
end
|
22
|
-
end
|
23
14
|
|
24
|
-
|
25
|
-
|
15
|
+
def staging_connection
|
16
|
+
StagingProbe.connection
|
17
|
+
end
|
26
18
|
|
27
|
-
|
19
|
+
def production_connection
|
20
|
+
ProductionProbe.connection
|
21
|
+
end
|
28
22
|
|
29
23
|
def with_connection(connection_name)
|
30
24
|
different = !Configuration.ghost_mode? && current_connection_name != connection_name.to_sym
|
@@ -53,5 +47,28 @@ module Stagehand
|
|
53
47
|
def current_connection_name
|
54
48
|
@@connection_name_stack.last
|
55
49
|
end
|
50
|
+
|
51
|
+
|
52
|
+
# CLASSES
|
53
|
+
|
54
|
+
class StagingProbe < ActiveRecord::Base
|
55
|
+
self.abstract_class = true
|
56
|
+
|
57
|
+
def self.init_connection
|
58
|
+
establish_connection(Configuration.staging_connection_name)
|
59
|
+
end
|
60
|
+
|
61
|
+
init_connection
|
62
|
+
end
|
63
|
+
|
64
|
+
class ProductionProbe < ActiveRecord::Base
|
65
|
+
self.abstract_class = true
|
66
|
+
|
67
|
+
def self.init_connection
|
68
|
+
establish_connection(Configuration.production_connection_name)
|
69
|
+
end
|
70
|
+
|
71
|
+
init_connection
|
72
|
+
end
|
56
73
|
end
|
57
74
|
end
|
data/lib/stagehand/engine.rb
CHANGED
@@ -9,11 +9,13 @@ module Stagehand
|
|
9
9
|
# These require the rails application to be intialized because configuration variables are used
|
10
10
|
initializer "stagehand.load_modules" do
|
11
11
|
require "stagehand/configuration"
|
12
|
+
require "stagehand/cache"
|
13
|
+
require "stagehand/key"
|
14
|
+
require "stagehand/database"
|
12
15
|
require "stagehand/controller_extensions"
|
13
16
|
require "stagehand/staging"
|
14
17
|
require "stagehand/schema"
|
15
18
|
require "stagehand/production"
|
16
|
-
require "stagehand/helpers"
|
17
19
|
end
|
18
20
|
end
|
19
21
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Stagehand
|
2
|
+
module Key
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def generate(staging_record, options = {})
|
6
|
+
case staging_record
|
7
|
+
when Staging::CommitEntry
|
8
|
+
id = staging_record.record_id || staging_record.id
|
9
|
+
table_name = staging_record.table_name || staging_record.class.table_name
|
10
|
+
when ActiveRecord::Base
|
11
|
+
id = staging_record.id
|
12
|
+
table_name = staging_record.class.table_name
|
13
|
+
else
|
14
|
+
id = staging_record
|
15
|
+
table_name = options[:table_name]
|
16
|
+
end
|
17
|
+
|
18
|
+
raise 'Invalid input' unless table_name && id
|
19
|
+
|
20
|
+
return [table_name, id]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/stagehand/production.rb
CHANGED
@@ -56,7 +56,6 @@ module Stagehand
|
|
56
56
|
|
57
57
|
def prepare_to_modify(table_name)
|
58
58
|
raise "Can't prepare to modify production records without knowning the table_name" unless table_name.present?
|
59
|
-
Record.establish_connection(Configuration.production_connection_name) and @connection_established = true unless @connection_established
|
60
59
|
Record.table_name = table_name
|
61
60
|
end
|
62
61
|
|
@@ -71,7 +70,7 @@ module Stagehand
|
|
71
70
|
|
72
71
|
# CLASSES
|
73
72
|
|
74
|
-
class Record <
|
73
|
+
class Record < Stagehand::Database::ProductionProbe
|
75
74
|
self.record_timestamps = false
|
76
75
|
end
|
77
76
|
end
|
@@ -5,9 +5,11 @@ module Stagehand
|
|
5
5
|
def create_table(table_name, options = {})
|
6
6
|
super
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
return if options.symbolize_keys[:stagehand] == false
|
9
|
+
return if UNTRACKED_TABLES.include?(table_name)
|
10
|
+
return if Database.connected_to_production?
|
11
|
+
|
12
|
+
Schema.add_stagehand! :only => table_name
|
11
13
|
end
|
12
14
|
end
|
13
15
|
end
|
data/lib/stagehand/schema.rb
CHANGED
@@ -2,9 +2,11 @@ require "stagehand/schema/statements"
|
|
2
2
|
|
3
3
|
module Stagehand
|
4
4
|
module Schema
|
5
|
+
extend self
|
6
|
+
|
5
7
|
UNTRACKED_TABLES = ['schema_migrations', Stagehand::Staging::CommitEntry.table_name]
|
6
8
|
|
7
|
-
def
|
9
|
+
def init_stagehand!(options = {})
|
8
10
|
ActiveRecord::Schema.define do
|
9
11
|
create_table :stagehand_commit_entries do |t|
|
10
12
|
t.integer :record_id
|
@@ -28,44 +30,49 @@ module Stagehand
|
|
28
30
|
add_stagehand!(options)
|
29
31
|
end
|
30
32
|
|
31
|
-
def
|
33
|
+
def add_stagehand!(options = {})
|
32
34
|
ActiveRecord::Schema.define do
|
33
|
-
|
34
35
|
table_names = ActiveRecord::Base.connection.tables
|
35
36
|
table_names -= UNTRACKED_TABLES
|
36
37
|
table_names -= Array(options[:except]).collect(&:to_s)
|
37
38
|
table_names &= Array(options[:only]).collect(&:to_s) if options[:only].present?
|
38
39
|
|
39
40
|
table_names.each do |table_name|
|
40
|
-
Stagehand::Schema.
|
41
|
-
Stagehand::Schema.
|
42
|
-
Stagehand::Schema.
|
43
|
-
|
44
|
-
Stagehand::Schema.create_trigger(table_name, 'insert', 'NEW')
|
45
|
-
Stagehand::Schema.create_trigger(table_name, 'update', 'NEW')
|
46
|
-
Stagehand::Schema.create_trigger(table_name, 'delete', 'OLD')
|
41
|
+
Stagehand::Schema.send :create_trigger, table_name, 'insert', 'NEW'
|
42
|
+
Stagehand::Schema.send :create_trigger, table_name, 'update', 'NEW'
|
43
|
+
Stagehand::Schema.send :create_trigger, table_name, 'delete', 'OLD'
|
47
44
|
end
|
48
45
|
end
|
49
46
|
end
|
50
47
|
|
51
|
-
def
|
48
|
+
def remove_stagehand!(options = {})
|
52
49
|
ActiveRecord::Schema.define do
|
53
50
|
table_names = ActiveRecord::Base.connection.tables
|
54
51
|
table_names &= Array(options[:only]).collect(&:to_s) if options[:only].present?
|
55
52
|
|
56
53
|
table_names.each do |table_name|
|
57
|
-
Stagehand::Schema.drop_trigger
|
58
|
-
Stagehand::Schema.drop_trigger
|
59
|
-
Stagehand::Schema.drop_trigger
|
54
|
+
Stagehand::Schema.send :drop_trigger, table_name, 'insert'
|
55
|
+
Stagehand::Schema.send :drop_trigger, table_name, 'update'
|
56
|
+
Stagehand::Schema.send :drop_trigger, table_name, 'delete'
|
60
57
|
end
|
61
58
|
|
62
59
|
drop_table :stagehand_commit_entries unless options[:only].present?
|
63
60
|
end
|
64
61
|
end
|
65
62
|
|
63
|
+
def has_stagehand?(table_name = nil)
|
64
|
+
if table_name
|
65
|
+
trigger_exists?(table_name, 'insert')
|
66
|
+
else
|
67
|
+
ActiveRecord::Base.Connection.table_exists?(Stagehand::Staging::CommitEntry.table_name)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
66
71
|
private
|
67
72
|
|
68
|
-
def
|
73
|
+
def create_trigger(table_name, trigger_action, record)
|
74
|
+
return if trigger_exists?(table_name, trigger_action)
|
75
|
+
|
69
76
|
ActiveRecord::Base.connection.execute("
|
70
77
|
CREATE TRIGGER #{trigger_name(table_name, trigger_action)} AFTER #{trigger_action.upcase} ON #{table_name}
|
71
78
|
FOR EACH ROW
|
@@ -76,12 +83,16 @@ module Stagehand
|
|
76
83
|
")
|
77
84
|
end
|
78
85
|
|
79
|
-
def
|
86
|
+
def drop_trigger(table_name, trigger_action)
|
80
87
|
ActiveRecord::Base.connection.execute("DROP TRIGGER IF EXISTS #{trigger_name(table_name, trigger_action)};")
|
81
88
|
end
|
82
89
|
|
83
|
-
def
|
84
|
-
"
|
90
|
+
def trigger_exists?(table_name, trigger_action)
|
91
|
+
ActiveRecord::Base.connection.select_one("SHOW TRIGGERS where `trigger` = '#{trigger_name(table_name, trigger_action)}'").present?
|
92
|
+
end
|
93
|
+
|
94
|
+
def trigger_name(table_name, trigger_action)
|
95
|
+
"stagehand_#{trigger_action}_trigger_#{table_name}".downcase
|
85
96
|
end
|
86
97
|
end
|
87
98
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Stagehand
|
2
|
+
module Staging
|
3
|
+
module Auditor
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def incomplete_commits
|
7
|
+
incomplete = []
|
8
|
+
|
9
|
+
incomplete_start_operations.each do |start_operation|
|
10
|
+
entries = records_until_match(start_operation, :asc, :operation => CommitEntry::START_OPERATION).to_a
|
11
|
+
incomplete << [start_operation.id, entries]
|
12
|
+
end
|
13
|
+
|
14
|
+
incomplete_end_operations.each do |end_operation|
|
15
|
+
entries = records_through_match(end_operation, :desc, :operation => CommitEntry::START_OPERATION).to_a
|
16
|
+
incomplete << [entries.last.id, entries]
|
17
|
+
end
|
18
|
+
|
19
|
+
return incomplete.to_h
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# Incomplete End Operation that are not the last entry in their session
|
25
|
+
def incomplete_end_operations
|
26
|
+
last_entry_per_session = CommitEntry.group(:session).select('MAX(id) AS id')
|
27
|
+
return CommitEntry.uncontained.end_operations.where.not(:id => last_entry_per_session)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Incomplete Start on the same session as a subsequent start operation
|
31
|
+
def incomplete_start_operations
|
32
|
+
last_start_entry_per_session = CommitEntry.start_operations.group(:session).select('MAX(id) AS id')
|
33
|
+
return CommitEntry.uncontained.start_operations.where.not(:id => last_start_entry_per_session)
|
34
|
+
end
|
35
|
+
|
36
|
+
def records_until_match(start_entry, direction, match_attributes)
|
37
|
+
records_through_match(start_entry, direction, match_attributes)[0..-2]
|
38
|
+
end
|
39
|
+
|
40
|
+
def records_through_match(start_entry, direction, match_attributes)
|
41
|
+
last_entry = next_match(start_entry, direction, match_attributes)
|
42
|
+
return records_from(start_entry, direction).where.not("id #{exclusive_comparator(direction)} ?", last_entry)
|
43
|
+
end
|
44
|
+
|
45
|
+
def next_match(start_entry, direction, match_attributes)
|
46
|
+
records_from(start_entry, direction).where.not(:id => start_entry.id).where(match_attributes).first
|
47
|
+
end
|
48
|
+
|
49
|
+
def records_from(start_entry, direction)
|
50
|
+
scope = CommitEntry.where(:session => start_entry.session).where("id #{comparator(direction)} ?", start_entry.id)
|
51
|
+
scope = scope.reverse_order if direction == :desc
|
52
|
+
return scope
|
53
|
+
end
|
54
|
+
|
55
|
+
def comparator(direction)
|
56
|
+
exclusive_comparator(direction) + '='
|
57
|
+
end
|
58
|
+
|
59
|
+
def exclusive_comparator(direction)
|
60
|
+
direction == :asc ? '>' : '<'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -1,6 +1,9 @@
|
|
1
1
|
module Stagehand
|
2
2
|
module Staging
|
3
3
|
class Checklist
|
4
|
+
extend Cache
|
5
|
+
include Cache
|
6
|
+
|
4
7
|
def self.related_commits(commit)
|
5
8
|
Commit.find(related_commit_ids(commit))
|
6
9
|
end
|
@@ -34,10 +37,67 @@ module Stagehand
|
|
34
37
|
return related_entries
|
35
38
|
end
|
36
39
|
|
40
|
+
def self.associated_records(entries)
|
41
|
+
records = preload_records(compact_entries(entries)).select(&:record).flat_map do |entry|
|
42
|
+
associated_associations(entry.record_class).flat_map do |association|
|
43
|
+
entry.record.send(association)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
records.uniq!
|
48
|
+
records.compact!
|
49
|
+
records.select! {|record| stagehand_class?(record.class) }
|
50
|
+
|
51
|
+
return records
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns a list of entries that only includes a single entry for each record.
|
55
|
+
# The type of entry chosen prioritizes creates over updates, and deletes over creates.
|
56
|
+
def self.compact_entries(entries)
|
57
|
+
compact_entries = group_entries(entries)
|
58
|
+
compact_entries = compact_entries[:delete] + compact_entries[:insert] + compact_entries[:update]
|
59
|
+
compact_entries.uniq!(&:key)
|
60
|
+
|
61
|
+
return compact_entries
|
62
|
+
end
|
63
|
+
|
64
|
+
# Groups entries by their operation
|
65
|
+
def self.group_entries(entries)
|
66
|
+
group_entries = Hash.new {|h,k| h[k] = [] }
|
67
|
+
group_entries.merge! entries.group_by(&:operation).symbolize_keys!
|
68
|
+
|
69
|
+
return group_entries
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.preload_records(entries)
|
73
|
+
entries.group_by(&:table_name).each do |table_name, group_entries|
|
74
|
+
klass = CommitEntry.infer_class(table_name)
|
75
|
+
records = klass.where(:id => group_entries.collect(&:record_id))
|
76
|
+
records = records.includes(associated_associations(klass))
|
77
|
+
records_by_id = records.collect {|r| [r.id, r] }.to_h
|
78
|
+
group_entries.each do |entry|
|
79
|
+
entry.record = records_by_id[entry.record_id]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
return entries
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def self.associated_associations(klass)
|
89
|
+
cache("#{klass.name}_associated_associations") { klass.reflect_on_all_associations(:belongs_to).collect(&:name) }
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.stagehand_class?(klass)
|
93
|
+
cache("#{klass.name}_stagehand_class?") { Schema.has_stagehand?(klass.table_name) }
|
94
|
+
end
|
95
|
+
|
96
|
+
public
|
97
|
+
|
37
98
|
def initialize(subject, &confirmation_filter)
|
38
99
|
@subject = subject
|
39
100
|
@confirmation_filter = confirmation_filter
|
40
|
-
@cache = {}
|
41
101
|
affected_entries # Init the affected_entries changes can be rolled back without affecting the checklist
|
42
102
|
end
|
43
103
|
|
@@ -64,7 +124,7 @@ module Stagehand
|
|
64
124
|
end
|
65
125
|
|
66
126
|
def syncing_entries
|
67
|
-
cache(:syncing_entries) { compact_entries(affected_entries) }
|
127
|
+
cache(:syncing_entries) { self.class.compact_entries(affected_entries) }
|
68
128
|
end
|
69
129
|
|
70
130
|
def affected_records
|
@@ -72,7 +132,13 @@ module Stagehand
|
|
72
132
|
end
|
73
133
|
|
74
134
|
def affected_entries
|
75
|
-
cache(:affected_entries)
|
135
|
+
cache(:affected_entries) do
|
136
|
+
related = self.class.related_entries(@subject)
|
137
|
+
associated = self.class.associated_records(related)
|
138
|
+
associated_related = self.class.related_entries(associated)
|
139
|
+
|
140
|
+
related + associated_related
|
141
|
+
end
|
76
142
|
end
|
77
143
|
|
78
144
|
private
|
@@ -89,59 +155,15 @@ module Stagehand
|
|
89
155
|
# Don't need to confirm entries that were not part of a commit
|
90
156
|
entries = entries.select(&:commit_id)
|
91
157
|
|
92
|
-
entries = compact_entries(entries)
|
93
|
-
entries = preload_records(entries)
|
158
|
+
entries = self.class.compact_entries(entries)
|
94
159
|
entries = filter_entries(entries)
|
95
|
-
entries = group_entries(entries)
|
160
|
+
entries = self.class.group_entries(entries)
|
96
161
|
end
|
97
162
|
end
|
98
163
|
|
99
164
|
def filter_entries(entries)
|
100
165
|
@confirmation_filter ? entries.select {|entry| @confirmation_filter.call(entry.record) } : entries
|
101
166
|
end
|
102
|
-
|
103
|
-
# Returns a list of entries that only includes a single entry for each record.
|
104
|
-
# The type of entry chosen prioritizes creates over updates, and deletes over creates.
|
105
|
-
def compact_entries(entries)
|
106
|
-
compact_entries = group_entries(entries)
|
107
|
-
compact_entries = compact_entries[:delete] + compact_entries[:insert] + compact_entries[:update]
|
108
|
-
compact_entries.uniq!(&:key)
|
109
|
-
|
110
|
-
return compact_entries
|
111
|
-
end
|
112
|
-
|
113
|
-
# Groups entries by their operation
|
114
|
-
def group_entries(entries)
|
115
|
-
group_entries = Hash.new {|h,k| h[k] = [] }
|
116
|
-
group_entries.merge! entries.group_by(&:operation).symbolize_keys!
|
117
|
-
|
118
|
-
return group_entries
|
119
|
-
end
|
120
|
-
|
121
|
-
def preload_records(entries)
|
122
|
-
entries.group_by(&:table_name).each do |table_name, group_entries|
|
123
|
-
klass = CommitEntry.infer_class(table_name)
|
124
|
-
records = klass.where(:id => group_entries.collect(&:record_id))
|
125
|
-
records_by_id = records.collect {|r| [r.id, r] }.to_h
|
126
|
-
group_entries.each do |entry|
|
127
|
-
entry.record = records_by_id[entry.record_id]
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
return entries
|
132
|
-
end
|
133
|
-
|
134
|
-
def cache(key, &block)
|
135
|
-
if @cache.key?(key)
|
136
|
-
@cache[key]
|
137
|
-
else
|
138
|
-
@cache[key] = block.call
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
def clear_cache
|
143
|
-
@cache.clear
|
144
|
-
end
|
145
167
|
end
|
146
168
|
end
|
147
169
|
end
|
@@ -40,6 +40,10 @@ module Stagehand
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def sync_entries(entries)
|
43
|
+
return 0 if Configuration.single_connection? # Avoid deadlocking if the databases are the same
|
44
|
+
|
45
|
+
raise SchemaMismatch unless schemas_match?
|
46
|
+
|
43
47
|
ActiveRecord::Base.transaction do
|
44
48
|
entries.each do |entry|
|
45
49
|
Rails.logger.info "Synchronizing #{entry.table_name} #{entry.record_id}"
|
@@ -62,10 +66,18 @@ module Stagehand
|
|
62
66
|
CommitEntry.select('MAX(id) AS id').content_operations.not_in_progress.group('record_id, table_name').having('count(commit_id) = 0'))
|
63
67
|
end
|
64
68
|
end
|
69
|
+
|
70
|
+
def schemas_match?
|
71
|
+
versions_scope = ActiveRecord::SchemaMigration.order(:version)
|
72
|
+
staging_versions = Stagehand::Database.staging_connection.select_values(versions_scope)
|
73
|
+
production_versions = Stagehand::Database.production_connection.select_values(versions_scope)
|
74
|
+
return staging_versions == production_versions
|
75
|
+
end
|
65
76
|
end
|
66
77
|
end
|
67
78
|
|
68
79
|
# EXCEPTIONS
|
69
80
|
|
70
81
|
class SyncBlockRequired < StandardError; end
|
82
|
+
class SchemaMismatch < StandardError; end
|
71
83
|
end
|
data/lib/stagehand/staging.rb
CHANGED
data/lib/stagehand/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: culturecode_stagehand
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nicholas Jakobsen
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-04-
|
12
|
+
date: 2016-04-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -67,15 +67,18 @@ files:
|
|
67
67
|
- Rakefile
|
68
68
|
- lib/culturecode_stagehand.rb
|
69
69
|
- lib/stagehand.rb
|
70
|
+
- lib/stagehand/cache.rb
|
70
71
|
- lib/stagehand/configuration.rb
|
71
72
|
- lib/stagehand/controller_extensions.rb
|
73
|
+
- lib/stagehand/database.rb
|
72
74
|
- lib/stagehand/engine.rb
|
73
|
-
- lib/stagehand/
|
75
|
+
- lib/stagehand/key.rb
|
74
76
|
- lib/stagehand/production.rb
|
75
77
|
- lib/stagehand/production/controller.rb
|
76
78
|
- lib/stagehand/schema.rb
|
77
79
|
- lib/stagehand/schema/statements.rb
|
78
80
|
- lib/stagehand/staging.rb
|
81
|
+
- lib/stagehand/staging/auditor.rb
|
79
82
|
- lib/stagehand/staging/checklist.rb
|
80
83
|
- lib/stagehand/staging/commit.rb
|
81
84
|
- lib/stagehand/staging/commit_entry.rb
|