gitlab-experiment 0.6.1 → 0.6.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0d1ad31e8b977491ccdd1a9d21fc348482d3942c80a3e2935a6ccabc515b4243
4
- data.tar.gz: bdf9a4b67bb2b5a72931c081fed88ac246853a2e90f4f7f5c08bf7bdb9d8f55e
3
+ metadata.gz: cd00eb06f769b8268e0e02e7d48b38dbef6be029c8f4d02b127e9f2b44f9dbc3
4
+ data.tar.gz: 7a3b9c5357489afd4b14bd6411536b1a2484c50f44934cc646b20abd1607ab0b
5
5
  SHA512:
6
- metadata.gz: dc1cc5077144d4e5514b6804599bba8e6829ad6472e5e362cde88940995b174f9989733fea17da91be92dc172694a4394ee0db7974efba8d6eb4e77e769a57ee
7
- data.tar.gz: 958cf74fa36b1588fd7f83776e87c7f8c92120cb8a6d421c09a4bd207adffdfcfe69ea295dd1e6a49d371225988f6fde3f559baf64d755a0c9176a33e7efddca
6
+ metadata.gz: '08ea7e0b62c92e7674a72271e388dd104878ad2b9328ad016fba758762e244b51da1a089cec0d74e1db11fba4da3e2bc59524ef2839424295fa3c7307c73cb87'
7
+ data.tar.gz: 7ecfc7bbaa0803b67ccfd642c7c06baec43cde54b41cc768a7c1a1537e5c6cae6e13a355bdf342d4cdaebef15f5a1b99e76676c87612d857affb865bb543e07d
@@ -56,6 +56,16 @@ Gitlab::Experiment.configure do |config|
56
56
  # '/-/experiment', '/redirect', nil
57
57
  config.mount_at = '/experiment'
58
58
 
59
+ # When using the middleware, links can be instrumented and redirected
60
+ # elsewhere. This can be exploited to make a harmful url look innocuous or
61
+ # that it's a valid url on your domain. To avoid this, you can provide your
62
+ # own logic for what urls will be considered valid and redirected to.
63
+ #
64
+ # Expected to return a boolean value.
65
+ config.redirect_url_validator = lambda do |redirect_url|
66
+ true
67
+ end
68
+
59
69
  # Logic this project uses to determine inclusion in a given experiment.
60
70
  #
61
71
  # Expected to return a boolean value.
@@ -120,6 +120,13 @@ module Gitlab
120
120
  instance_exec(action, event_args, &Configuration.tracking_behavior)
121
121
  end
122
122
 
123
+ def process_redirect_url(url)
124
+ return unless Configuration.redirect_url_validator&.call(url)
125
+
126
+ track('visited', url: url)
127
+ url # return the url, which allows for mutation
128
+ end
129
+
123
130
  def enabled?
124
131
  true
125
132
  end
@@ -29,7 +29,7 @@ module Gitlab
29
29
 
30
30
  def from_param(id)
31
31
  %r{/?(?<name>.*):(?<key>.*)$} =~ id
32
- Gitlab::Experiment.new(name).tap { |e| e.context.key(key) }
32
+ constantize(name).new(name).tap { |e| e.context.key(key) }
33
33
  end
34
34
  end
35
35
 
@@ -39,17 +39,19 @@ module Gitlab
39
39
 
40
40
  # The default base path that the middleware (or rails engine) will be
41
41
  # mounted.
42
- @mount_at = '/experiment'
42
+ @mount_at = nil
43
+
44
+ # The middleware won't redirect to urls that aren't considered valid.
45
+ # Expected to return a boolean value.
46
+ @redirect_url_validator = ->(_redirect_url) { true }
43
47
 
44
48
  # Logic this project uses to determine inclusion in a given experiment.
45
49
  # Expected to return a boolean value.
46
- @inclusion_resolver = lambda do |requested_variant|
47
- false
48
- end
50
+ @inclusion_resolver = ->(_requested_variant) { false }
49
51
 
50
52
  # Tracking behavior can be implemented to link an event to an experiment.
51
53
  @tracking_behavior = lambda do |event, args|
52
- Configuration.logger.info "Gitlab::Experiment[#{name}] #{event}: #{args.merge(signature: signature)}"
54
+ Configuration.logger.info("#{self.class.name}[#{name}] #{event}: #{args.merge(signature: signature)}")
53
55
  end
54
56
 
55
57
  # Called at the end of every experiment run, with the result.
@@ -88,6 +90,7 @@ module Gitlab
88
90
  :context_key_bit_length,
89
91
  :mount_at,
90
92
  :default_rollout,
93
+ :redirect_url_validator,
91
94
  :inclusion_resolver,
92
95
  :tracking_behavior,
93
96
  :publishing_behavior
@@ -3,6 +3,10 @@
3
3
  module Gitlab
4
4
  class Experiment
5
5
  module Dsl
6
+ def self.include_in(klass, with_helper: false)
7
+ klass.include(self).tap { |base| base.helper_method(:experiment) if with_helper }
8
+ end
9
+
6
10
  def experiment(name, variant_name = nil, **context, &block)
7
11
  raise ArgumentError, 'name is required' if name.nil?
8
12
 
@@ -1,34 +1,42 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'active_model'
4
+
3
5
  module Gitlab
4
6
  class Experiment
7
+ include ActiveModel::Model
8
+
9
+ # used for generating routes
10
+ def self.model_name
11
+ ActiveModel::Name.new(self, Gitlab)
12
+ end
13
+
5
14
  class Engine < ::Rails::Engine
6
- def self.include_dsl
7
- if defined?(ActionController)
8
- ActionController::Base.include(Dsl)
9
- ActionController::Base.helper_method(:experiment)
10
- end
15
+ isolate_namespace Experiment
11
16
 
12
- return unless defined?(ActionMailer)
17
+ initializer('gitlab_experiment.include_dsl') { include_dsl }
18
+ initializer('gitlab_experiment.mount_engine') { |app| mount_engine(app, Configuration.mount_at) }
13
19
 
14
- ActionMailer::Base.include(Dsl)
15
- ActionMailer::Base.helper_method(:experiment)
20
+ private
21
+
22
+ def include_dsl
23
+ Dsl.include_in(ActionController::Base, with_helper: true) if defined?(ActionController)
24
+ Dsl.include_in(ActionMailer::Base, with_helper: true) if defined?(ActionMailer)
16
25
  end
17
26
 
18
- def add_middleware(app, base_path)
19
- return if base_path.blank?
27
+ def mount_engine(app, mount_at)
28
+ return if mount_at.blank?
20
29
 
21
- app.config.middleware.use(Middleware, base_path)
22
- app.routes.append do
23
- direct :experiment_redirect do |experiment, to_url|
24
- [base_path, experiment.to_param].join('/') + "?#{to_url}"
25
- end
30
+ engine = routes do
31
+ default_url_options app.routes.default_url_options
32
+ resources :experiments, path: '/', only: :show
26
33
  end
27
- end
28
34
 
29
- config.after_initialize { include_dsl }
30
- initializer 'gitlab_experiment.add_middleware' do |app|
31
- add_middleware(app, Configuration.mount_at)
35
+ app.config.middleware.use(Middleware, mount_at)
36
+ app.routes.append do
37
+ mount Engine, at: mount_at, as: :experiment_engine
38
+ direct(:experiment_redirect) { |ex, url:| "#{engine.url_helpers.experiment_url(ex)}?#{url}" }
39
+ end
32
40
  end
33
41
  end
34
42
  end
@@ -6,8 +6,8 @@ module Gitlab
6
6
  def self.redirect(id, url)
7
7
  raise Error, 'no url to redirect to' if url.blank?
8
8
 
9
- Gitlab::Experiment.from_param(id).tap { |e| e.track('visited', url: url) }
10
- [303, { 'Location' => url }, []]
9
+ experiment = Gitlab::Experiment.from_param(id)
10
+ [303, { 'Location' => experiment.process_redirect_url(url) || raise(Error, 'not redirecting') }, []]
11
11
  end
12
12
 
13
13
  def initialize(app, base_path)
@@ -82,7 +82,7 @@ module Gitlab
82
82
  extend RSpec::Matchers::DSL
83
83
 
84
84
  def require_experiment(experiment, matcher_name, classes: false)
85
- klass = experiment.class == Class ? experiment : experiment.class
85
+ klass = experiment.instance_of?(Class) ? experiment : experiment.class
86
86
  unless klass <= Gitlab::Experiment
87
87
  raise(
88
88
  ArgumentError,
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Gitlab
4
4
  class Experiment
5
- VERSION = '0.6.1'
5
+ VERSION = '0.6.2'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab-experiment
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitLab
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-22 00:00:00.000000000 Z
11
+ date:
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -65,38 +65,52 @@ executables: []
65
65
  extensions: []
66
66
  extra_rdoc_files: []
67
67
  files:
68
- - LICENSE.txt
69
- - README.md
70
- - lib/generators/gitlab/experiment/USAGE
71
- - lib/generators/gitlab/experiment/experiment_generator.rb
68
+ - lib/generators/gitlab
69
+ - lib/generators/gitlab/experiment
70
+ - lib/generators/gitlab/experiment/install
72
71
  - lib/generators/gitlab/experiment/install/install_generator.rb
73
- - lib/generators/gitlab/experiment/install/templates/POST_INSTALL
72
+ - lib/generators/gitlab/experiment/install/templates
74
73
  - lib/generators/gitlab/experiment/install/templates/application_experiment.rb.tt
75
74
  - lib/generators/gitlab/experiment/install/templates/initializer.rb.tt
75
+ - lib/generators/gitlab/experiment/install/templates/POST_INSTALL
76
+ - lib/generators/gitlab/experiment/USAGE
77
+ - lib/generators/gitlab/experiment/experiment_generator.rb
78
+ - lib/generators/gitlab/experiment/templates
76
79
  - lib/generators/gitlab/experiment/templates/experiment.rb.tt
77
- - lib/generators/rspec/experiment/experiment_generator.rb
78
- - lib/generators/rspec/experiment/templates/experiment_spec.rb.tt
80
+ - lib/generators/test_unit
81
+ - lib/generators/test_unit/experiment
79
82
  - lib/generators/test_unit/experiment/experiment_generator.rb
83
+ - lib/generators/test_unit/experiment/templates
80
84
  - lib/generators/test_unit/experiment/templates/experiment_test.rb.tt
85
+ - lib/generators/rspec
86
+ - lib/generators/rspec/experiment
87
+ - lib/generators/rspec/experiment/experiment_generator.rb
88
+ - lib/generators/rspec/experiment/templates
89
+ - lib/generators/rspec/experiment/templates/experiment_spec.rb.tt
81
90
  - lib/gitlab/experiment.rb
82
- - lib/gitlab/experiment/base_interface.rb
83
- - lib/gitlab/experiment/cache.rb
91
+ - lib/gitlab/experiment
92
+ - lib/gitlab/experiment/variant.rb
93
+ - lib/gitlab/experiment/middleware.rb
94
+ - lib/gitlab/experiment/cache
84
95
  - lib/gitlab/experiment/cache/redis_hash_store.rb
96
+ - lib/gitlab/experiment/errors.rb
85
97
  - lib/gitlab/experiment/callbacks.rb
86
- - lib/gitlab/experiment/configuration.rb
98
+ - lib/gitlab/experiment/rollout.rb
99
+ - lib/gitlab/experiment/base_interface.rb
87
100
  - lib/gitlab/experiment/context.rb
88
- - lib/gitlab/experiment/cookies.rb
89
- - lib/gitlab/experiment/dsl.rb
90
101
  - lib/gitlab/experiment/engine.rb
91
- - lib/gitlab/experiment/errors.rb
92
- - lib/gitlab/experiment/middleware.rb
93
- - lib/gitlab/experiment/rollout.rb
94
- - lib/gitlab/experiment/rollout/percent.rb
102
+ - lib/gitlab/experiment/rspec.rb
103
+ - lib/gitlab/experiment/rollout
95
104
  - lib/gitlab/experiment/rollout/random.rb
96
105
  - lib/gitlab/experiment/rollout/round_robin.rb
97
- - lib/gitlab/experiment/rspec.rb
98
- - lib/gitlab/experiment/variant.rb
106
+ - lib/gitlab/experiment/rollout/percent.rb
107
+ - lib/gitlab/experiment/cache.rb
99
108
  - lib/gitlab/experiment/version.rb
109
+ - lib/gitlab/experiment/cookies.rb
110
+ - lib/gitlab/experiment/configuration.rb
111
+ - lib/gitlab/experiment/dsl.rb
112
+ - LICENSE.txt
113
+ - README.md
100
114
  homepage: https://gitlab.com/gitlab-org/gitlab-experiment
101
115
  licenses:
102
116
  - MIT
@@ -116,7 +130,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
116
130
  - !ruby/object:Gem::Version
117
131
  version: '0'
118
132
  requirements: []
119
- rubygems_version: 3.2.20
133
+ rubygems_version: 3.1.4
120
134
  signing_key:
121
135
  specification_version: 4
122
136
  summary: GitLab experiment library built on top of scientist.