statesman 9.0.1 → 10.1.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/.gitignore +68 -15
- data/.rubocop.yml +9 -0
- data/CHANGELOG.md +12 -0
- data/README.md +47 -1
- data/lib/generators/statesman/active_record_transition_generator.rb +1 -1
- data/lib/statesman/adapters/active_record.rb +1 -3
- data/lib/statesman/adapters/active_record_queries.rb +5 -5
- data/lib/statesman/adapters/memory.rb +1 -1
- data/lib/statesman/exceptions.rb +9 -7
- data/lib/statesman/guard.rb +1 -1
- data/lib/statesman/machine.rb +52 -0
- data/lib/statesman/version.rb +1 -1
- data/lib/tasks/statesman.rake +3 -3
- data/spec/statesman/adapters/active_record_queries_spec.rb +4 -4
- data/spec/statesman/exceptions_spec.rb +7 -1
- data/spec/statesman/machine_spec.rb +144 -2
- data/spec/support/active_record.rb +2 -8
- data/statesman.gemspec +5 -5
- metadata +16 -35
- 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: e3ff12f10c3b26c96652704af9008eb0154a0d1686ed5c6d8ddcdb18a04dbadc
|
|
4
|
+
data.tar.gz: 1a5a5744e82f569de82a75f8eb87a251e0ddd5fe22f835ca5de4b2d21fa87ecf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6762062d6fe240f1acc32e742f5b333dd80e2fb20a5e6419200b7b78b0a29d3d37df843ee445afb317ac4db1c142249a233ed4217adeeb6e4242538d9e1fa096
|
|
7
|
+
data.tar.gz: 6df883f757f7de70a31cfa1758de70f1b44b753b95b23942317f7c4638f107a88d4c7bedc654fbf286611125755fa96e908b7c4158d7b28fac7094c09ec65b18
|
|
@@ -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/.gitignore
CHANGED
|
@@ -1,18 +1,71 @@
|
|
|
1
1
|
*.gem
|
|
2
2
|
*.rbc
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
/.config
|
|
4
|
+
/coverage/
|
|
5
|
+
/InstalledFiles
|
|
6
|
+
/pkg/
|
|
7
|
+
/spec/reports/
|
|
8
|
+
/spec/examples.txt
|
|
9
|
+
/test/tmp/
|
|
10
|
+
/test/version_tmp/
|
|
11
|
+
/tmp/
|
|
12
|
+
|
|
13
|
+
# Used by dotenv library to load environment variables.
|
|
14
|
+
# .env
|
|
15
|
+
|
|
16
|
+
# Ignore Byebug command history file.
|
|
17
|
+
.byebug_history
|
|
18
|
+
|
|
19
|
+
## Specific to RubyMotion:
|
|
20
|
+
.dat*
|
|
21
|
+
.repl_history
|
|
22
|
+
build/
|
|
23
|
+
*.bridgesupport
|
|
24
|
+
build-iPhoneOS/
|
|
25
|
+
build-iPhoneSimulator/
|
|
26
|
+
|
|
27
|
+
## Specific to RubyMotion (use of CocoaPods):
|
|
28
|
+
#
|
|
29
|
+
# We recommend against adding the Pods directory to your .gitignore. However
|
|
30
|
+
# you should judge for yourself, the pros and cons are mentioned at:
|
|
31
|
+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
|
32
|
+
#
|
|
33
|
+
# vendor/Pods/
|
|
34
|
+
|
|
35
|
+
## Documentation cache and generated files:
|
|
36
|
+
/.yardoc/
|
|
37
|
+
/_yardoc/
|
|
38
|
+
/doc/
|
|
39
|
+
/rdoc/
|
|
40
|
+
|
|
41
|
+
## Environment normalization:
|
|
42
|
+
/.bundle/
|
|
43
|
+
/vendor/bundle
|
|
44
|
+
/lib/bundler/man/
|
|
45
|
+
|
|
46
|
+
# for a library or gem, you might want to ignore these files since the code is
|
|
47
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
7
48
|
Gemfile.lock
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
49
|
+
# .ruby-version
|
|
50
|
+
# .ruby-gemset
|
|
51
|
+
|
|
52
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
|
53
|
+
.rvmrc
|
|
54
|
+
|
|
55
|
+
# Used by RuboCop. Remote config files pulled in from inherit_from directive.
|
|
56
|
+
# .rubocop-https?--*
|
|
57
|
+
|
|
58
|
+
# Project-specific ignores
|
|
59
|
+
.rspec
|
|
60
|
+
|
|
61
|
+
# VSCode
|
|
62
|
+
.vscode
|
|
63
|
+
|
|
64
|
+
# Local History for Visual Studio Code
|
|
65
|
+
.history/
|
|
66
|
+
|
|
67
|
+
# Built Visual Studio Code Extensions
|
|
68
|
+
*.vsix
|
|
69
|
+
|
|
70
|
+
# JetBrains
|
|
71
|
+
.idea
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## v10.1.0 10th March 2023
|
|
2
|
+
|
|
3
|
+
### CHanged
|
|
4
|
+
- Add the source location of the guard callback to `Statesman::GuardFailedError`
|
|
5
|
+
|
|
6
|
+
## v10.0.0 17th May 2022
|
|
7
|
+
|
|
8
|
+
### Changed
|
|
9
|
+
- Added support for Ruby 3.1 [#462](https://github.com/gocardless/statesman/pull/462)
|
|
10
|
+
- Removed support for Ruby 2.5 and 2.6 [#462](https://github.com/gocardless/statesman/pull/462)
|
|
11
|
+
- Added `remove_state` and `remove_transitions` methods to `Statesman::Machine` [#464](https://github.com/gocardless/statesman/pull/464)
|
|
12
|
+
|
|
1
13
|
## v9.0.1 4th February 2021
|
|
2
14
|
|
|
3
15
|
### Changed
|
data/README.md
CHANGED
|
@@ -30,7 +30,7 @@ protection.
|
|
|
30
30
|
To get started, just add Statesman to your `Gemfile`, and then run `bundle`:
|
|
31
31
|
|
|
32
32
|
```ruby
|
|
33
|
-
gem 'statesman', '~>
|
|
33
|
+
gem 'statesman', '~> 10.0.0'
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
## Usage
|
|
@@ -116,6 +116,52 @@ Order.in_state(:cancelled) # => [#<Order id: "123">]
|
|
|
116
116
|
Order.not_in_state(:checking_out) # => [#<Order id: "123">]
|
|
117
117
|
```
|
|
118
118
|
|
|
119
|
+
If you'd like, you can also define a template for a generic state machine, then alter classes which extend it as required:
|
|
120
|
+
|
|
121
|
+
```ruby
|
|
122
|
+
module Template
|
|
123
|
+
def define_states
|
|
124
|
+
state :a, initial: true
|
|
125
|
+
state :b
|
|
126
|
+
state :c
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def define_transitions
|
|
130
|
+
transition from: :a, to: :b
|
|
131
|
+
transition from: :b, to: :c
|
|
132
|
+
transition from: :c, to: :a
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
class Circular
|
|
137
|
+
include Statesman::Machine
|
|
138
|
+
extend Template
|
|
139
|
+
|
|
140
|
+
define_states
|
|
141
|
+
define_transitions
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
class Linear
|
|
145
|
+
include Statesman::Machine
|
|
146
|
+
extend Template
|
|
147
|
+
|
|
148
|
+
define_states
|
|
149
|
+
define_transitions
|
|
150
|
+
|
|
151
|
+
remove_transitions from: :c, to: :a
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
class Shorter
|
|
155
|
+
include Statesman::Machine
|
|
156
|
+
extend Template
|
|
157
|
+
|
|
158
|
+
define_states
|
|
159
|
+
define_transitions
|
|
160
|
+
|
|
161
|
+
remove_state :c
|
|
162
|
+
end
|
|
163
|
+
```
|
|
164
|
+
|
|
119
165
|
## Persistence
|
|
120
166
|
|
|
121
167
|
By default Statesman stores transition history in memory only. It can be
|
|
@@ -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"
|
|
@@ -81,7 +81,6 @@ module Statesman
|
|
|
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
|
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/machine.rb
CHANGED
|
@@ -42,6 +42,17 @@ module Statesman
|
|
|
42
42
|
states << name
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
+
def remove_state(state_name)
|
|
46
|
+
state_name = state_name.to_s
|
|
47
|
+
|
|
48
|
+
remove_transitions(from: state_name)
|
|
49
|
+
remove_transitions(to: state_name)
|
|
50
|
+
remove_callbacks(from: state_name)
|
|
51
|
+
remove_callbacks(to: state_name)
|
|
52
|
+
|
|
53
|
+
@states.delete(state_name.to_s)
|
|
54
|
+
end
|
|
55
|
+
|
|
45
56
|
def successors
|
|
46
57
|
@successors ||= {}
|
|
47
58
|
end
|
|
@@ -70,6 +81,20 @@ module Statesman
|
|
|
70
81
|
successors[from] += to
|
|
71
82
|
end
|
|
72
83
|
|
|
84
|
+
def remove_transitions(from: nil, to: nil)
|
|
85
|
+
raise ArgumentError, "Both from and to can't be nil!" if from.nil? && to.nil?
|
|
86
|
+
return if successors.nil?
|
|
87
|
+
|
|
88
|
+
if from.present?
|
|
89
|
+
@successors[from.to_s].delete(to.to_s) if to.present?
|
|
90
|
+
@successors.delete(from.to_s) if to.nil? || successors[from.to_s].empty?
|
|
91
|
+
elsif to.present?
|
|
92
|
+
@successors.
|
|
93
|
+
transform_values! { |to_states| to_states - [to.to_s] }.
|
|
94
|
+
filter! { |_from_state, to_states| to_states.any? }
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
73
98
|
def before_transition(options = {}, &block)
|
|
74
99
|
add_callback(callback_type: :before, callback_class: Callback,
|
|
75
100
|
from: options[:from], to: options[:to], &block)
|
|
@@ -151,6 +176,33 @@ module Statesman
|
|
|
151
176
|
callback_class.new(from: from, to: to, callback: block)
|
|
152
177
|
end
|
|
153
178
|
|
|
179
|
+
def remove_callbacks(from: nil, to: nil)
|
|
180
|
+
raise ArgumentError, "Both from and to can't be nil!" if from.nil? && to.nil?
|
|
181
|
+
return if callbacks.nil?
|
|
182
|
+
|
|
183
|
+
@callbacks.transform_values! do |callbacks|
|
|
184
|
+
filter_callbacks(callbacks, from: from, to: to)
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def filter_callbacks(callbacks, from: nil, to: nil)
|
|
189
|
+
callbacks.filter_map do |callback|
|
|
190
|
+
next if callback.from == from && to.nil?
|
|
191
|
+
|
|
192
|
+
if callback.to.include?(to) && (from.nil? || callback.from == from)
|
|
193
|
+
next if callback.to == [to]
|
|
194
|
+
|
|
195
|
+
callback = Statesman::Callback.new({
|
|
196
|
+
from: callback.from,
|
|
197
|
+
to: callback.to - [to],
|
|
198
|
+
callback: callback.callback,
|
|
199
|
+
})
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
callback
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
154
206
|
def validate_callback_type_and_class(callback_type, callback_class)
|
|
155
207
|
raise ArgumentError, "missing keyword: callback_type" if callback_type.nil?
|
|
156
208
|
raise ArgumentError, "missing keyword: callback_class" if callback_class.nil?
|
data/lib/statesman/version.rb
CHANGED
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
|
|
@@ -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
|
|
@@ -27,6 +27,112 @@ describe Statesman::Machine do
|
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
describe ".remove_state" do
|
|
31
|
+
subject(:remove_state) { -> { machine.remove_state(:x) } }
|
|
32
|
+
|
|
33
|
+
before do
|
|
34
|
+
machine.class_eval do
|
|
35
|
+
state :x
|
|
36
|
+
state :y
|
|
37
|
+
state :z
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "removes the state" do
|
|
42
|
+
expect(remove_state).
|
|
43
|
+
to change(machine, :states).
|
|
44
|
+
from(match_array(%w[x y z])).
|
|
45
|
+
to(%w[y z])
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
context "with a transition from the removed state" do
|
|
49
|
+
before { machine.transition from: :x, to: :y }
|
|
50
|
+
|
|
51
|
+
it "removes the transition" do
|
|
52
|
+
expect(remove_state).
|
|
53
|
+
to change(machine, :successors).
|
|
54
|
+
from({ "x" => ["y"] }).
|
|
55
|
+
to({})
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
context "with multiple transitions" do
|
|
59
|
+
before { machine.transition from: :x, to: :z }
|
|
60
|
+
|
|
61
|
+
it "removes all transitions" do
|
|
62
|
+
expect(remove_state).
|
|
63
|
+
to change(machine, :successors).
|
|
64
|
+
from({ "x" => %w[y z] }).
|
|
65
|
+
to({})
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
context "with a transition to the removed state" do
|
|
71
|
+
before { machine.transition from: :y, to: :x }
|
|
72
|
+
|
|
73
|
+
it "removes the transition" do
|
|
74
|
+
expect(remove_state).
|
|
75
|
+
to change(machine, :successors).
|
|
76
|
+
from({ "y" => ["x"] }).
|
|
77
|
+
to({})
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
context "with multiple transitions" do
|
|
81
|
+
before { machine.transition from: :z, to: :x }
|
|
82
|
+
|
|
83
|
+
it "removes all transitions" do
|
|
84
|
+
expect(remove_state).
|
|
85
|
+
to change(machine, :successors).
|
|
86
|
+
from({ "y" => ["x"], "z" => ["x"] }).
|
|
87
|
+
to({})
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
context "with a callback from the removed state" do
|
|
93
|
+
before do
|
|
94
|
+
machine.class_eval do
|
|
95
|
+
transition from: :x, to: :y
|
|
96
|
+
transition from: :x, to: :z
|
|
97
|
+
guard_transition(from: :x) { return false }
|
|
98
|
+
guard_transition(from: :x, to: :z) { return true }
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
let(:guards) do
|
|
103
|
+
[having_attributes(from: "x", to: []), having_attributes(from: "x", to: ["z"])]
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it "removes the guard" do
|
|
107
|
+
expect(remove_state).
|
|
108
|
+
to change(machine, :callbacks).
|
|
109
|
+
from(a_hash_including(guards: match_array(guards))).
|
|
110
|
+
to(a_hash_including(guards: []))
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
context "with a callback to the removed state" do
|
|
115
|
+
before do
|
|
116
|
+
machine.class_eval do
|
|
117
|
+
transition from: :y, to: :x
|
|
118
|
+
guard_transition(to: :x) { return false }
|
|
119
|
+
guard_transition(from: :y, to: :x) { return true }
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
let(:guards) do
|
|
124
|
+
[having_attributes(from: nil, to: ["x"]), having_attributes(from: "y", to: ["x"])]
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
it "removes the guard" do
|
|
128
|
+
expect(remove_state).
|
|
129
|
+
to change(machine, :callbacks).
|
|
130
|
+
from(a_hash_including(guards: match_array(guards))).
|
|
131
|
+
to(a_hash_including(guards: []))
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
30
136
|
describe ".retry_conflicts" do
|
|
31
137
|
subject(:transition_state) do
|
|
32
138
|
described_class.retry_conflicts(retry_attempts) do
|
|
@@ -170,6 +276,42 @@ describe Statesman::Machine do
|
|
|
170
276
|
end
|
|
171
277
|
end
|
|
172
278
|
|
|
279
|
+
describe ".remove_transitions" do
|
|
280
|
+
before do
|
|
281
|
+
machine.class_eval do
|
|
282
|
+
state :x
|
|
283
|
+
state :y
|
|
284
|
+
state :z
|
|
285
|
+
transition from: :x, to: :y
|
|
286
|
+
transition from: :x, to: :z
|
|
287
|
+
transition from: :y, to: :z
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
let(:initial_successors) { { "x" => %w[y z], "y" => ["z"] } }
|
|
292
|
+
|
|
293
|
+
it "removes the correct transitions when given a from state" do
|
|
294
|
+
expect { machine.remove_transitions(from: :x) }.
|
|
295
|
+
to change(machine, :successors).
|
|
296
|
+
from(initial_successors).
|
|
297
|
+
to({ "y" => ["z"] })
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
it "removes the correct transitions when given a to state" do
|
|
301
|
+
expect { machine.remove_transitions(to: :z) }.
|
|
302
|
+
to change(machine, :successors).
|
|
303
|
+
from(initial_successors).
|
|
304
|
+
to({ "x" => ["y"] })
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
it "removes the correct transitions when given a from and to state" do
|
|
308
|
+
expect { machine.remove_transitions(from: :x, to: :z) }.
|
|
309
|
+
to change(machine, :successors).
|
|
310
|
+
from(initial_successors).
|
|
311
|
+
to({ "x" => ["y"], "y" => ["z"] })
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
|
|
173
315
|
describe ".validate_callback_condition" do
|
|
174
316
|
before do
|
|
175
317
|
machine.class_eval do
|
|
@@ -793,10 +935,10 @@ describe Statesman::Machine do
|
|
|
793
935
|
it { is_expected.to be(:some_state) }
|
|
794
936
|
end
|
|
795
937
|
|
|
796
|
-
context "when it is
|
|
938
|
+
context "when it is unsuccessful" do
|
|
797
939
|
before do
|
|
798
940
|
allow(instance).to receive(:transition_to!).
|
|
799
|
-
and_raise(Statesman::GuardFailedError.new(:x, :some_state))
|
|
941
|
+
and_raise(Statesman::GuardFailedError.new(:x, :some_state, nil))
|
|
800
942
|
end
|
|
801
943
|
|
|
802
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,23 @@ 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
|
-
spec.required_ruby_version = ">= 2.
|
|
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
29
|
spec.add_development_dependency "pg", ">= 0.18", "<= 1.3"
|
|
31
30
|
spec.add_development_dependency "pry"
|
|
32
31
|
spec.add_development_dependency "rails", ">= 5.2"
|
|
33
32
|
spec.add_development_dependency "rake", "~> 13.0.0"
|
|
34
33
|
spec.add_development_dependency "rspec", "~> 3.1"
|
|
34
|
+
spec.add_development_dependency "rspec-github", "~> 2.3.1"
|
|
35
35
|
spec.add_development_dependency "rspec-its", "~> 1.1"
|
|
36
|
-
spec.add_development_dependency "rspec_junit_formatter", "~> 0.4.0"
|
|
37
36
|
spec.add_development_dependency "rspec-rails", "~> 3.1"
|
|
38
|
-
spec.add_development_dependency "sqlite3", "~> 1.
|
|
37
|
+
spec.add_development_dependency "sqlite3", "~> 1.6.1"
|
|
39
38
|
spec.add_development_dependency "timecop", "~> 0.9.1"
|
|
40
39
|
|
|
41
40
|
spec.metadata = {
|
|
@@ -44,5 +43,6 @@ Gem::Specification.new do |spec|
|
|
|
44
43
|
"documentation_uri" => "#{GITHUB_URL}/blob/master/README.md",
|
|
45
44
|
"homepage_uri" => GITHUB_URL,
|
|
46
45
|
"source_code_uri" => GITHUB_URL,
|
|
46
|
+
"rubygems_mfa_required" => "true",
|
|
47
47
|
}
|
|
48
48
|
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:
|
|
4
|
+
version: 10.1.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-03-10 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
|
|
@@ -149,33 +149,33 @@ dependencies:
|
|
|
149
149
|
- !ruby/object:Gem::Version
|
|
150
150
|
version: '3.1'
|
|
151
151
|
- !ruby/object:Gem::Dependency
|
|
152
|
-
name: rspec-
|
|
152
|
+
name: rspec-github
|
|
153
153
|
requirement: !ruby/object:Gem::Requirement
|
|
154
154
|
requirements:
|
|
155
155
|
- - "~>"
|
|
156
156
|
- !ruby/object:Gem::Version
|
|
157
|
-
version:
|
|
157
|
+
version: 2.3.1
|
|
158
158
|
type: :development
|
|
159
159
|
prerelease: false
|
|
160
160
|
version_requirements: !ruby/object:Gem::Requirement
|
|
161
161
|
requirements:
|
|
162
162
|
- - "~>"
|
|
163
163
|
- !ruby/object:Gem::Version
|
|
164
|
-
version:
|
|
164
|
+
version: 2.3.1
|
|
165
165
|
- !ruby/object:Gem::Dependency
|
|
166
|
-
name:
|
|
166
|
+
name: rspec-its
|
|
167
167
|
requirement: !ruby/object:Gem::Requirement
|
|
168
168
|
requirements:
|
|
169
169
|
- - "~>"
|
|
170
170
|
- !ruby/object:Gem::Version
|
|
171
|
-
version:
|
|
171
|
+
version: '1.1'
|
|
172
172
|
type: :development
|
|
173
173
|
prerelease: false
|
|
174
174
|
version_requirements: !ruby/object:Gem::Requirement
|
|
175
175
|
requirements:
|
|
176
176
|
- - "~>"
|
|
177
177
|
- !ruby/object:Gem::Version
|
|
178
|
-
version:
|
|
178
|
+
version: '1.1'
|
|
179
179
|
- !ruby/object:Gem::Dependency
|
|
180
180
|
name: rspec-rails
|
|
181
181
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -196,14 +196,14 @@ dependencies:
|
|
|
196
196
|
requirements:
|
|
197
197
|
- - "~>"
|
|
198
198
|
- !ruby/object:Gem::Version
|
|
199
|
-
version: 1.
|
|
199
|
+
version: 1.6.1
|
|
200
200
|
type: :development
|
|
201
201
|
prerelease: false
|
|
202
202
|
version_requirements: !ruby/object:Gem::Requirement
|
|
203
203
|
requirements:
|
|
204
204
|
- - "~>"
|
|
205
205
|
- !ruby/object:Gem::Version
|
|
206
|
-
version: 1.
|
|
206
|
+
version: 1.6.1
|
|
207
207
|
- !ruby/object:Gem::Dependency
|
|
208
208
|
name: timecop
|
|
209
209
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -225,8 +225,8 @@ executables: []
|
|
|
225
225
|
extensions: []
|
|
226
226
|
extra_rdoc_files: []
|
|
227
227
|
files:
|
|
228
|
-
- ".circleci/config.yml"
|
|
229
228
|
- ".github/dependabot.yml"
|
|
229
|
+
- ".github/workflows/tests.yml"
|
|
230
230
|
- ".gitignore"
|
|
231
231
|
- ".rubocop.yml"
|
|
232
232
|
- ".rubocop_todo.yml"
|
|
@@ -290,6 +290,7 @@ metadata:
|
|
|
290
290
|
documentation_uri: https://github.com/gocardless/statesman/blob/master/README.md
|
|
291
291
|
homepage_uri: https://github.com/gocardless/statesman
|
|
292
292
|
source_code_uri: https://github.com/gocardless/statesman
|
|
293
|
+
rubygems_mfa_required: 'true'
|
|
293
294
|
post_install_message:
|
|
294
295
|
rdoc_options: []
|
|
295
296
|
require_paths:
|
|
@@ -298,7 +299,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
298
299
|
requirements:
|
|
299
300
|
- - ">="
|
|
300
301
|
- !ruby/object:Gem::Version
|
|
301
|
-
version: '2.
|
|
302
|
+
version: '2.7'
|
|
302
303
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
303
304
|
requirements:
|
|
304
305
|
- - ">="
|
|
@@ -309,24 +310,4 @@ rubygems_version: 3.2.22
|
|
|
309
310
|
signing_key:
|
|
310
311
|
specification_version: 4
|
|
311
312
|
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
|
|
313
|
+
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.5"
|
|
50
|
-
- "2.6"
|
|
51
|
-
- "2.7"
|
|
52
|
-
- "3.0"
|
|
53
|
-
|
|
54
|
-
rails_versions: &rails_versions
|
|
55
|
-
- "5.2.6"
|
|
56
|
-
- "6.0.4"
|
|
57
|
-
- "6.1.4"
|
|
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
|