gitlab-labkit 1.9.0 → 1.10.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ce6ea44972e6b4b1831c66fd9980f6b501d7c517d89e987cd13e54fa8869fd8d
4
- data.tar.gz: e03f282e419b06a8a030eaf5b9215eb99ced4883064c66abbca3ca84f9d452bf
3
+ metadata.gz: ce9130ded76934b6e21e82724c7371548b9e790e451179a7e70cd14f545969d7
4
+ data.tar.gz: 1463999f63f123911a57a45d6943fb68e25daa07338cc2afd49f9592cb71ffb0
5
5
  SHA512:
6
- metadata.gz: 602a91b5315f74bdfd68997e7c5dd7bc4c4ec888fb7ab79e68baa98ca0173b77d59a826bcdb695c492665ef3d3f46e586863ea06274245b0d8047e46297408bd
7
- data.tar.gz: 7d972eaf40419b5b4c33ae4c283a72d496cfc81be35386d16924fc133b9b94f028456bd9e0bfc7f076799239f938dee931b7a7a20c690cabcb4fcab571df8b8a
6
+ metadata.gz: df940f5abe8e939c2bb84440ed9ad340dc2e4a359dddc330d752f778e1d9c7c5aa2a6d19ee233081a7fc0cfd512e7cf5e54ad44fd419d11b2d0f85030ad6fd56
7
+ data.tar.gz: eee7205f950d1c9bf59060d25d0e5e7a196dadc98b521064813014129e022b2e3c9a5adfad68332b4ba1e2b9f75cbe6a6e8625cc228daa9d2976edbc05a31c25
data/.copier-answers.yml CHANGED
@@ -3,7 +3,7 @@
3
3
  # See the project for instructions on how to update the project
4
4
  #
5
5
  # Changes here will be overwritten by Copier; NEVER EDIT MANUALLY
6
- _commit: v1.43.0
6
+ _commit: v1.45.0
7
7
  _src_path: https://gitlab.com/gitlab-com/gl-infra/common-template-copier.git
8
8
  ee_licensed: false
9
9
  golang: false
data/CODEOWNERS CHANGED
@@ -1,4 +1,4 @@
1
1
  # CODEOWNERS is used to lookup assignees for
2
2
  # Renovate Bot dependency change Merge Requests.
3
3
  # https://docs.renovatebot.com/configuration-options/#assigneesfromcodeowners
4
- * @reprazent @andrewn @mkaeppler @ayufan @hmerscher @d.barrett @splattael
4
+ * @reprazent @andrewn @mkaeppler @ayufan @hmerscher @d.barrett @splattael @e_forbes @M_Alvarez
@@ -74,15 +74,6 @@ expect { subject }.to complete_user_experience('rails_request', error: true, suc
74
74
  expect { subject }.not_to complete_user_experience('rails_request')
75
75
  ```
76
76
 
77
- ### Legacy Matchers (Backward Compatibility)
78
-
79
- For backward compatibility, the following legacy matchers are still available but deprecated. Please migrate to the new `*_user_experience` matchers above.
80
-
81
- - `start_covered_experience`
82
- - `checkpoint_covered_experience`
83
- - `resume_covered_experience`
84
- - `complete_covered_experience`
85
-
86
77
  ## Example Usage
87
78
 
88
79
  ### In your spec_helper.rb or rails_helper.rb:
@@ -203,6 +203,59 @@ RSpec::Matchers.define :complete_user_experience do |user_experience_id, error:
203
203
  end
204
204
  end
205
205
 
206
+ # Matcher for verifying UserExperience observed metrics instrumentation.
207
+ #
208
+ # Usage:
209
+ # expect { subject }.to observed_user_experience('rails_request')
210
+ #
211
+ # This matcher verifies that the following metrics are incremented with specific labels:
212
+ # - gitlab_user_experience_checkpoint_total (with checkpoint=start)
213
+ # - gitlab_user_experience_checkpoint_total (with checkpoint=end)
214
+ # - gitlab_user_experience_total (with error=false)
215
+ # - gitlab_user_experience_apdex_total (with success=true)
216
+ #
217
+ # Parameters:
218
+ # - user_experience_id: Required. The ID of the user experience (e.g., 'rails_request')
219
+ # - error: Optional. The expected error flag for gitlab_user_experience_total (false by default)
220
+ # - success: Optional. The expected success flag for gitlab_user_experience_apdex_total (true by default)
221
+ RSpec::Matchers.define :observed_user_experience do |user_experience_id, error: false, success: true|
222
+ include Labkit::RSpec::Matchers::UserExperience
223
+
224
+ description { "observe user experience '#{user_experience_id}'" }
225
+ supports_block_expectations
226
+
227
+ match do |actual|
228
+ labels = attributes(user_experience_id)
229
+
230
+ start_before = checkpoint_counter&.get(labels.merge(checkpoint: "start")).to_i
231
+ end_before = checkpoint_counter&.get(labels.merge(checkpoint: "end")).to_i
232
+ total_before = total_counter&.get(labels.merge(error: error)).to_i
233
+ apdex_before = apdex_counter&.get(labels.merge(success: success)).to_i
234
+
235
+ actual.call
236
+
237
+ start_after = checkpoint_counter&.get(labels.merge(checkpoint: "start")).to_i
238
+ end_after = checkpoint_counter&.get(labels.merge(checkpoint: "end")).to_i
239
+ total_after = total_counter&.get(labels.merge(error: error)).to_i
240
+ apdex_after = apdex_counter&.get(labels.merge(success: success)).to_i
241
+
242
+ @start_change = start_after - start_before
243
+ @end_change = end_after - end_before
244
+ @total_change = total_after - total_before
245
+ @apdex_change = apdex_after - apdex_before
246
+
247
+ @start_change == 1 && @end_change == 1 && @total_change == 1 && @apdex_change == (error ? 0 : 1)
248
+ end
249
+
250
+ failure_message do
251
+ "Failed to observe user experience '#{user_experience_id}':\n" \
252
+ "expected checkpoint='start' counter to increase by 1, but increased by #{@start_change}\n" \
253
+ "expected checkpoint='end' counter to increase by 1, but increased by #{@end_change}\n" \
254
+ "expected total='error: #{error}' counter to increase by 1, but increased by #{@total_change}\n" \
255
+ "expected apdex='success: #{success}' counter to increase by #{error ? 0 : 1}, but increased by #{@apdex_change}"
256
+ end
257
+ end
258
+
206
259
  # Backward compatibility matchers for CoveredExperience
207
260
  RSpec::Matchers.alias_matcher :start_covered_experience, :start_user_experience
208
261
  RSpec::Matchers.alias_matcher :checkpoint_covered_experience, :checkpoint_user_experience
@@ -161,6 +161,26 @@ experience.checkpoint
161
161
  experience.complete
162
162
  ```
163
163
 
164
+ #### Observing a Past Experience
165
+
166
+ When an action already happened and you want to record its duration retroactively, use `observed`. It fires the start and end metrics without registering in the active context:
167
+
168
+ ```ruby
169
+ Labkit::UserExperienceSli.observed('merge_request_creation', start_time: start_time_of_past_action)
170
+ ```
171
+
172
+ You can also signal that an error occurred during the action:
173
+
174
+ ```ruby
175
+ Labkit::UserExperienceSli.observed('merge_request_creation', start_time: start_time_of_past_action, error: true)
176
+ ```
177
+
178
+ Extra labels are forwarded to both the start and end log events:
179
+
180
+ ```ruby
181
+ Labkit::UserExperienceSli.observed('merge_request_creation', start_time: start_time_of_past_action, worker: 'MyWorker')
182
+ ```
183
+
164
184
  #### Resuming Experiences
165
185
 
166
186
  You can resume a user experience SLI that was previously started and stored in the context. This is useful for distributed operations or when work spans multiple processes.
@@ -135,6 +135,28 @@ module Labkit
135
135
  self
136
136
  end
137
137
 
138
+ # Records a past User Experience by its duration.
139
+ #
140
+ # @param start_time [Time] The time when the experience started.
141
+ # @param error [Boolean] Whether the experience ended in an error.
142
+ # @param extra [Hash] Additional data to include in the log events.
143
+ # @return [self]
144
+ def observed(start_time:, error: false, **extra)
145
+ @start_time = start_time.utc
146
+ @end_time = Time.now.utc
147
+ error!("observed_error") if error
148
+
149
+ checkpoint_counter.increment(checkpoint: "start", **base_labels)
150
+ log_event("start", **extra)
151
+
152
+ checkpoint_counter.increment(checkpoint: "end", **base_labels)
153
+ total_counter.increment(error: has_error?, **base_labels)
154
+ apdex_counter.increment(success: apdex_success?, **base_labels) unless has_error?
155
+ log_event("end", **extra)
156
+
157
+ self
158
+ end
159
+
138
160
  # Marks the experience as failed with an error
139
161
  #
140
162
  # @param error [StandardError, String] The error that caused the experience to fail.
@@ -20,6 +20,7 @@ module Labkit
20
20
  self
21
21
  end
22
22
 
23
+ def observed(**_kwargs) = self
23
24
  def push_attributes!(*_args) = self
24
25
  def checkpoint(*_args) = self
25
26
  def complete(*_args) = self
@@ -77,7 +77,7 @@ module Labkit
77
77
  reset_configuration
78
78
  end
79
79
 
80
- # Retrieves a covered experience using the experience_id.
80
+ # Retrieves a user experience using the experience_id.
81
81
  # It retrieves from the current context when available,
82
82
  # otherwise it instantiates a new experience with the definition
83
83
  # from the registry.
@@ -88,7 +88,7 @@ module Labkit
88
88
  find_current(experience_id) || raise_or_null(experience_id)
89
89
  end
90
90
 
91
- # Starts a covered experience using the experience_id.
91
+ # Starts a user experience using the experience_id.
92
92
  #
93
93
  # @param experience_id [String, Symbol] The ID of the experience to start.
94
94
  # @param extra [Hash] Additional data to include in the log event.
@@ -97,7 +97,19 @@ module Labkit
97
97
  get(experience_id).start(**extra, &)
98
98
  end
99
99
 
100
- # Resumes a covered experience using the experience_id.
100
+ # Records a past user experience by its duration atomically.
101
+ #
102
+ # @param experience_id [String, Symbol] The ID of the experience.
103
+ # @param start_time [Time] The time when the experience started.
104
+ # @param extra [Hash] Additional data to include in the log events.
105
+ # @return [Experience, Null] The observed experience or a Null object if not found (in production/staging).
106
+ def observed(experience_id, start_time:, **extra)
107
+ definition = registry[experience_id]
108
+ experience = definition ? Experience.new(definition) : raise_or_null(experience_id)
109
+ experience.observed(start_time: start_time, **extra)
110
+ end
111
+
112
+ # Resumes a user experience using the experience_id.
101
113
  #
102
114
  # @param experience_id [String, Symbol] The ID of the experience to resume.
103
115
  # @return [Experience, Null] The started experience or a Null object if not found (in production/staging).
@@ -54,6 +54,7 @@ fi
54
54
  # install mise/asdf dependencies
55
55
  echo "installing required plugins with mise install.."
56
56
  mise plugins update -q
57
+ mise trust
57
58
  mise install
58
59
 
59
60
  # set PROMPT_COMMAND to empty value for mise if unset
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab-labkit
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.0
4
+ version: 1.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Newdigate