light-service 0.15.0 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/project-build.yml +28 -0
- data/.travis.yml +3 -8
- data/README.md +20 -12
- data/RELEASES.md +6 -1
- data/lib/light-service/action.rb +3 -0
- data/lib/light-service/context.rb +2 -2
- data/lib/light-service/context/key_verifier.rb +18 -1
- data/lib/light-service/organizer.rb +12 -3
- data/lib/light-service/version.rb +1 -1
- data/light-service.gemspec +2 -1
- data/spec/acceptance/after_actions_spec.rb +17 -0
- data/spec/acceptance/organizer/add_to_context_spec.rb +27 -0
- data/spec/acceptance/organizer/execute_with_add_to_context_spec.rb +28 -0
- metadata +11 -10
- data/gemfiles/activesupport_4.gemfile +0 -7
- data/resources/orchestrators_deprecated.svg +0 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d41ecb22a4b0d3cd9779c1e5726c8f34e6f186a34f04ec97ea5928f682f08fd8
|
4
|
+
data.tar.gz: 64f4d7f52607048313e9f39bea158899ef804deb32ae9744715e5969cc7b1567
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2345b72e3d9581aecaea2fe5eca1bd3c538cdb0cfcd2d943ac021ca4f3ef31913ac4b06011944c017df330f3ee8dc385793e8185f3e79cba6c51fbe6ee6acba6
|
7
|
+
data.tar.gz: 703b9608edfa42bf0d73135fa5b4eafa789e8a31c4239056fd8b7397d6f0a212f8c5c69d66834f1f5b9fe2431b234f8c0373ccaaa86f286d82671bfe8d8b705b
|
@@ -0,0 +1,28 @@
|
|
1
|
+
name: CI Tests
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ main ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ main ]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
test:
|
11
|
+
runs-on: ${{ matrix.os }}-latest
|
12
|
+
strategy:
|
13
|
+
fail-fast: false
|
14
|
+
matrix:
|
15
|
+
os: [ubuntu, macos]
|
16
|
+
ruby: [2.5.3, 2.6.6, 2.7.2]
|
17
|
+
gemfile: [activesupport_5, activesupport_6]
|
18
|
+
continue-on-error: ${{ endsWith(matrix.ruby, 'head') || matrix.ruby == 'debug' }}
|
19
|
+
env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps
|
20
|
+
BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}.gemfile
|
21
|
+
steps:
|
22
|
+
- uses: actions/checkout@v2
|
23
|
+
- uses: ruby/setup-ruby@v1
|
24
|
+
with:
|
25
|
+
ruby-version: ${{ matrix.ruby }}
|
26
|
+
- run: bundle install
|
27
|
+
- run: bundle exec rspec spec
|
28
|
+
- run: bundle exec rubocop
|
data/.travis.yml
CHANGED
@@ -4,10 +4,9 @@ env:
|
|
4
4
|
- RUN_COVERAGE_REPORT=true
|
5
5
|
|
6
6
|
rvm:
|
7
|
-
- 2.4.2
|
8
7
|
- 2.5.3
|
9
|
-
- 2.6.
|
10
|
-
- 2.7.
|
8
|
+
- 2.6.6
|
9
|
+
- 2.7.2
|
11
10
|
|
12
11
|
before_install:
|
13
12
|
- 'echo ''gem: --no-ri --no-rdoc'' > ~/.gemrc'
|
@@ -26,9 +25,5 @@ gemfile:
|
|
26
25
|
|
27
26
|
matrix:
|
28
27
|
exclude:
|
29
|
-
- rvm: 2.
|
30
|
-
gemfile: gemfiles/activesupport_6.gemfile
|
31
|
-
- rvm: 2.7.0
|
32
|
-
gemfile: gemfiles/activesupport_3.gemfile
|
33
|
-
- rvm: 2.7.0
|
28
|
+
- rvm: 2.7.2
|
34
29
|
gemfile: gemfiles/activesupport_4.gemfile
|
data/README.md
CHANGED
@@ -1,20 +1,15 @@
|
|
1
1
|
![LightService](https://raw.githubusercontent.com/adomokos/light-service/master/resources/light-service.png)
|
2
2
|
|
3
3
|
[![Gem Version](https://img.shields.io/gem/v/light-service.svg)](https://rubygems.org/gems/light-service)
|
4
|
-
[![
|
4
|
+
[![CI Tests](https://github.com/adomokos/light-service/actions/workflows/project-build.yml/badge.svg)](https://github.com/adomokos/light-service/actions/workflows/project-build.yml)
|
5
5
|
[![codecov](https://codecov.io/gh/adomokos/light-service/branch/master/graph/badge.svg)](https://codecov.io/gh/adomokos/light-service)
|
6
6
|
[![Code Climate](https://codeclimate.com/github/adomokos/light-service.svg)](https://codeclimate.com/github/adomokos/light-service)
|
7
7
|
[![License](https://img.shields.io/badge/license-MIT-green.svg)](http://opensource.org/licenses/MIT)
|
8
8
|
[![Download Count](https://ruby-gem-downloads-badge.herokuapp.com/light-service?type=total)](https://rubygems.org/gems/light-service)
|
9
9
|
|
10
|
-
|
10
|
+
LightService is a powerful and flexible service skeleton framework with an emphasis on simplicity
|
11
11
|
|
12
|
-
|
13
|
-
<br>Version 0.9.0 deprecates Orchestrators and moves all their functionalities into Organizers. Please check out [this PR](https://github.com/adomokos/light-service/pull/132) to see the changes.
|
14
|
-
|
15
|
-
<br>
|
16
|
-
|
17
|
-
## Table of Content
|
12
|
+
## Table of Contents
|
18
13
|
* [Why LightService?](#why-lightservice)
|
19
14
|
* [Getting Started](#getting-started)
|
20
15
|
* [Requirements](#requirements)
|
@@ -31,9 +26,11 @@
|
|
31
26
|
* [Error Codes](#error-codes)
|
32
27
|
* [Action Rollback](#action-rollback)
|
33
28
|
* [Localizing Messages](#localizing-messages)
|
34
|
-
* [
|
29
|
+
* [Orchestrating Logic in Organizers](#orchestrating-logic-in-organizers)
|
35
30
|
* [ContextFactory for Faster Action Testing](#contextfactory-for-faster-action-testing)
|
36
31
|
* [Rails support](#rails-support)
|
32
|
+
* [Implementations in other languages](#other-implementations)
|
33
|
+
* [Contributing](#contributing)
|
37
34
|
|
38
35
|
## Why LightService?
|
39
36
|
|
@@ -866,9 +863,13 @@ end
|
|
866
863
|
|
867
864
|
To get the value of a `fail!` or `succeed!` message, simply call `#message` on the returned context.
|
868
865
|
|
869
|
-
##
|
866
|
+
## Orchestrating Logic in Organizers
|
867
|
+
|
868
|
+
The Organizer - Action combination works really well for simple use cases. However, as business logic gets more complex, or when LightService is used in an ETL workflow, the code that routes the different organizers becomes very complex and imperative.
|
870
869
|
|
871
|
-
|
870
|
+
In the past, this was solved using Orchestrators. As of [Version 0.9.0 Orchestrators have been deprecated](https://github.com/adomokos/light-service/pull/132). All their functionality is now usable directly within Organizers. Read on to understand how to orchestrate workflows from within a single Organizer.
|
871
|
+
|
872
|
+
Let's look at a piece of code that does basic data transformations:
|
872
873
|
|
873
874
|
```ruby
|
874
875
|
class ExtractsTransformsLoadsData
|
@@ -942,7 +943,7 @@ To take advantage of another organizer or action, you might need to tweak the co
|
|
942
943
|
|
943
944
|
Use `with_callback` when you want to execute actions with a deferred and controlled callback. It works similar to a Sax parser, I've used it for processing large files. The advantage of it is not having to keep large amount of data in memory. See [this acceptance test](spec/acceptance/organizer/with_callback_spec.rb) as a working example.
|
944
945
|
|
945
|
-
`add_to_context` can add key-value pairs on the fly to the context. This functionality is useful when you need a value injected into the context under a specific key right before the subsequent actions are executed. [This test](spec/acceptance/organizer/add_to_context_spec.rb) describes its functionality.
|
946
|
+
`add_to_context` can add key-value pairs on the fly to the context. This functionality is useful when you need a value injected into the context under a specific key right before the subsequent actions are executed. Keys are also made available as accessors on the context object and can be used just like methods exposed via `expects` and `promises`. [This test](spec/acceptance/organizer/add_to_context_spec.rb) describes its functionality.
|
946
947
|
|
947
948
|
Your action needs a certain key in the context but it's under a different one? Use the function `add_aliases` to alias an existing key in the context under the desired key. Take a look at [this test](spec/acceptance/organizer/add_aliases_spec.rb) to see an example.
|
948
949
|
|
@@ -1046,6 +1047,13 @@ them through the context. A stub context will be created in the test file using
|
|
1046
1047
|
|
1047
1048
|
When specifying `promises`, specs will be created testing for their existence after executing the action.
|
1048
1049
|
|
1050
|
+
## Other implementations
|
1051
|
+
|
1052
|
+
| Language | Repo | Author |
|
1053
|
+
| :------- |:------------------------------------------------------------------| :------------------------------------------------------|
|
1054
|
+
| Python | [pyservice](https://github.com/adomokos/pyservice) | [@adomokos](https://github.com/adomokos) |
|
1055
|
+
| PHP | [light-service](https://github.com/douglasgreyling/light-service) | [@douglasgreyling](https://github.com/douglasgreyling) |
|
1056
|
+
|
1049
1057
|
## Contributing
|
1050
1058
|
1. Fork it
|
1051
1059
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
data/RELEASES.md
CHANGED
@@ -1,11 +1,16 @@
|
|
1
1
|
A brief list of new features and changes introduced with the specified version.
|
2
2
|
|
3
|
+
### 0.16.0
|
4
|
+
* [Drop Ruby 2.4 support](https://github.com/adomokos/light-service/pull/207)
|
5
|
+
* [Fix callback current action](https://github.com/adomokos/light-service/pull/209)
|
6
|
+
* [Add Context accessors](https://github.com/adomokos/light-service/pull/211)
|
7
|
+
* [Switched to GH Actions from Travis CI](https://github.com/adomokos/light-service/pull/212)
|
8
|
+
|
3
9
|
### 0.15.0
|
4
10
|
* [Add Rails Generators](https://github.com/adomokos/light-service/pull/194) - LightService actions and organizers can be generated with generators
|
5
11
|
* [Add CodeCov](https://github.com/adomokos/light-service/pull/195) - Upload code coverage report to codecov.io
|
6
12
|
* [Remove ActiveSupport 3 checks](https://github.com/adomokos/light-service/pull/197) - They are unsupported, no need to tests them any more.
|
7
13
|
|
8
|
-
|
9
14
|
### 0.14.0
|
10
15
|
* [Add 'organized_by' to context](https://github.com/adomokos/light-service/pull/192) - Context now have an #organized_by attribute
|
11
16
|
|
data/lib/light-service/action.rb
CHANGED
@@ -44,6 +44,9 @@ module LightService
|
|
44
44
|
catch(:jump_when_failed) do
|
45
45
|
call_before_action(action_context)
|
46
46
|
yield(action_context)
|
47
|
+
|
48
|
+
# Reset the stored action in case it was changed downstream
|
49
|
+
action_context.current_action = self
|
47
50
|
call_after_action(action_context)
|
48
51
|
end
|
49
52
|
end
|
@@ -115,9 +115,9 @@ module LightService
|
|
115
115
|
end
|
116
116
|
|
117
117
|
def define_accessor_methods_for_keys(keys)
|
118
|
-
return if keys.
|
118
|
+
return if keys.blank?
|
119
119
|
|
120
|
-
keys.each do |key|
|
120
|
+
Array(keys).each do |key|
|
121
121
|
next if respond_to?(key.to_sym)
|
122
122
|
|
123
123
|
define_singleton_method(key.to_s) { fetch(key) }
|
@@ -111,7 +111,24 @@ module LightService
|
|
111
111
|
end
|
112
112
|
|
113
113
|
def reserved_keys
|
114
|
-
%i[message error_code current_action].freeze
|
114
|
+
%i[message error_code current_action organized_by].freeze
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
class ReservedKeysViaOrganizerVerifier < ReservedKeysVerifier
|
119
|
+
def initialize(context_data)
|
120
|
+
@context = LightService::Context.make(context_data)
|
121
|
+
end
|
122
|
+
|
123
|
+
def violated_keys
|
124
|
+
context.keys.map(&:to_sym) & reserved_keys
|
125
|
+
end
|
126
|
+
|
127
|
+
def error_message
|
128
|
+
<<~ERR
|
129
|
+
reserved keys cannot be added to the context
|
130
|
+
reserved key: [#{format_keys(violated_keys)}]
|
131
|
+
ERR
|
115
132
|
end
|
116
133
|
end
|
117
134
|
end
|
@@ -65,9 +65,18 @@ module LightService
|
|
65
65
|
@logger
|
66
66
|
end
|
67
67
|
|
68
|
-
|
69
|
-
|
70
|
-
|
68
|
+
# Set the value as a key on the context hash
|
69
|
+
# and also create convenience accessors for the keys
|
70
|
+
def add_to_context(args)
|
71
|
+
Context::ReservedKeysViaOrganizerVerifier.new(args).verify
|
72
|
+
|
73
|
+
Hash(args).map do |key, value|
|
74
|
+
context_key = lambda do |ctx|
|
75
|
+
ctx[key.to_sym] = value
|
76
|
+
ctx.define_accessor_methods_for_keys(key)
|
77
|
+
end
|
78
|
+
|
79
|
+
execute(context_key)
|
71
80
|
end
|
72
81
|
end
|
73
82
|
|
data/light-service.gemspec
CHANGED
@@ -15,8 +15,9 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.name = "light-service"
|
16
16
|
gem.require_paths = ["lib"]
|
17
17
|
gem.version = LightService::VERSION
|
18
|
+
gem.required_ruby_version = '>= 2.5.0'
|
18
19
|
|
19
|
-
gem.add_runtime_dependency("activesupport", ">=
|
20
|
+
gem.add_runtime_dependency("activesupport", ">= 4.0.0")
|
20
21
|
|
21
22
|
gem.add_development_dependency("generator_spec", "~> 0.9.4")
|
22
23
|
gem.add_development_dependency("test-unit", "~> 3.0") # Needed for generator specs.
|
@@ -65,6 +65,23 @@ RSpec.describe 'Action after_actions' do
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
+
context 'with callbacks' do
|
69
|
+
it 'ensures the correct :current_action is set' do
|
70
|
+
TestDoubles::TestWithCallback.after_actions = [
|
71
|
+
lambda do |ctx|
|
72
|
+
if ctx.current_action == TestDoubles::IterateCollectionAction
|
73
|
+
ctx.total -= 1000
|
74
|
+
end
|
75
|
+
end
|
76
|
+
]
|
77
|
+
|
78
|
+
result = TestDoubles::TestWithCallback.call
|
79
|
+
|
80
|
+
expect(result.counter).to eq(3)
|
81
|
+
expect(result.total).to eq(-994)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
68
85
|
describe 'after_actions can be appended' do
|
69
86
|
it 'adds to the :_after_actions collection' do
|
70
87
|
TestDoubles::AdditionOrganizer.append_after_actions(
|
@@ -20,6 +20,20 @@ RSpec.describe LightService::Organizer do
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
+
class TestAddToContextReservedWords
|
24
|
+
extend LightService::Organizer
|
25
|
+
|
26
|
+
def self.call(context = LightService::Context.make)
|
27
|
+
with(context).reduce(steps)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.steps
|
31
|
+
[
|
32
|
+
add_to_context(:message => "yo", "error_code" => "00P5")
|
33
|
+
]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
23
37
|
it 'adds items to the context on the fly' do
|
24
38
|
result = TestAddToContext.call
|
25
39
|
|
@@ -27,4 +41,17 @@ RSpec.describe LightService::Organizer do
|
|
27
41
|
expect(result.number).to eq(1)
|
28
42
|
expect(result[:something]).to eq('hello')
|
29
43
|
end
|
44
|
+
|
45
|
+
it 'adds items to the context as accessors' do
|
46
|
+
result = TestAddToContext.call
|
47
|
+
|
48
|
+
expect(result).to be_success
|
49
|
+
expect(result.something).to eq('hello')
|
50
|
+
end
|
51
|
+
|
52
|
+
it "will not add items as accessors when they are reserved" do
|
53
|
+
expect { TestAddToContextReservedWords.call }.to \
|
54
|
+
raise_error(LightService::ReservedKeysInContextError)
|
55
|
+
.with_message(/:message, :error_code/)
|
56
|
+
end
|
30
57
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'test_doubles'
|
3
|
+
|
4
|
+
RSpec.describe LightService::Organizer do
|
5
|
+
class TestExecuteWithAddToContext
|
6
|
+
extend LightService::Organizer
|
7
|
+
|
8
|
+
def self.call
|
9
|
+
with.reduce(steps)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.steps
|
13
|
+
[
|
14
|
+
add_to_context(:greeting => "hello"),
|
15
|
+
execute(->(ctx) { ctx.greeting.upcase! })
|
16
|
+
]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when using context values created by add_to_context" do
|
21
|
+
it "is expected to reference them as accessors" do
|
22
|
+
result = TestExecuteWithAddToContext.call
|
23
|
+
|
24
|
+
expect(result).to be_a_success
|
25
|
+
expect(result.greeting).to eq "HELLO"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: light-service
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.16.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Attila Domokos
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-07-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 4.0.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 4.0.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: generator_spec
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -157,6 +157,7 @@ executables: []
|
|
157
157
|
extensions: []
|
158
158
|
extra_rdoc_files: []
|
159
159
|
files:
|
160
|
+
- ".github/workflows/project-build.yml"
|
160
161
|
- ".gitignore"
|
161
162
|
- ".rspec"
|
162
163
|
- ".rubocop.yml"
|
@@ -168,7 +169,6 @@ files:
|
|
168
169
|
- README.md
|
169
170
|
- RELEASES.md
|
170
171
|
- Rakefile
|
171
|
-
- gemfiles/activesupport_4.gemfile
|
172
172
|
- gemfiles/activesupport_5.gemfile
|
173
173
|
- gemfiles/activesupport_6.gemfile
|
174
174
|
- lib/generators/light_service/action_generator.rb
|
@@ -203,7 +203,6 @@ files:
|
|
203
203
|
- light-service.gemspec
|
204
204
|
- resources/fail_actions.png
|
205
205
|
- resources/light-service.png
|
206
|
-
- resources/orchestrators_deprecated.svg
|
207
206
|
- resources/organizer_and_actions.png
|
208
207
|
- resources/skip_actions.png
|
209
208
|
- spec/acceptance/add_numbers_spec.rb
|
@@ -228,6 +227,7 @@ files:
|
|
228
227
|
- spec/acceptance/organizer/around_each_with_reduce_if_spec.rb
|
229
228
|
- spec/acceptance/organizer/context_failure_and_skipping_spec.rb
|
230
229
|
- spec/acceptance/organizer/execute_spec.rb
|
230
|
+
- spec/acceptance/organizer/execute_with_add_to_context_spec.rb
|
231
231
|
- spec/acceptance/organizer/iterate_spec.rb
|
232
232
|
- spec/acceptance/organizer/reduce_if_spec.rb
|
233
233
|
- spec/acceptance/organizer/reduce_until_spec.rb
|
@@ -270,7 +270,7 @@ homepage: https://github.com/adomokos/light-service
|
|
270
270
|
licenses:
|
271
271
|
- MIT
|
272
272
|
metadata: {}
|
273
|
-
post_install_message:
|
273
|
+
post_install_message:
|
274
274
|
rdoc_options: []
|
275
275
|
require_paths:
|
276
276
|
- lib
|
@@ -278,7 +278,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
278
278
|
requirements:
|
279
279
|
- - ">="
|
280
280
|
- !ruby/object:Gem::Version
|
281
|
-
version:
|
281
|
+
version: 2.5.0
|
282
282
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
283
283
|
requirements:
|
284
284
|
- - ">="
|
@@ -286,7 +286,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
286
286
|
version: '0'
|
287
287
|
requirements: []
|
288
288
|
rubygems_version: 3.1.2
|
289
|
-
signing_key:
|
289
|
+
signing_key:
|
290
290
|
specification_version: 4
|
291
291
|
summary: A service skeleton with an emphasis on simplicity
|
292
292
|
test_files:
|
@@ -312,6 +312,7 @@ test_files:
|
|
312
312
|
- spec/acceptance/organizer/around_each_with_reduce_if_spec.rb
|
313
313
|
- spec/acceptance/organizer/context_failure_and_skipping_spec.rb
|
314
314
|
- spec/acceptance/organizer/execute_spec.rb
|
315
|
+
- spec/acceptance/organizer/execute_with_add_to_context_spec.rb
|
315
316
|
- spec/acceptance/organizer/iterate_spec.rb
|
316
317
|
- spec/acceptance/organizer/reduce_if_spec.rb
|
317
318
|
- spec/acceptance/organizer/reduce_until_spec.rb
|
@@ -1,10 +0,0 @@
|
|
1
|
-
<?xml version="1.0" encoding="utf-8"?>
|
2
|
-
<svg version="1.1"
|
3
|
-
xmlns="http://www.w3.org/2000/svg"
|
4
|
-
xmlns:xlink="http://www.w3.org/1999/xlink"
|
5
|
-
width="350" height="20"
|
6
|
-
>
|
7
|
-
<text font-size="20" x="0" y="20" font-family="Verdana">
|
8
|
-
<tspan fill="red">Orchestrators are DEPRECATED!</tspan>
|
9
|
-
</text>
|
10
|
-
</svg>
|