statesman 10.0.0 → 10.2.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.
- checksums.yaml +4 -4
- data/.github/workflows/tests.yml +106 -0
- data/.rubocop.yml +2 -1
- data/.ruby-version +1 -1
- data/CHANGELOG.md +10 -0
- data/Gemfile +1 -0
- data/README.md +24 -0
- data/lib/generators/statesman/active_record_transition_generator.rb +1 -1
- data/lib/statesman/adapters/active_record.rb +6 -8
- data/lib/statesman/adapters/active_record_queries.rb +5 -5
- data/lib/statesman/adapters/memory.rb +1 -1
- data/lib/statesman/adapters/type_safe_active_record_queries.rb +21 -0
- data/lib/statesman/exceptions.rb +9 -7
- data/lib/statesman/guard.rb +1 -1
- data/lib/statesman/version.rb +1 -1
- data/lib/statesman.rb +2 -0
- data/lib/tasks/statesman.rake +3 -3
- data/spec/statesman/adapters/active_record_queries_spec.rb +5 -5
- data/spec/statesman/adapters/active_record_spec.rb +27 -19
- data/spec/statesman/adapters/shared_examples.rb +2 -2
- data/spec/statesman/adapters/type_safe_active_record_queries_spec.rb +208 -0
- data/spec/statesman/exceptions_spec.rb +7 -1
- data/spec/statesman/machine_spec.rb +10 -10
- data/spec/support/active_record.rb +2 -8
- data/statesman.gemspec +6 -7
- metadata +22 -53
- data/.circleci/config.yml +0 -127
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f18f4e346afec7b89e6057602992d3d69f73f7c18f99d88bb3604d34724f9b0
|
4
|
+
data.tar.gz: 9888c2c3bc47bb78a52f2b086d9bc3729ddefec9ab776663ebf04ec9118c4d05
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50cdb42aa87bf9ab25e4f5a0de6f4f52647866453d9298811351ac16fdec88e7ff7b210948f756b9af59983e56cc5ca842232ae240be54f1a9e37185958eee9d
|
7
|
+
data.tar.gz: c9835aa4537d9e8adab3a75d6f63b020eaac4d4ec5aa15a8be4a4f2a6f41a869a54b5398862b23b84929cf219aff6b86eac00af3fd4a86b3e4c0ff3a6c84bae7
|
@@ -0,0 +1,106 @@
|
|
1
|
+
name: tests
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- "master"
|
7
|
+
pull_request:
|
8
|
+
|
9
|
+
concurrency:
|
10
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
11
|
+
cancel-in-progress: true
|
12
|
+
|
13
|
+
jobs:
|
14
|
+
rubocop:
|
15
|
+
runs-on: ubuntu-latest
|
16
|
+
steps:
|
17
|
+
- uses: actions/checkout@v3
|
18
|
+
- uses: ruby/setup-ruby@v1
|
19
|
+
with:
|
20
|
+
bundler-cache: true
|
21
|
+
- run: bundle exec rubocop --extra-details --display-style-guide --parallel --force-exclusion
|
22
|
+
|
23
|
+
postgres:
|
24
|
+
strategy:
|
25
|
+
fail-fast: false
|
26
|
+
matrix:
|
27
|
+
ruby-version: ["2.7", "3.0", "3.1", "3.2"]
|
28
|
+
rails-version:
|
29
|
+
- "6.1.5"
|
30
|
+
- "7.0.4"
|
31
|
+
- "main"
|
32
|
+
postgres-version: ["9.6", "11", "14"]
|
33
|
+
exclude:
|
34
|
+
- ruby-version: "3.2"
|
35
|
+
rails-version: "6.1.5"
|
36
|
+
runs-on: ubuntu-latest
|
37
|
+
services:
|
38
|
+
postgres:
|
39
|
+
image: postgres:${{ matrix.postgres-version }}
|
40
|
+
env:
|
41
|
+
POSTGRES_USER: postgres
|
42
|
+
POSTGRES_DB: statesman_test
|
43
|
+
POSTGRES_PASSWORD: statesman
|
44
|
+
ports:
|
45
|
+
- 5432:5432
|
46
|
+
options: >-
|
47
|
+
--health-cmd pg_isready
|
48
|
+
--health-interval 10s
|
49
|
+
--health-timeout 5s
|
50
|
+
--health-retries 10
|
51
|
+
env:
|
52
|
+
DATABASE_URL: postgres://postgres:statesman@localhost/statesman_test
|
53
|
+
DATABASE_DEPENDENCY_PORT: "5432"
|
54
|
+
steps:
|
55
|
+
- uses: actions/checkout@v3
|
56
|
+
- name: Set up Ruby
|
57
|
+
uses: ruby/setup-ruby@v1
|
58
|
+
with:
|
59
|
+
bundler-cache: true
|
60
|
+
ruby-version: "${{ matrix.ruby-version }}"
|
61
|
+
- name: Run specs
|
62
|
+
run: |
|
63
|
+
bundle exec rspec --profile --format progress --format RSpec::Github::Formatter
|
64
|
+
|
65
|
+
mysql:
|
66
|
+
strategy:
|
67
|
+
fail-fast: false
|
68
|
+
matrix:
|
69
|
+
ruby-version: ["2.7", "3.0", "3.1", "3.2"]
|
70
|
+
rails-version:
|
71
|
+
- "6.1.5"
|
72
|
+
- "7.0.4"
|
73
|
+
- "main"
|
74
|
+
mysql-version: ["5.7", "8.0"]
|
75
|
+
exclude:
|
76
|
+
- ruby-version: 3.2
|
77
|
+
rails-version: "6.1.5"
|
78
|
+
runs-on: ubuntu-latest
|
79
|
+
services:
|
80
|
+
mysql:
|
81
|
+
image: mysql:${{ matrix.mysql-version }}
|
82
|
+
env:
|
83
|
+
MYSQL_ROOT_PASSWORD: password
|
84
|
+
MYSQL_USER: foobar
|
85
|
+
MYSQL_PASSWORD: password
|
86
|
+
MYSQL_DATABASE: statesman_test
|
87
|
+
ports:
|
88
|
+
- "3306:3306"
|
89
|
+
options: >-
|
90
|
+
--health-cmd "mysqladmin ping"
|
91
|
+
--health-interval 10s
|
92
|
+
--health-timeout 5s
|
93
|
+
--health-retries 5
|
94
|
+
env:
|
95
|
+
DATABASE_URL: mysql2://foobar:password@127.0.0.1/statesman_test
|
96
|
+
DATABASE_DEPENDENCY_PORT: "3306"
|
97
|
+
steps:
|
98
|
+
- uses: actions/checkout@v3
|
99
|
+
- name: Set up Ruby
|
100
|
+
uses: ruby/setup-ruby@v1
|
101
|
+
with:
|
102
|
+
bundler-cache: true
|
103
|
+
ruby-version: "${{ matrix.ruby-version }}"
|
104
|
+
- name: Run specs
|
105
|
+
run: |
|
106
|
+
bundle exec rspec --profile --format progress --format RSpec::Github::Formatter
|
data/.rubocop.yml
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.0
|
1
|
+
3.2.0
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
## v10.2.0 3rd April 2023
|
2
|
+
|
3
|
+
### Changed
|
4
|
+
- Fixed caching of `last_transition` [#505](https://github.com/gocardless/statesman/pull/505)
|
5
|
+
|
6
|
+
## v10.1.0 10th March 2023
|
7
|
+
|
8
|
+
### CHanged
|
9
|
+
- Add the source location of the guard callback to `Statesman::GuardFailedError`
|
10
|
+
|
1
11
|
## v10.0.0 17th May 2022
|
2
12
|
|
3
13
|
### Changed
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -611,6 +611,30 @@ describe "some callback" do
|
|
611
611
|
end
|
612
612
|
```
|
613
613
|
|
614
|
+
## Compatibility with type checkers
|
615
|
+
|
616
|
+
Including ActiveRecordQueries to your model can cause issues with type checkers
|
617
|
+
such as Sorbet, this is because this technically is using a dynamic include,
|
618
|
+
which is not supported by Sorbet.
|
619
|
+
|
620
|
+
To avoid these issues you can instead include the TypeSafeActiveRecordQueries
|
621
|
+
module and pass in configuration.
|
622
|
+
|
623
|
+
```ruby
|
624
|
+
class Order < ActiveRecord::Base
|
625
|
+
has_many :order_transitions, autosave: false
|
626
|
+
|
627
|
+
include Statesman::Adapters::TypeSafeActiveRecordQueries
|
628
|
+
|
629
|
+
configure_state_machine transition_class: OrderTransition,
|
630
|
+
initial_state: :pending
|
631
|
+
|
632
|
+
def state_machine
|
633
|
+
@state_machine ||= OrderStateMachine.new(self, transition_class: OrderTransition)
|
634
|
+
end
|
635
|
+
end
|
636
|
+
```
|
637
|
+
|
614
638
|
# Third-party extensions
|
615
639
|
|
616
640
|
[statesman-sequel](https://github.com/badosu/statesman-sequel) - An adapter to make Statesman work with [Sequel](https://github.com/jeremyevans/sequel)
|
@@ -7,7 +7,7 @@ module Statesman
|
|
7
7
|
class ActiveRecordTransitionGenerator < Rails::Generators::Base
|
8
8
|
include Statesman::GeneratorHelpers
|
9
9
|
|
10
|
-
desc "Create an ActiveRecord-based transition model"\
|
10
|
+
desc "Create an ActiveRecord-based transition model" \
|
11
11
|
"with the required attributes"
|
12
12
|
|
13
13
|
argument :parent, type: :string, desc: "Your parent model name"
|
@@ -52,7 +52,7 @@ module Statesman
|
|
52
52
|
|
53
53
|
raise
|
54
54
|
ensure
|
55
|
-
|
55
|
+
remove_instance_variable(:@last_transition)
|
56
56
|
end
|
57
57
|
|
58
58
|
def history(force_reload: false)
|
@@ -65,23 +65,22 @@ module Statesman
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
-
# rubocop:disable Naming/MemoizedInstanceVariableName
|
69
68
|
def last(force_reload: false)
|
70
69
|
if force_reload
|
71
70
|
@last_transition = history(force_reload: true).last
|
71
|
+
elsif instance_variable_defined?(:@last_transition)
|
72
|
+
@last_transition
|
72
73
|
else
|
73
|
-
@last_transition
|
74
|
+
@last_transition = history.last
|
74
75
|
end
|
75
76
|
end
|
76
|
-
# rubocop:enable Naming/MemoizedInstanceVariableName
|
77
77
|
|
78
78
|
def reset
|
79
|
-
|
79
|
+
remove_instance_variable(:@last_transition)
|
80
80
|
end
|
81
81
|
|
82
82
|
private
|
83
83
|
|
84
|
-
# rubocop:disable Metrics/MethodLength
|
85
84
|
def create_transition(from, to, metadata)
|
86
85
|
transition = transitions_for_parent.build(
|
87
86
|
default_transition_attributes(to, metadata),
|
@@ -118,7 +117,6 @@ module Statesman
|
|
118
117
|
|
119
118
|
transition
|
120
119
|
end
|
121
|
-
# rubocop:enable Metrics/MethodLength
|
122
120
|
|
123
121
|
def default_transition_attributes(to, metadata)
|
124
122
|
{
|
@@ -231,7 +229,7 @@ module Statesman
|
|
231
229
|
end
|
232
230
|
|
233
231
|
def next_sort_key
|
234
|
-
(last && last.sort_key + 10) || 10
|
232
|
+
(last && (last.sort_key + 10)) || 10
|
235
233
|
end
|
236
234
|
|
237
235
|
def serialized?(transition_class)
|
@@ -95,18 +95,18 @@ module Statesman
|
|
95
95
|
def states_where(states)
|
96
96
|
if initial_state.to_s.in?(states.map(&:to_s))
|
97
97
|
"#{most_recent_transition_alias}.to_state IN (?) OR " \
|
98
|
-
|
98
|
+
"#{most_recent_transition_alias}.to_state IS NULL"
|
99
99
|
else
|
100
100
|
"#{most_recent_transition_alias}.to_state IN (?) AND " \
|
101
|
-
|
101
|
+
"#{most_recent_transition_alias}.to_state IS NOT NULL"
|
102
102
|
end
|
103
103
|
end
|
104
104
|
|
105
105
|
def most_recent_transition_join
|
106
106
|
"LEFT OUTER JOIN #{model_table} AS #{most_recent_transition_alias} " \
|
107
|
-
|
108
|
-
|
109
|
-
|
107
|
+
"ON #{model.table_name}.#{model_primary_key} = " \
|
108
|
+
"#{most_recent_transition_alias}.#{model_foreign_key} " \
|
109
|
+
"AND #{most_recent_transition_alias}.most_recent = #{db_true}"
|
110
110
|
end
|
111
111
|
|
112
112
|
private
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Statesman
|
4
|
+
module Adapters
|
5
|
+
module TypeSafeActiveRecordQueries
|
6
|
+
def configure_state_machine(args = {})
|
7
|
+
transition_class = args.fetch(:transition_class)
|
8
|
+
initial_state = args.fetch(:initial_state)
|
9
|
+
|
10
|
+
include(
|
11
|
+
ActiveRecordQueries::ClassMethods.new(
|
12
|
+
transition_class: transition_class,
|
13
|
+
initial_state: initial_state,
|
14
|
+
most_recent_transition_alias: try(:most_recent_transition_alias),
|
15
|
+
transition_name: try(:transition_name),
|
16
|
+
),
|
17
|
+
)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/statesman/exceptions.rb
CHANGED
@@ -28,13 +28,15 @@ module Statesman
|
|
28
28
|
end
|
29
29
|
|
30
30
|
class GuardFailedError < StandardError
|
31
|
-
def initialize(from, to)
|
31
|
+
def initialize(from, to, callback)
|
32
32
|
@from = from
|
33
33
|
@to = to
|
34
|
+
@callback = callback
|
34
35
|
super(_message)
|
36
|
+
set_backtrace(callback.source_location.join(":")) if callback&.source_location
|
35
37
|
end
|
36
38
|
|
37
|
-
attr_reader :from, :to
|
39
|
+
attr_reader :from, :to, :callback
|
38
40
|
|
39
41
|
private
|
40
42
|
|
@@ -52,8 +54,8 @@ module Statesman
|
|
52
54
|
|
53
55
|
def _message(transition_class_name)
|
54
56
|
"#{transition_class_name}#metadata is not serialized. If you " \
|
55
|
-
|
56
|
-
|
57
|
+
"are using a non-json column type, you should `include " \
|
58
|
+
"Statesman::Adapters::ActiveRecordTransition`"
|
57
59
|
end
|
58
60
|
end
|
59
61
|
|
@@ -66,9 +68,9 @@ module Statesman
|
|
66
68
|
|
67
69
|
def _message(transition_class_name)
|
68
70
|
"#{transition_class_name}#metadata column type cannot be json " \
|
69
|
-
|
70
|
-
|
71
|
-
|
71
|
+
"and serialized simultaneously. If you are using a json " \
|
72
|
+
"column type, it is not necessary to `include " \
|
73
|
+
"Statesman::Adapters::ActiveRecordTransition`"
|
72
74
|
end
|
73
75
|
end
|
74
76
|
end
|
data/lib/statesman/guard.rb
CHANGED
data/lib/statesman/version.rb
CHANGED
data/lib/statesman.rb
CHANGED
@@ -14,6 +14,8 @@ module Statesman
|
|
14
14
|
"statesman/adapters/active_record_transition"
|
15
15
|
autoload :ActiveRecordQueries,
|
16
16
|
"statesman/adapters/active_record_queries"
|
17
|
+
autoload :TypeSafeActiveRecordQueries,
|
18
|
+
"statesman/adapters/type_safe_active_record_queries"
|
17
19
|
end
|
18
20
|
require "statesman/railtie" if defined?(::Rails::Railtie)
|
19
21
|
|
data/lib/tasks/statesman.rake
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
namespace :statesman do
|
4
|
-
desc "Set most_recent to false for old transitions and to true for the "\
|
4
|
+
desc "Set most_recent to false for old transitions and to true for the " \
|
5
5
|
"latest one. Safe to re-run"
|
6
6
|
task :backfill_most_recent, [:parent_model_name] => :environment do |_, args|
|
7
7
|
parent_model_name = args.parent_model_name
|
@@ -56,8 +56,8 @@ namespace :statesman do
|
|
56
56
|
end
|
57
57
|
|
58
58
|
done_models += batch_size
|
59
|
-
puts "Updated #{transition_class.name.pluralize} for "\
|
60
|
-
"#{[done_models, total_models].min}/#{total_models} "\
|
59
|
+
puts "Updated #{transition_class.name.pluralize} for " \
|
60
|
+
"#{[done_models, total_models].min}/#{total_models} " \
|
61
61
|
"#{parent_model_name.pluralize}"
|
62
62
|
end
|
63
63
|
end
|
@@ -117,8 +117,8 @@ describe Statesman::Adapters::ActiveRecordQueries, active_record: true do
|
|
117
117
|
subject(:not_in_state) { MyActiveRecordModel.not_in_state(:succeeded, :failed) }
|
118
118
|
|
119
119
|
it do
|
120
|
-
expect(not_in_state).to
|
121
|
-
|
120
|
+
expect(not_in_state).to contain_exactly(initial_state_model,
|
121
|
+
returned_to_initial_model)
|
122
122
|
end
|
123
123
|
end
|
124
124
|
|
@@ -126,8 +126,8 @@ describe Statesman::Adapters::ActiveRecordQueries, active_record: true do
|
|
126
126
|
subject(:not_in_state) { MyActiveRecordModel.not_in_state(%i[succeeded failed]) }
|
127
127
|
|
128
128
|
it do
|
129
|
-
expect(not_in_state).to
|
130
|
-
|
129
|
+
expect(not_in_state).to contain_exactly(initial_state_model,
|
130
|
+
returned_to_initial_model)
|
131
131
|
end
|
132
132
|
end
|
133
133
|
end
|
@@ -254,7 +254,7 @@ describe Statesman::Adapters::ActiveRecordQueries, active_record: true do
|
|
254
254
|
end
|
255
255
|
|
256
256
|
it "does not raise an error" do
|
257
|
-
expect { check_missing_methods! }.to_not raise_exception
|
257
|
+
expect { check_missing_methods! }.to_not raise_exception
|
258
258
|
end
|
259
259
|
end
|
260
260
|
|
@@ -35,8 +35,8 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
|
|
35
35
|
allow(metadata_column).to receive_messages(sql_type: "")
|
36
36
|
allow(MyActiveRecordModelTransition).to receive_messages(columns_hash:
|
37
37
|
{ "metadata" => metadata_column })
|
38
|
-
if
|
39
|
-
|
38
|
+
if ActiveRecord.respond_to?(:gem_version) &&
|
39
|
+
ActiveRecord.gem_version >= Gem::Version.new("4.2.0.a")
|
40
40
|
expect(MyActiveRecordModelTransition).
|
41
41
|
to receive(:type_for_attribute).with("metadata").
|
42
42
|
and_return(ActiveRecord::Type::Value.new)
|
@@ -60,10 +60,10 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
|
|
60
60
|
allow(metadata_column).to receive_messages(sql_type: "json")
|
61
61
|
allow(MyActiveRecordModelTransition).to receive_messages(columns_hash:
|
62
62
|
{ "metadata" => metadata_column })
|
63
|
-
if
|
64
|
-
|
65
|
-
serialized_type =
|
66
|
-
"",
|
63
|
+
if ActiveRecord.respond_to?(:gem_version) &&
|
64
|
+
ActiveRecord.gem_version >= Gem::Version.new("4.2.0.a")
|
65
|
+
serialized_type = ActiveRecord::Type::Serialized.new(
|
66
|
+
"", ActiveRecord::Coders::JSON
|
67
67
|
)
|
68
68
|
expect(MyActiveRecordModelTransition).
|
69
69
|
to receive(:type_for_attribute).with("metadata").
|
@@ -88,10 +88,10 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
|
|
88
88
|
allow(metadata_column).to receive_messages(sql_type: "jsonb")
|
89
89
|
allow(MyActiveRecordModelTransition).to receive_messages(columns_hash:
|
90
90
|
{ "metadata" => metadata_column })
|
91
|
-
if
|
92
|
-
|
93
|
-
serialized_type =
|
94
|
-
"",
|
91
|
+
if ActiveRecord.respond_to?(:gem_version) &&
|
92
|
+
ActiveRecord.gem_version >= Gem::Version.new("4.2.0.a")
|
93
|
+
serialized_type = ActiveRecord::Type::Serialized.new(
|
94
|
+
"", ActiveRecord::Coders::JSON
|
95
95
|
)
|
96
96
|
expect(MyActiveRecordModelTransition).
|
97
97
|
to receive(:type_for_attribute).with("metadata").
|
@@ -112,7 +112,7 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
|
|
112
112
|
end
|
113
113
|
|
114
114
|
describe "#create" do
|
115
|
-
subject {
|
115
|
+
subject(:transition) { create }
|
116
116
|
|
117
117
|
let!(:adapter) do
|
118
118
|
described_class.new(MyActiveRecordModelTransition, model, observer)
|
@@ -165,27 +165,25 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
|
|
165
165
|
|
166
166
|
context "ActiveRecord::RecordNotUnique unrelated to this transition" do
|
167
167
|
let(:error) do
|
168
|
-
if
|
169
|
-
|
168
|
+
if ActiveRecord.respond_to?(:gem_version) &&
|
169
|
+
ActiveRecord.gem_version >= Gem::Version.new("4.0.0")
|
170
170
|
ActiveRecord::RecordNotUnique.new("unrelated")
|
171
171
|
else
|
172
172
|
ActiveRecord::RecordNotUnique.new("unrelated", nil)
|
173
173
|
end
|
174
174
|
end
|
175
175
|
|
176
|
-
it {
|
176
|
+
it { expect { transition }.to raise_exception(ActiveRecord::RecordNotUnique) }
|
177
177
|
end
|
178
178
|
|
179
179
|
context "other errors" do
|
180
180
|
let(:error) { StandardError }
|
181
181
|
|
182
|
-
it {
|
182
|
+
it { expect { transition }.to raise_exception(StandardError) }
|
183
183
|
end
|
184
184
|
end
|
185
185
|
|
186
186
|
describe "updating the most_recent column" do
|
187
|
-
subject { create }
|
188
|
-
|
189
187
|
context "with no previous transition" do
|
190
188
|
its(:most_recent) { is_expected.to eq(true) }
|
191
189
|
end
|
@@ -310,9 +308,9 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
|
|
310
308
|
described_class.new(MyActiveRecordModelTransition, model, observer)
|
311
309
|
end
|
312
310
|
|
313
|
-
before { adapter.create(:x, :y) }
|
314
|
-
|
315
311
|
context "with a previously looked up transition" do
|
312
|
+
before { adapter.create(:x, :y) }
|
313
|
+
|
316
314
|
before { adapter.last }
|
317
315
|
|
318
316
|
it "caches the transition" do
|
@@ -378,6 +376,16 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
|
|
378
376
|
expect(adapter.last.to_state).to eq("y")
|
379
377
|
end
|
380
378
|
end
|
379
|
+
|
380
|
+
context "without previous transitions" do
|
381
|
+
it "does query the database only once" do
|
382
|
+
expect(model.my_active_record_model_transitions).
|
383
|
+
to receive(:order).once.and_call_original
|
384
|
+
|
385
|
+
expect(adapter.last).to eq(nil)
|
386
|
+
expect(adapter.last).to eq(nil)
|
387
|
+
end
|
388
|
+
end
|
381
389
|
end
|
382
390
|
|
383
391
|
it "resets last with #reload" do
|
@@ -30,14 +30,14 @@ shared_examples_for "an adapter" do |adapter_class, transition_class, options =
|
|
30
30
|
end
|
31
31
|
|
32
32
|
describe "#create" do
|
33
|
-
subject {
|
33
|
+
subject(:transition) { create }
|
34
34
|
|
35
35
|
let(:from) { :x }
|
36
36
|
let(:to) { :y }
|
37
37
|
let(:there) { :z }
|
38
38
|
let(:create) { adapter.create(from, to) }
|
39
39
|
|
40
|
-
it {
|
40
|
+
it { expect { transition }.to change(adapter.history, :count).by(1) }
|
41
41
|
|
42
42
|
context "the new transition" do
|
43
43
|
subject(:instance) { create }
|
@@ -0,0 +1,208 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe Statesman::Adapters::TypeSafeActiveRecordQueries, active_record: true do
|
6
|
+
def configure(klass, transition_class)
|
7
|
+
klass.send(:extend, described_class)
|
8
|
+
klass.configure_state_machine(
|
9
|
+
transition_class: transition_class,
|
10
|
+
initial_state: :initial,
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
before do
|
15
|
+
prepare_model_table
|
16
|
+
prepare_transitions_table
|
17
|
+
prepare_other_model_table
|
18
|
+
prepare_other_transitions_table
|
19
|
+
|
20
|
+
Statesman.configure do
|
21
|
+
storage_adapter(Statesman::Adapters::ActiveRecord)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
after { Statesman.configure { storage_adapter(Statesman::Adapters::Memory) } }
|
26
|
+
|
27
|
+
let!(:model) do
|
28
|
+
model = MyActiveRecordModel.create
|
29
|
+
model.state_machine.transition_to(:succeeded)
|
30
|
+
model
|
31
|
+
end
|
32
|
+
|
33
|
+
let!(:other_model) do
|
34
|
+
model = MyActiveRecordModel.create
|
35
|
+
model.state_machine.transition_to(:failed)
|
36
|
+
model
|
37
|
+
end
|
38
|
+
|
39
|
+
let!(:initial_state_model) { MyActiveRecordModel.create }
|
40
|
+
|
41
|
+
let!(:returned_to_initial_model) do
|
42
|
+
model = MyActiveRecordModel.create
|
43
|
+
model.state_machine.transition_to(:failed)
|
44
|
+
model.state_machine.transition_to(:initial)
|
45
|
+
model
|
46
|
+
end
|
47
|
+
|
48
|
+
shared_examples "testing methods" do
|
49
|
+
before do
|
50
|
+
configure(MyActiveRecordModel, MyActiveRecordModelTransition)
|
51
|
+
configure(OtherActiveRecordModel, OtherActiveRecordModelTransition)
|
52
|
+
|
53
|
+
MyActiveRecordModel.send(:has_one, :other_active_record_model)
|
54
|
+
OtherActiveRecordModel.send(:belongs_to, :my_active_record_model)
|
55
|
+
end
|
56
|
+
|
57
|
+
describe ".in_state" do
|
58
|
+
context "given a single state" do
|
59
|
+
subject { MyActiveRecordModel.in_state(:succeeded) }
|
60
|
+
|
61
|
+
it { is_expected.to include model }
|
62
|
+
it { is_expected.to_not include other_model }
|
63
|
+
end
|
64
|
+
|
65
|
+
context "given multiple states" do
|
66
|
+
subject { MyActiveRecordModel.in_state(:succeeded, :failed) }
|
67
|
+
|
68
|
+
it { is_expected.to include model }
|
69
|
+
it { is_expected.to include other_model }
|
70
|
+
end
|
71
|
+
|
72
|
+
context "given the initial state" do
|
73
|
+
subject { MyActiveRecordModel.in_state(:initial) }
|
74
|
+
|
75
|
+
it { is_expected.to include initial_state_model }
|
76
|
+
it { is_expected.to include returned_to_initial_model }
|
77
|
+
end
|
78
|
+
|
79
|
+
context "given an array of states" do
|
80
|
+
subject { MyActiveRecordModel.in_state(%i[succeeded failed]) }
|
81
|
+
|
82
|
+
it { is_expected.to include model }
|
83
|
+
it { is_expected.to include other_model }
|
84
|
+
end
|
85
|
+
|
86
|
+
context "merging two queries" do
|
87
|
+
subject do
|
88
|
+
MyActiveRecordModel.in_state(:succeeded).
|
89
|
+
joins(:other_active_record_model).
|
90
|
+
merge(OtherActiveRecordModel.in_state(:initial))
|
91
|
+
end
|
92
|
+
|
93
|
+
it { is_expected.to be_empty }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe ".not_in_state" do
|
98
|
+
context "given a single state" do
|
99
|
+
subject { MyActiveRecordModel.not_in_state(:failed) }
|
100
|
+
|
101
|
+
it { is_expected.to include model }
|
102
|
+
it { is_expected.to_not include other_model }
|
103
|
+
end
|
104
|
+
|
105
|
+
context "given multiple states" do
|
106
|
+
subject(:not_in_state) { MyActiveRecordModel.not_in_state(:succeeded, :failed) }
|
107
|
+
|
108
|
+
it do
|
109
|
+
expect(not_in_state).to contain_exactly(initial_state_model,
|
110
|
+
returned_to_initial_model)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context "given an array of states" do
|
115
|
+
subject(:not_in_state) { MyActiveRecordModel.not_in_state(%i[succeeded failed]) }
|
116
|
+
|
117
|
+
it do
|
118
|
+
expect(not_in_state).to contain_exactly(initial_state_model,
|
119
|
+
returned_to_initial_model)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context "with a custom name for the transition association" do
|
125
|
+
before do
|
126
|
+
# Switch to using OtherActiveRecordModelTransition, so the existing
|
127
|
+
# relation with MyActiveRecordModelTransition doesn't interfere with
|
128
|
+
# this spec.
|
129
|
+
MyActiveRecordModel.send(:has_many,
|
130
|
+
:custom_name,
|
131
|
+
class_name: "OtherActiveRecordModelTransition")
|
132
|
+
|
133
|
+
MyActiveRecordModel.class_eval do
|
134
|
+
def self.transition_class
|
135
|
+
OtherActiveRecordModelTransition
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe ".in_state" do
|
141
|
+
subject(:query) { MyActiveRecordModel.in_state(:succeeded) }
|
142
|
+
|
143
|
+
specify { expect { query }.to_not raise_error }
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context "with a custom primary key for the model" do
|
148
|
+
before do
|
149
|
+
# Switch to using OtherActiveRecordModelTransition, so the existing
|
150
|
+
# relation with MyActiveRecordModelTransition doesn't interfere with
|
151
|
+
# this spec.
|
152
|
+
# Configure the relationship to use a different primary key,
|
153
|
+
MyActiveRecordModel.send(:has_many,
|
154
|
+
:custom_name,
|
155
|
+
class_name: "OtherActiveRecordModelTransition",
|
156
|
+
primary_key: :external_id)
|
157
|
+
|
158
|
+
MyActiveRecordModel.class_eval do
|
159
|
+
def self.transition_class
|
160
|
+
OtherActiveRecordModelTransition
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe ".in_state" do
|
166
|
+
subject(:query) { MyActiveRecordModel.in_state(:succeeded) }
|
167
|
+
|
168
|
+
specify { expect { query }.to_not raise_error }
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
context "after_commit transactional integrity" do
|
173
|
+
before do
|
174
|
+
MyStateMachine.class_eval do
|
175
|
+
cattr_accessor(:after_commit_callback_executed) { false }
|
176
|
+
|
177
|
+
after_transition(from: :initial, to: :succeeded, after_commit: true) do
|
178
|
+
# This leaks state in a testable way if transactional integrity is broken.
|
179
|
+
MyStateMachine.after_commit_callback_executed = true
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
after do
|
185
|
+
MyStateMachine.class_eval do
|
186
|
+
callbacks[:after_commit] = []
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
let!(:model) do
|
191
|
+
MyActiveRecordModel.create
|
192
|
+
end
|
193
|
+
|
194
|
+
it do
|
195
|
+
expect do
|
196
|
+
ActiveRecord::Base.transaction do
|
197
|
+
model.state_machine.transition_to!(:succeeded)
|
198
|
+
raise ActiveRecord::Rollback
|
199
|
+
end
|
200
|
+
end.to_not change(MyStateMachine, :after_commit_callback_executed)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
context "using configuration method" do
|
206
|
+
include_examples "testing methods"
|
207
|
+
end
|
208
|
+
end
|
@@ -64,12 +64,18 @@ describe Statesman do
|
|
64
64
|
end
|
65
65
|
|
66
66
|
describe "GuardFailedError" do
|
67
|
-
subject(:error) { Statesman::GuardFailedError.new("from", "to") }
|
67
|
+
subject(:error) { Statesman::GuardFailedError.new("from", "to", callback) }
|
68
|
+
|
69
|
+
let(:callback) { -> { "hello" } }
|
68
70
|
|
69
71
|
its(:message) do
|
70
72
|
is_expected.to eq("Guard on transition from: 'from' to 'to' returned false")
|
71
73
|
end
|
72
74
|
|
75
|
+
its(:backtrace) do
|
76
|
+
is_expected.to eq([callback.source_location.join(":")])
|
77
|
+
end
|
78
|
+
|
73
79
|
its "string matches its message" do
|
74
80
|
expect(error.to_s).to eq(error.message)
|
75
81
|
end
|
@@ -28,7 +28,7 @@ describe Statesman::Machine do
|
|
28
28
|
end
|
29
29
|
|
30
30
|
describe ".remove_state" do
|
31
|
-
subject(:remove_state) {
|
31
|
+
subject(:remove_state) { machine.remove_state(:x) }
|
32
32
|
|
33
33
|
before do
|
34
34
|
machine.class_eval do
|
@@ -39,7 +39,7 @@ describe Statesman::Machine do
|
|
39
39
|
end
|
40
40
|
|
41
41
|
it "removes the state" do
|
42
|
-
expect
|
42
|
+
expect { remove_state }.
|
43
43
|
to change(machine, :states).
|
44
44
|
from(match_array(%w[x y z])).
|
45
45
|
to(%w[y z])
|
@@ -49,7 +49,7 @@ describe Statesman::Machine do
|
|
49
49
|
before { machine.transition from: :x, to: :y }
|
50
50
|
|
51
51
|
it "removes the transition" do
|
52
|
-
expect
|
52
|
+
expect { remove_state }.
|
53
53
|
to change(machine, :successors).
|
54
54
|
from({ "x" => ["y"] }).
|
55
55
|
to({})
|
@@ -59,7 +59,7 @@ describe Statesman::Machine do
|
|
59
59
|
before { machine.transition from: :x, to: :z }
|
60
60
|
|
61
61
|
it "removes all transitions" do
|
62
|
-
expect
|
62
|
+
expect { remove_state }.
|
63
63
|
to change(machine, :successors).
|
64
64
|
from({ "x" => %w[y z] }).
|
65
65
|
to({})
|
@@ -71,7 +71,7 @@ describe Statesman::Machine do
|
|
71
71
|
before { machine.transition from: :y, to: :x }
|
72
72
|
|
73
73
|
it "removes the transition" do
|
74
|
-
expect
|
74
|
+
expect { remove_state }.
|
75
75
|
to change(machine, :successors).
|
76
76
|
from({ "y" => ["x"] }).
|
77
77
|
to({})
|
@@ -81,7 +81,7 @@ describe Statesman::Machine do
|
|
81
81
|
before { machine.transition from: :z, to: :x }
|
82
82
|
|
83
83
|
it "removes all transitions" do
|
84
|
-
expect
|
84
|
+
expect { remove_state }.
|
85
85
|
to change(machine, :successors).
|
86
86
|
from({ "y" => ["x"], "z" => ["x"] }).
|
87
87
|
to({})
|
@@ -104,7 +104,7 @@ describe Statesman::Machine do
|
|
104
104
|
end
|
105
105
|
|
106
106
|
it "removes the guard" do
|
107
|
-
expect
|
107
|
+
expect { remove_state }.
|
108
108
|
to change(machine, :callbacks).
|
109
109
|
from(a_hash_including(guards: match_array(guards))).
|
110
110
|
to(a_hash_including(guards: []))
|
@@ -125,7 +125,7 @@ describe Statesman::Machine do
|
|
125
125
|
end
|
126
126
|
|
127
127
|
it "removes the guard" do
|
128
|
-
expect
|
128
|
+
expect { remove_state }.
|
129
129
|
to change(machine, :callbacks).
|
130
130
|
from(a_hash_including(guards: match_array(guards))).
|
131
131
|
to(a_hash_including(guards: []))
|
@@ -935,10 +935,10 @@ describe Statesman::Machine do
|
|
935
935
|
it { is_expected.to be(:some_state) }
|
936
936
|
end
|
937
937
|
|
938
|
-
context "when it is
|
938
|
+
context "when it is unsuccessful" do
|
939
939
|
before do
|
940
940
|
allow(instance).to receive(:transition_to!).
|
941
|
-
and_raise(Statesman::GuardFailedError.new(:x, :some_state))
|
941
|
+
and_raise(Statesman::GuardFailedError.new(:x, :some_state, nil))
|
942
942
|
end
|
943
943
|
|
944
944
|
it { is_expected.to be_falsey }
|
@@ -64,7 +64,6 @@ class CreateMyActiveRecordModelMigration < MIGRATION_CLASS
|
|
64
64
|
end
|
65
65
|
|
66
66
|
# TODO: make this a module we can extend from the app? Or a generator?
|
67
|
-
# rubocop:disable Metrics/MethodLength
|
68
67
|
class CreateMyActiveRecordModelTransitionMigration < MIGRATION_CLASS
|
69
68
|
def change
|
70
69
|
create_table :my_active_record_model_transitions do |t|
|
@@ -110,7 +109,6 @@ class CreateMyActiveRecordModelTransitionMigration < MIGRATION_CLASS
|
|
110
109
|
end
|
111
110
|
end
|
112
111
|
end
|
113
|
-
# rubocop:enable Metrics/MethodLength
|
114
112
|
|
115
113
|
class OtherActiveRecordModel < ActiveRecord::Base
|
116
114
|
has_many :other_active_record_model_transitions, autosave: false
|
@@ -144,7 +142,6 @@ class CreateOtherActiveRecordModelMigration < MIGRATION_CLASS
|
|
144
142
|
end
|
145
143
|
end
|
146
144
|
|
147
|
-
# rubocop:disable Metrics/MethodLength
|
148
145
|
class CreateOtherActiveRecordModelTransitionMigration < MIGRATION_CLASS
|
149
146
|
def change
|
150
147
|
create_table :other_active_record_model_transitions do |t|
|
@@ -177,18 +174,17 @@ class CreateOtherActiveRecordModelTransitionMigration < MIGRATION_CLASS
|
|
177
174
|
%i[other_active_record_model_id most_recent],
|
178
175
|
unique: true,
|
179
176
|
where: "most_recent",
|
180
|
-
name: "index_other_active_record_model_transitions_"\
|
177
|
+
name: "index_other_active_record_model_transitions_" \
|
181
178
|
"parent_latest"
|
182
179
|
else
|
183
180
|
add_index :other_active_record_model_transitions,
|
184
181
|
%i[other_active_record_model_id most_recent],
|
185
182
|
unique: true,
|
186
|
-
name: "index_other_active_record_model_transitions_"\
|
183
|
+
name: "index_other_active_record_model_transitions_" \
|
187
184
|
"parent_latest"
|
188
185
|
end
|
189
186
|
end
|
190
187
|
end
|
191
|
-
# rubocop:enable Metrics/MethodLength
|
192
188
|
|
193
189
|
class DropMostRecentColumn < MIGRATION_CLASS
|
194
190
|
def change
|
@@ -242,7 +238,6 @@ class CreateNamespacedARModelMigration < MIGRATION_CLASS
|
|
242
238
|
end
|
243
239
|
end
|
244
240
|
|
245
|
-
# rubocop:disable Metrics/MethodLength
|
246
241
|
class CreateNamespacedARModelTransitionMigration < MIGRATION_CLASS
|
247
242
|
def change
|
248
243
|
create_table :my_namespace_my_active_record_model_transitions do |t|
|
@@ -282,5 +277,4 @@ class CreateNamespacedARModelTransitionMigration < MIGRATION_CLASS
|
|
282
277
|
name: "index_namespace_model_transitions_parent_latest"
|
283
278
|
end
|
284
279
|
end
|
285
|
-
# rubocop:enable Metrics/MethodLength
|
286
280
|
end
|
data/statesman.gemspec
CHANGED
@@ -18,24 +18,22 @@ Gem::Specification.new do |spec|
|
|
18
18
|
|
19
19
|
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
20
20
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
21
|
-
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
22
21
|
spec.require_paths = ["lib"]
|
23
22
|
|
24
23
|
spec.required_ruby_version = ">= 2.7"
|
25
24
|
|
26
25
|
spec.add_development_dependency "ammeter", "~> 1.1"
|
27
26
|
spec.add_development_dependency "bundler", "~> 2"
|
28
|
-
spec.add_development_dependency "gc_ruboconfig", "~>
|
27
|
+
spec.add_development_dependency "gc_ruboconfig", "~> 3.6.0"
|
29
28
|
spec.add_development_dependency "mysql2", ">= 0.4", "< 0.6"
|
30
|
-
spec.add_development_dependency "pg", ">= 0.18", "<= 1.
|
31
|
-
spec.add_development_dependency "pry"
|
29
|
+
spec.add_development_dependency "pg", ">= 0.18", "<= 1.5"
|
32
30
|
spec.add_development_dependency "rails", ">= 5.2"
|
33
31
|
spec.add_development_dependency "rake", "~> 13.0.0"
|
34
32
|
spec.add_development_dependency "rspec", "~> 3.1"
|
33
|
+
spec.add_development_dependency "rspec-github", "~> 2.4.0"
|
35
34
|
spec.add_development_dependency "rspec-its", "~> 1.1"
|
36
|
-
spec.add_development_dependency "
|
37
|
-
spec.add_development_dependency "
|
38
|
-
spec.add_development_dependency "sqlite3", "~> 1.4.2"
|
35
|
+
spec.add_development_dependency "rspec-rails", "~> 6.0"
|
36
|
+
spec.add_development_dependency "sqlite3", "~> 1.6.1"
|
39
37
|
spec.add_development_dependency "timecop", "~> 0.9.1"
|
40
38
|
|
41
39
|
spec.metadata = {
|
@@ -44,5 +42,6 @@ Gem::Specification.new do |spec|
|
|
44
42
|
"documentation_uri" => "#{GITHUB_URL}/blob/master/README.md",
|
45
43
|
"homepage_uri" => GITHUB_URL,
|
46
44
|
"source_code_uri" => GITHUB_URL,
|
45
|
+
"rubygems_mfa_required" => "true",
|
47
46
|
}
|
48
47
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: statesman
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 10.
|
4
|
+
version: 10.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GoCardless
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-04-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ammeter
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: 3.6.0
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
54
|
+
version: 3.6.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: mysql2
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -81,7 +81,7 @@ dependencies:
|
|
81
81
|
version: '0.18'
|
82
82
|
- - "<="
|
83
83
|
- !ruby/object:Gem::Version
|
84
|
-
version: '1.
|
84
|
+
version: '1.5'
|
85
85
|
type: :development
|
86
86
|
prerelease: false
|
87
87
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -91,21 +91,7 @@ dependencies:
|
|
91
91
|
version: '0.18'
|
92
92
|
- - "<="
|
93
93
|
- !ruby/object:Gem::Version
|
94
|
-
version: '1.
|
95
|
-
- !ruby/object:Gem::Dependency
|
96
|
-
name: pry
|
97
|
-
requirement: !ruby/object:Gem::Requirement
|
98
|
-
requirements:
|
99
|
-
- - ">="
|
100
|
-
- !ruby/object:Gem::Version
|
101
|
-
version: '0'
|
102
|
-
type: :development
|
103
|
-
prerelease: false
|
104
|
-
version_requirements: !ruby/object:Gem::Requirement
|
105
|
-
requirements:
|
106
|
-
- - ">="
|
107
|
-
- !ruby/object:Gem::Version
|
108
|
-
version: '0'
|
94
|
+
version: '1.5'
|
109
95
|
- !ruby/object:Gem::Dependency
|
110
96
|
name: rails
|
111
97
|
requirement: !ruby/object:Gem::Requirement
|
@@ -149,61 +135,61 @@ dependencies:
|
|
149
135
|
- !ruby/object:Gem::Version
|
150
136
|
version: '3.1'
|
151
137
|
- !ruby/object:Gem::Dependency
|
152
|
-
name: rspec-
|
138
|
+
name: rspec-github
|
153
139
|
requirement: !ruby/object:Gem::Requirement
|
154
140
|
requirements:
|
155
141
|
- - "~>"
|
156
142
|
- !ruby/object:Gem::Version
|
157
|
-
version:
|
143
|
+
version: 2.4.0
|
158
144
|
type: :development
|
159
145
|
prerelease: false
|
160
146
|
version_requirements: !ruby/object:Gem::Requirement
|
161
147
|
requirements:
|
162
148
|
- - "~>"
|
163
149
|
- !ruby/object:Gem::Version
|
164
|
-
version:
|
150
|
+
version: 2.4.0
|
165
151
|
- !ruby/object:Gem::Dependency
|
166
|
-
name:
|
152
|
+
name: rspec-its
|
167
153
|
requirement: !ruby/object:Gem::Requirement
|
168
154
|
requirements:
|
169
155
|
- - "~>"
|
170
156
|
- !ruby/object:Gem::Version
|
171
|
-
version:
|
157
|
+
version: '1.1'
|
172
158
|
type: :development
|
173
159
|
prerelease: false
|
174
160
|
version_requirements: !ruby/object:Gem::Requirement
|
175
161
|
requirements:
|
176
162
|
- - "~>"
|
177
163
|
- !ruby/object:Gem::Version
|
178
|
-
version:
|
164
|
+
version: '1.1'
|
179
165
|
- !ruby/object:Gem::Dependency
|
180
166
|
name: rspec-rails
|
181
167
|
requirement: !ruby/object:Gem::Requirement
|
182
168
|
requirements:
|
183
169
|
- - "~>"
|
184
170
|
- !ruby/object:Gem::Version
|
185
|
-
version: '
|
171
|
+
version: '6.0'
|
186
172
|
type: :development
|
187
173
|
prerelease: false
|
188
174
|
version_requirements: !ruby/object:Gem::Requirement
|
189
175
|
requirements:
|
190
176
|
- - "~>"
|
191
177
|
- !ruby/object:Gem::Version
|
192
|
-
version: '
|
178
|
+
version: '6.0'
|
193
179
|
- !ruby/object:Gem::Dependency
|
194
180
|
name: sqlite3
|
195
181
|
requirement: !ruby/object:Gem::Requirement
|
196
182
|
requirements:
|
197
183
|
- - "~>"
|
198
184
|
- !ruby/object:Gem::Version
|
199
|
-
version: 1.
|
185
|
+
version: 1.6.1
|
200
186
|
type: :development
|
201
187
|
prerelease: false
|
202
188
|
version_requirements: !ruby/object:Gem::Requirement
|
203
189
|
requirements:
|
204
190
|
- - "~>"
|
205
191
|
- !ruby/object:Gem::Version
|
206
|
-
version: 1.
|
192
|
+
version: 1.6.1
|
207
193
|
- !ruby/object:Gem::Dependency
|
208
194
|
name: timecop
|
209
195
|
requirement: !ruby/object:Gem::Requirement
|
@@ -225,8 +211,8 @@ executables: []
|
|
225
211
|
extensions: []
|
226
212
|
extra_rdoc_files: []
|
227
213
|
files:
|
228
|
-
- ".circleci/config.yml"
|
229
214
|
- ".github/dependabot.yml"
|
215
|
+
- ".github/workflows/tests.yml"
|
230
216
|
- ".gitignore"
|
231
217
|
- ".rubocop.yml"
|
232
218
|
- ".rubocop_todo.yml"
|
@@ -251,6 +237,7 @@ files:
|
|
251
237
|
- lib/statesman/adapters/active_record_transition.rb
|
252
238
|
- lib/statesman/adapters/memory.rb
|
253
239
|
- lib/statesman/adapters/memory_transition.rb
|
240
|
+
- lib/statesman/adapters/type_safe_active_record_queries.rb
|
254
241
|
- lib/statesman/callback.rb
|
255
242
|
- lib/statesman/config.rb
|
256
243
|
- lib/statesman/exceptions.rb
|
@@ -272,6 +259,7 @@ files:
|
|
272
259
|
- spec/statesman/adapters/memory_spec.rb
|
273
260
|
- spec/statesman/adapters/memory_transition_spec.rb
|
274
261
|
- spec/statesman/adapters/shared_examples.rb
|
262
|
+
- spec/statesman/adapters/type_safe_active_record_queries_spec.rb
|
275
263
|
- spec/statesman/callback_spec.rb
|
276
264
|
- spec/statesman/config_spec.rb
|
277
265
|
- spec/statesman/exceptions_spec.rb
|
@@ -290,6 +278,7 @@ metadata:
|
|
290
278
|
documentation_uri: https://github.com/gocardless/statesman/blob/master/README.md
|
291
279
|
homepage_uri: https://github.com/gocardless/statesman
|
292
280
|
source_code_uri: https://github.com/gocardless/statesman
|
281
|
+
rubygems_mfa_required: 'true'
|
293
282
|
post_install_message:
|
294
283
|
rdoc_options: []
|
295
284
|
require_paths:
|
@@ -305,28 +294,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
305
294
|
- !ruby/object:Gem::Version
|
306
295
|
version: '0'
|
307
296
|
requirements: []
|
308
|
-
rubygems_version: 3.
|
297
|
+
rubygems_version: 3.4.1
|
309
298
|
signing_key:
|
310
299
|
specification_version: 4
|
311
300
|
summary: A statesman-like state machine library
|
312
|
-
test_files:
|
313
|
-
- spec/fixtures/add_constraints_to_most_recent_for_bacon_transitions_with_partial_index.rb
|
314
|
-
- spec/fixtures/add_constraints_to_most_recent_for_bacon_transitions_without_partial_index.rb
|
315
|
-
- spec/fixtures/add_most_recent_to_bacon_transitions.rb
|
316
|
-
- spec/generators/statesman/active_record_transition_generator_spec.rb
|
317
|
-
- spec/generators/statesman/migration_generator_spec.rb
|
318
|
-
- spec/spec_helper.rb
|
319
|
-
- spec/statesman/adapters/active_record_queries_spec.rb
|
320
|
-
- spec/statesman/adapters/active_record_spec.rb
|
321
|
-
- spec/statesman/adapters/active_record_transition_spec.rb
|
322
|
-
- spec/statesman/adapters/memory_spec.rb
|
323
|
-
- spec/statesman/adapters/memory_transition_spec.rb
|
324
|
-
- spec/statesman/adapters/shared_examples.rb
|
325
|
-
- spec/statesman/callback_spec.rb
|
326
|
-
- spec/statesman/config_spec.rb
|
327
|
-
- spec/statesman/exceptions_spec.rb
|
328
|
-
- spec/statesman/guard_spec.rb
|
329
|
-
- spec/statesman/machine_spec.rb
|
330
|
-
- spec/statesman/utils_spec.rb
|
331
|
-
- spec/support/active_record.rb
|
332
|
-
- spec/support/generators_shared_examples.rb
|
301
|
+
test_files: []
|
data/.circleci/config.yml
DELETED
@@ -1,127 +0,0 @@
|
|
1
|
-
---
|
2
|
-
version: 2.1
|
3
|
-
|
4
|
-
references:
|
5
|
-
bundle_install: &bundle_install
|
6
|
-
run:
|
7
|
-
name: Bundle
|
8
|
-
command: |
|
9
|
-
gem install bundler --no-document && \
|
10
|
-
bundle config set no-cache 'true' && \
|
11
|
-
bundle config set jobs '4' && \
|
12
|
-
bundle config set retry '3' && \
|
13
|
-
bundle install
|
14
|
-
|
15
|
-
cache_bundle: &cache_bundle
|
16
|
-
save_cache:
|
17
|
-
key: bundle-<< parameters.ruby_version >>-<< parameters.rails_version >>-{{ checksum "statesman.gemspec" }}-{{ checksum "Gemfile" }}
|
18
|
-
paths:
|
19
|
-
- vendor/bundle
|
20
|
-
|
21
|
-
restore_bundle: &restore_bundle
|
22
|
-
restore_cache:
|
23
|
-
key: bundle-<< parameters.ruby_version >>-<< parameters.rails_version >>-{{ checksum "statesman.gemspec" }}-{{ checksum "Gemfile" }}
|
24
|
-
|
25
|
-
steps: &steps
|
26
|
-
- add_ssh_keys
|
27
|
-
- checkout
|
28
|
-
- run:
|
29
|
-
name: "Add dependencies"
|
30
|
-
command: |
|
31
|
-
sudo apt-get update && sudo apt-get install -y sqlite3 libsqlite3-dev
|
32
|
-
- *restore_bundle
|
33
|
-
- *bundle_install
|
34
|
-
- *cache_bundle
|
35
|
-
- run: dockerize -wait tcp://localhost:$DATABASE_DEPENDENCY_PORT -timeout 1m
|
36
|
-
- run:
|
37
|
-
name: Run specs
|
38
|
-
command: |
|
39
|
-
bundle exec rspec $(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings) --profile --format progress --format RspecJunitFormatter -o /tmp/circle_artifacts/rspec.xml
|
40
|
-
- run:
|
41
|
-
name: "Rubocop"
|
42
|
-
command: bundle exec rubocop --extra-details --display-style-guide --parallel --force-exclusion
|
43
|
-
- store_artifacts:
|
44
|
-
path: /tmp/circle_artifacts/
|
45
|
-
- store_test_results:
|
46
|
-
path: /tmp/circle_artifacts/
|
47
|
-
|
48
|
-
ruby_versions: &ruby_versions
|
49
|
-
- "2.7"
|
50
|
-
- "3.0"
|
51
|
-
- "3.1"
|
52
|
-
|
53
|
-
rails_versions: &rails_versions
|
54
|
-
- "5.2.7"
|
55
|
-
- "6.0.4"
|
56
|
-
- "6.1.5"
|
57
|
-
- "7.0.2"
|
58
|
-
- "main"
|
59
|
-
|
60
|
-
mysql_versions: &mysql_versions
|
61
|
-
- "5.7"
|
62
|
-
|
63
|
-
psql_versions: &psql_versions
|
64
|
-
- "9.6"
|
65
|
-
|
66
|
-
jobs:
|
67
|
-
rspec_mysql:
|
68
|
-
working_directory: /mnt/ramdisk
|
69
|
-
parameters:
|
70
|
-
ruby_version:
|
71
|
-
type: string
|
72
|
-
rails_version:
|
73
|
-
type: string
|
74
|
-
mysql_version:
|
75
|
-
type: string
|
76
|
-
docker:
|
77
|
-
- image: cimg/ruby:<< parameters.ruby_version >>
|
78
|
-
environment:
|
79
|
-
CIRCLE_TEST_REPORTS: /tmp/circle_artifacts/
|
80
|
-
DATABASE_URL: mysql2://foobar:password@127.0.0.1/statesman_test
|
81
|
-
DATABASE_DEPENDENCY_PORT: "3306"
|
82
|
-
- image: cimg/mysql:<< parameters.mysql_version >>
|
83
|
-
environment:
|
84
|
-
MYSQL_ROOT_PASSWORD: password
|
85
|
-
MYSQL_USER: foobar
|
86
|
-
MYSQL_PASSWORD: password
|
87
|
-
MYSQL_DATABASE: statesman_test
|
88
|
-
steps: *steps
|
89
|
-
|
90
|
-
rspec_postgres:
|
91
|
-
working_directory: /mnt/ramdisk
|
92
|
-
parameters:
|
93
|
-
ruby_version:
|
94
|
-
type: string
|
95
|
-
rails_version:
|
96
|
-
type: string
|
97
|
-
psql_version:
|
98
|
-
type: string
|
99
|
-
docker:
|
100
|
-
- image: cimg/ruby:<< parameters.ruby_version >>
|
101
|
-
environment:
|
102
|
-
CIRCLE_TEST_REPORTS: /tmp/circle_artifacts/
|
103
|
-
DATABASE_URL: postgres://postgres@localhost/statesman_test
|
104
|
-
DATABASE_DEPENDENCY_PORT: "5432"
|
105
|
-
- image: circleci/postgres:<< parameters.psql_version >>
|
106
|
-
environment:
|
107
|
-
POSTGRES_USER: postgres
|
108
|
-
POSTGRES_DB: statesman_test
|
109
|
-
POSTGRES_PASSWORD: statesman
|
110
|
-
steps: *steps
|
111
|
-
|
112
|
-
workflows:
|
113
|
-
version: 2
|
114
|
-
tests:
|
115
|
-
jobs:
|
116
|
-
- rspec_mysql:
|
117
|
-
matrix:
|
118
|
-
parameters:
|
119
|
-
mysql_version: *mysql_versions
|
120
|
-
ruby_version: *ruby_versions
|
121
|
-
rails_version: *rails_versions
|
122
|
-
- rspec_postgres:
|
123
|
-
matrix:
|
124
|
-
parameters:
|
125
|
-
psql_version: *psql_versions
|
126
|
-
ruby_version: *ruby_versions
|
127
|
-
rails_version: *rails_versions
|