marty 6.1.0 → 8.0.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/.gitignore +1 -0
- data/.gitlab-ci.yml +17 -3
- data/.rubocop.yml +5 -0
- data/.rubocop_todo.yml +3 -2
- data/Gemfile +2 -1
- data/app/assets/javascripts/marty/extjs/extensions/marty.js +23 -1
- data/app/assets/stylesheets/marty/application.css +4 -1
- data/app/assets/stylesheets/marty/dark_mode.css +17 -0
- data/app/components/marty/auth_app.rb +10 -1
- data/app/components/marty/auth_app/client/auth_app.js +4 -0
- data/app/components/marty/extras/layout.rb +2 -2
- data/app/components/marty/extras/misc.rb +1 -1
- data/app/components/marty/log_view.rb +0 -1
- data/app/components/marty/main_auth_app.rb +9 -12
- data/app/components/marty/promise_view.rb +5 -0
- data/app/components/marty/promise_view/client/promise_view.js +11 -0
- data/app/components/marty/schedule_jobs_dashboard.rb +30 -96
- data/app/components/marty/schedule_jobs_grid.rb +118 -0
- data/app/controllers/marty/application_controller.rb +6 -2
- data/app/models/marty/base.rb +48 -48
- data/app/models/marty/config.rb +14 -2
- data/app/models/marty/user.rb +12 -0
- data/app/services/marty/background_job/fetch_missing_in_schedule_cron_jobs.rb +19 -0
- data/app/services/marty/enums/report.rb +18 -0
- data/app/services/marty/promises/delorean/create.rb +16 -27
- data/app/services/marty/promises/ruby/create.rb +10 -1
- data/app/views/layouts/marty/application.html.erb +4 -1
- data/app/views/marty/diagnostic/op.html.erb +3 -1
- data/config/locales/en.yml +2 -0
- data/db/migrate/512_add_promise_priority.rb +9 -0
- data/db/migrate/513_add_priority_to_promise_view.rb +44 -0
- data/db/migrate/514_remove_marty_events.rb +13 -0
- data/delorean/enum_report.dl +11 -0
- data/delorean/table_report.dl +7 -0
- data/docker-compose.dummy.yml +7 -4
- data/lib/marty.rb +5 -2
- data/lib/marty/api/base.rb +15 -9
- data/lib/marty/cache_adapters.rb +2 -0
- data/lib/marty/cache_adapters/mcfly_ruby_cache.rb +1 -5
- data/lib/marty/cache_adapters/memory_and_redis.rb +93 -0
- data/lib/marty/cache_adapters/redis.rb +63 -0
- data/lib/marty/delayed_job/scheduled_job_plugin.rb +33 -0
- data/lib/marty/diagnostic/database.rb +1 -2
- data/lib/marty/logger.rb +50 -17
- data/lib/marty/monkey.rb +26 -6
- data/lib/marty/promise_ruby_job.rb +2 -0
- data/lib/marty/rails_app.rb +29 -0
- data/lib/marty/railtie.rb +1 -0
- data/lib/marty/version.rb +1 -1
- data/marty.gemspec +1 -0
- data/spec/controllers/job_controller_spec.rb +2 -2
- data/spec/dummy/app/components/gemini/cm_auth_app.rb +12 -0
- data/spec/dummy/app/components/gemini/simple_view.rb +17 -0
- data/spec/dummy/app/jobs/test_failing_job.rb +14 -0
- data/spec/dummy/app/models/gemini/helper.rb +90 -1
- data/spec/dummy/config/application.rb +1 -0
- data/spec/dummy/db/migrate/20191101132729_add_activity_flag_to_simple.rb +10 -0
- data/spec/dummy/delorean/blame_report.dl +1 -0
- data/spec/dummy/delorean/enum_report.dl +1 -0
- data/spec/dummy/delorean/marty_fields.dl +1 -0
- data/spec/dummy/delorean/table_report.dl +1 -0
- data/spec/features/data_blame_report_spec.rb +66 -0
- data/spec/features/data_grid_spec.rb +1 -1
- data/spec/features/enum_values_report_spec.rb +76 -0
- data/spec/features/inline_editing_spec.rb +33 -0
- data/spec/features/rule_spec.rb +1 -1
- data/spec/features/schedule_jobs_dashboard_spec.rb +1 -1
- data/spec/features/scripting_spec.rb +1 -1
- data/spec/features/user_list_report_spec.rb +74 -0
- data/spec/fixtures/misc/struct_compare_tests.txt +15 -5
- data/spec/job_helper.rb +39 -0
- data/spec/jobs/cron_job_spec.rb +91 -0
- data/spec/lib/mcfly_model_spec.rb +9 -0
- data/spec/models/promise_spec.rb +168 -1
- data/spec/other/diagnostic/delayed_job_workers_spec.rb +1 -1
- data/spec/performance/caching_spec.rb +99 -0
- data/spec/services/background_job/fetch_missing_in_schedule_cron_jobs_spec.rb +34 -0
- data/spec/support/delayed_job_helpers.rb +3 -3
- data/spec/support/shared_connection.rb +9 -1
- data/spec/support/structure_compare.rb +19 -3
- metadata +39 -6
- data/app/components/marty/event_view.rb +0 -129
- data/app/models/marty/event.rb +0 -317
- data/spec/dummy/db/migrate/20160923183516_add_bulk_pricing_event_ops.rb +0 -8
- data/spec/dummy/delorean/blame_report.dl +0 -268
- data/spec/dummy/delorean/marty_fields.dl +0 -63
- data/spec/dummy/delorean/table_report.dl +0 -34
- data/spec/models/event_spec.rb +0 -272
@@ -52,7 +52,9 @@
|
|
52
52
|
<body>
|
53
53
|
<div style="text-align:center">
|
54
54
|
<h1 class="application <%= 'error' unless @result['errors'].empty? %>">
|
55
|
-
<%=
|
55
|
+
<%=
|
56
|
+
ENV['DIAG_TITLE'] || ::Marty::RailsApp.application_name
|
57
|
+
%> Diagnostic
|
56
58
|
</h1>
|
57
59
|
<h3><i><%= DateTime.now %></i></h3>
|
58
60
|
<%== @result['display'] %>
|
data/config/locales/en.yml
CHANGED
@@ -0,0 +1,44 @@
|
|
1
|
+
class AddPriorityToPromiseView < ActiveRecord::Migration[4.2]
|
2
|
+
def up
|
3
|
+
execute <<~SQL
|
4
|
+
DROP VIEW IF EXISTS marty_vw_promises;
|
5
|
+
CREATE OR REPLACE VIEW marty_vw_promises
|
6
|
+
AS
|
7
|
+
SELECT
|
8
|
+
id,
|
9
|
+
title,
|
10
|
+
user_id,
|
11
|
+
cformat,
|
12
|
+
parent_id,
|
13
|
+
job_id,
|
14
|
+
status,
|
15
|
+
start_dt,
|
16
|
+
end_dt,
|
17
|
+
priority
|
18
|
+
FROM marty_promises;
|
19
|
+
|
20
|
+
GRANT SELECT ON marty_vw_promises TO public;
|
21
|
+
SQL
|
22
|
+
end
|
23
|
+
|
24
|
+
def down
|
25
|
+
execute <<~SQL
|
26
|
+
DROP VIEW IF EXISTS marty_vw_promises;
|
27
|
+
CREATE OR REPLACE VIEW marty_vw_promises
|
28
|
+
AS
|
29
|
+
SELECT
|
30
|
+
id,
|
31
|
+
title,
|
32
|
+
user_id,
|
33
|
+
cformat,
|
34
|
+
parent_id,
|
35
|
+
job_id,
|
36
|
+
status,
|
37
|
+
start_dt,
|
38
|
+
end_dt
|
39
|
+
FROM marty_promises;
|
40
|
+
|
41
|
+
GRANT SELECT ON marty_vw_promises TO public;
|
42
|
+
SQL
|
43
|
+
end
|
44
|
+
end
|
data/delorean/table_report.dl
CHANGED
data/docker-compose.dummy.yml
CHANGED
@@ -17,9 +17,11 @@ services:
|
|
17
17
|
- "HEADLESS=true"
|
18
18
|
- "PGTZ=America/Los_Angeles"
|
19
19
|
- "BUNDLER_VERSION=2.0.1"
|
20
|
+
- "MARTY_REDIS_URL=redis:6379/1"
|
20
21
|
# env_file: ".rbenv-vars"
|
21
22
|
depends_on:
|
22
23
|
- "postgres"
|
24
|
+
- "redis"
|
23
25
|
volumes:
|
24
26
|
- .:/opt/app:delegated
|
25
27
|
- '.bash_history.docker:/root/.bash_history'
|
@@ -34,12 +36,13 @@ services:
|
|
34
36
|
volumes:
|
35
37
|
- postgresql-data:/var/lib/postgresql/data
|
36
38
|
|
37
|
-
|
38
|
-
image:
|
39
|
+
redis:
|
40
|
+
image: 'redis:5.0.6-alpine'
|
39
41
|
volumes:
|
40
|
-
-
|
42
|
+
- redis-data:/data
|
41
43
|
|
42
44
|
volumes:
|
43
|
-
postgresql-data:
|
44
45
|
bundle_box:
|
46
|
+
postgresql-data:
|
47
|
+
redis-data:
|
45
48
|
|
data/lib/marty.rb
CHANGED
@@ -15,6 +15,7 @@ require 'marty/cache_adapters'
|
|
15
15
|
require 'marty/monkey'
|
16
16
|
require 'marty/promise_job'
|
17
17
|
require 'marty/json_schema'
|
18
|
+
require 'marty/rails_app'
|
18
19
|
|
19
20
|
# This does not get loaded in via bundler unless it is included in the
|
20
21
|
# application's Gemfile. Requiring it here removes the need to add it
|
@@ -25,7 +26,9 @@ require 'delayed_cron_job'
|
|
25
26
|
require 'pathname'
|
26
27
|
|
27
28
|
module Marty
|
28
|
-
|
29
|
-
|
29
|
+
class << self
|
30
|
+
def root
|
31
|
+
Pathname.new(File.expand_path('..', __dir__))
|
32
|
+
end
|
30
33
|
end
|
31
34
|
end
|
data/lib/marty/api/base.rb
CHANGED
@@ -53,14 +53,19 @@ class Marty::Api::Base
|
|
53
53
|
params = params.deep_dup
|
54
54
|
|
55
55
|
schema_key = [params[:tag], params[:script], params[:node], params[:attr]]
|
56
|
-
input_schema =
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
Marty::JsonSchema.get_schema(*schema_key)
|
62
|
-
|
63
|
-
|
56
|
+
input_schema = @@schemas[schema_key]
|
57
|
+
unless input_schema
|
58
|
+
begin
|
59
|
+
# get_schema will either return a hash with the schema,
|
60
|
+
# or a string with the error
|
61
|
+
result_schema = Marty::JsonSchema.get_schema(*schema_key)
|
62
|
+
|
63
|
+
# only store schema in cache when not error
|
64
|
+
@@schemas[schema_key] = result_schema if result_schema.is_a?(Hash)
|
65
|
+
input_schema = result_schema
|
66
|
+
rescue StandardError => e
|
67
|
+
return { error: e.message }
|
68
|
+
end
|
64
69
|
end
|
65
70
|
|
66
71
|
# if schema was found
|
@@ -165,7 +170,8 @@ class Marty::Api::Base
|
|
165
170
|
def self.filter_hash hash, filter_params
|
166
171
|
return unless hash
|
167
172
|
|
168
|
-
|
173
|
+
pf_class = ::Marty::RailsApp.parameter_filter_class
|
174
|
+
pf = pf_class.new(filter_params)
|
169
175
|
pf.filter(hash.stringify_keys)
|
170
176
|
end
|
171
177
|
|
data/lib/marty/cache_adapters.rb
CHANGED
@@ -2,11 +2,7 @@ module Marty
|
|
2
2
|
module CacheAdapters
|
3
3
|
class McflyRubyCache < ::Delorean::Cache::Adapters::RubyCache
|
4
4
|
def cache_item?(klass:, method_name:, args:)
|
5
|
-
|
6
|
-
|
7
|
-
return false if Mcfly.is_infinity(ts)
|
8
|
-
|
9
|
-
true
|
5
|
+
!Mcfly.is_infinity(args&.first)
|
10
6
|
end
|
11
7
|
end
|
12
8
|
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Marty
|
4
|
+
module CacheAdapters
|
5
|
+
class MemoryAndRedis < ::Delorean::Cache::Adapters::Base
|
6
|
+
POST = '__RedisCache'
|
7
|
+
|
8
|
+
def initialize(
|
9
|
+
size_per_class: 1000,
|
10
|
+
redis_url: Rails.application.config.marty.redis_url,
|
11
|
+
redis_expires_in: 48.hours
|
12
|
+
)
|
13
|
+
@size_per_class = size_per_class
|
14
|
+
|
15
|
+
@redis_adapter = ::Marty::CacheAdapters::Redis.new(
|
16
|
+
redis_url: redis_url,
|
17
|
+
expires_in: redis_expires_in
|
18
|
+
)
|
19
|
+
|
20
|
+
@memory_adapter = ::Marty::CacheAdapters::McflyRubyCache.new(
|
21
|
+
size_per_class: size_per_class
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def cache_item(klass:, cache_key:, item:)
|
26
|
+
@redis_adapter.cache_item(
|
27
|
+
klass: klass,
|
28
|
+
cache_key: cache_key,
|
29
|
+
item: item
|
30
|
+
)
|
31
|
+
|
32
|
+
@memory_adapter.cache_item(
|
33
|
+
klass: klass,
|
34
|
+
cache_key: cache_key,
|
35
|
+
item: item
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
# When cache is found in local memory, we simply return the cached item.
|
40
|
+
# Otherwise we look into Redis, if item is cached there,
|
41
|
+
# we copy it to local memory to speed up future lookups.
|
42
|
+
def fetch_item(klass:, cache_key:, default: nil)
|
43
|
+
memory_item = @memory_adapter.fetch_item(
|
44
|
+
klass: klass,
|
45
|
+
cache_key: cache_key,
|
46
|
+
default: default
|
47
|
+
)
|
48
|
+
|
49
|
+
return memory_item if memory_item != default
|
50
|
+
|
51
|
+
redis_item = @redis_adapter.fetch_item(
|
52
|
+
klass: klass,
|
53
|
+
cache_key: cache_key,
|
54
|
+
default: default
|
55
|
+
)
|
56
|
+
|
57
|
+
return default if redis_item == default
|
58
|
+
|
59
|
+
@memory_adapter.cache_item(
|
60
|
+
klass: klass,
|
61
|
+
cache_key: cache_key,
|
62
|
+
item: redis_item
|
63
|
+
)
|
64
|
+
|
65
|
+
redis_item
|
66
|
+
end
|
67
|
+
|
68
|
+
def cache_key(klass:, method_name:, args:)
|
69
|
+
r = ["#{klass.name}#{POST}", method_name] + args.map do |arg|
|
70
|
+
arg.respond_to?(:id) ? arg.id : arg
|
71
|
+
|
72
|
+
arg
|
73
|
+
end.freeze
|
74
|
+
|
75
|
+
Marshal.dump r
|
76
|
+
end
|
77
|
+
|
78
|
+
def clear!(klass:)
|
79
|
+
@redis_adapter.clear!(klass: klass)
|
80
|
+
@memory_adapter.clear!(klass: klass)
|
81
|
+
end
|
82
|
+
|
83
|
+
def clear_all!
|
84
|
+
@redis_adapter.clear_all!
|
85
|
+
@memory_adapter.clear_all!
|
86
|
+
end
|
87
|
+
|
88
|
+
def cache_item?(klass:, method_name:, args:)
|
89
|
+
!Mcfly.is_infinity(args&.first)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'redis'
|
4
|
+
|
5
|
+
module Marty
|
6
|
+
module CacheAdapters
|
7
|
+
class Redis < ::Delorean::Cache::Adapters::Base
|
8
|
+
POST = '__RedisCache'
|
9
|
+
|
10
|
+
def initialize(
|
11
|
+
size_per_class: 1000,
|
12
|
+
redis_url: Rails.application.config.marty.redis_url,
|
13
|
+
expires_in: 48.hours
|
14
|
+
)
|
15
|
+
@redis = ::Redis.new(url: "redis://#{redis_url}")
|
16
|
+
@expires_in = expires_in
|
17
|
+
end
|
18
|
+
|
19
|
+
def cache_item(klass:, cache_key:, item:)
|
20
|
+
@redis.set(
|
21
|
+
cache_key,
|
22
|
+
Marshal.dump(item),
|
23
|
+
ex: @expires_in.seconds.to_i
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
def fetch_item(klass:, cache_key:, default: nil)
|
28
|
+
r = @redis.get(cache_key)
|
29
|
+
|
30
|
+
return default if r.nil?
|
31
|
+
|
32
|
+
Marshal.load(r)
|
33
|
+
end
|
34
|
+
|
35
|
+
def cache_key(klass:, method_name:, args:)
|
36
|
+
r = ["#{klass.name}#{POST}", method_name] + args.map do |arg|
|
37
|
+
next arg.id if arg.respond_to?(:id)
|
38
|
+
|
39
|
+
arg
|
40
|
+
end.freeze
|
41
|
+
|
42
|
+
Marshal.dump r
|
43
|
+
end
|
44
|
+
|
45
|
+
def clear!(klass:)
|
46
|
+
keys = @redis.keys("*#{klass.name}#{POST}*")
|
47
|
+
@redis.pipelined do
|
48
|
+
keys.each do |key|
|
49
|
+
@redis.del key
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def clear_all!
|
55
|
+
@redis.flushall
|
56
|
+
end
|
57
|
+
|
58
|
+
def cache_item?(klass:, method_name:, args:)
|
59
|
+
!Mcfly.is_infinity(args&.first)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Marty
|
2
|
+
module DelayedJob
|
3
|
+
class ScheduledJobPlugin < Delayed::Plugin
|
4
|
+
class << self
|
5
|
+
def cron?(job)
|
6
|
+
job.cron.present?
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
callbacks do |lifecycle|
|
11
|
+
# We want to nullify cron column if job schedule was turned off
|
12
|
+
# while the job was running, so it won't add a new record to
|
13
|
+
# delayed_jobs table
|
14
|
+
lifecycle.before(:error) do |worker, job, &block|
|
15
|
+
if cron?(job)
|
16
|
+
begin
|
17
|
+
job_class_str = job.handler.split("\n").find do |line|
|
18
|
+
line.include? 'job_class'
|
19
|
+
end
|
20
|
+
job_class_name = job_class_str.gsub('job_class:', '').strip
|
21
|
+
job_class = job_class_name.constantize
|
22
|
+
job.cron = job_class.cron_expression
|
23
|
+
rescue StandardError
|
24
|
+
end
|
25
|
+
else
|
26
|
+
# No cron job - proceed as normal
|
27
|
+
block.call(worker, job)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -22,8 +22,7 @@ module Marty::Diagnostic::Database
|
|
22
22
|
def self.db_schema
|
23
23
|
current = ActiveRecord::Migrator.current_version
|
24
24
|
raise "Migration is needed.\nCurrent Version: #{current}" if
|
25
|
-
|
26
|
-
ActiveRecord::Base.connection.migration_context.needs_migration?
|
25
|
+
::Marty::RailsApp.needs_migration?
|
27
26
|
|
28
27
|
current.to_s
|
29
28
|
end
|
data/lib/marty/logger.rb
CHANGED
@@ -1,27 +1,60 @@
|
|
1
1
|
class Marty::Logger
|
2
2
|
include Delorean::Model
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
[:debug, :info, :warn, :error, :fatal, :unknown].include?(m)
|
7
|
-
|
8
|
-
Marty::Util.logger.send(m, args[0]) if Marty::Util.logger.respond_to?(m)
|
9
|
-
log(m, *args)
|
4
|
+
delorean_fn :dllog, sig: [2, 20] do |*args|
|
5
|
+
info args[0], args[1..-1]
|
10
6
|
end
|
11
7
|
|
12
|
-
|
13
|
-
|
14
|
-
|
8
|
+
class << self
|
9
|
+
def log_event(event_name, *args)
|
10
|
+
if Marty::Util.logger.respond_to?(event_name)
|
11
|
+
Marty::Util.logger.send(
|
12
|
+
event_name,
|
13
|
+
args[0]
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
log(event_name, *args)
|
18
|
+
end
|
19
|
+
|
20
|
+
def debug(*args)
|
21
|
+
log_event(:debug, *args)
|
22
|
+
end
|
23
|
+
|
24
|
+
def info(*args)
|
25
|
+
log_event(:info, *args)
|
26
|
+
end
|
27
|
+
|
28
|
+
def warn(*args)
|
29
|
+
log_event(:warn, *args)
|
30
|
+
end
|
31
|
+
|
32
|
+
def error(*args)
|
33
|
+
log_event(:error, *args)
|
34
|
+
end
|
15
35
|
|
16
|
-
|
36
|
+
def fatal(*args)
|
37
|
+
log_event(:fatal, *args)
|
38
|
+
end
|
39
|
+
|
40
|
+
def unknown(*args)
|
41
|
+
log_event(:unknown, *args)
|
42
|
+
end
|
43
|
+
|
44
|
+
def log(type, message, details = nil)
|
45
|
+
Marty::Log.write_log(type, message, details)
|
46
|
+
end
|
47
|
+
|
48
|
+
def with_logging(error_message, error_data)
|
17
49
|
yield
|
18
|
-
|
19
|
-
error(
|
20
|
-
|
21
|
-
|
22
|
-
|
50
|
+
rescue StandardError => e
|
51
|
+
error(
|
52
|
+
error_message,
|
53
|
+
'message' => e.message,
|
54
|
+
'data' => error_data
|
55
|
+
)
|
23
56
|
|
24
|
-
|
25
|
-
|
57
|
+
raise "#{error_message}: #{e.message}"
|
58
|
+
end
|
26
59
|
end
|
27
60
|
end
|