fastlane-plugin-sentry_api 0.1.0 → 0.2.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.
@@ -5,6 +5,7 @@ module Fastlane
5
5
  module Actions
6
6
  module SharedValues
7
7
  SENTRY_TTID_DATA = :SENTRY_TTID_DATA
8
+ SENTRY_TTID_OVERALL = :SENTRY_TTID_OVERALL
8
9
  SENTRY_TTID_STATUS_CODE = :SENTRY_TTID_STATUS_CODE
9
10
  SENTRY_TTID_JSON = :SENTRY_TTID_JSON
10
11
  end
@@ -47,6 +48,24 @@ module Fastlane
47
48
  UI.message(" #{screen[:transaction]}: p50=#{screen[:p50]}ms p75=#{screen[:p75]}ms p95=#{screen[:p95]}ms (#{screen[:count]} loads)")
48
49
  end
49
50
 
51
+ # Fetch overall/aggregate TTID when requested
52
+ if params[:include_overall]
53
+ overall_params = build_overall_query_params(params, project_id)
54
+ overall_response = Helper::SentryApiHelper.get_events(
55
+ auth_token: auth_token,
56
+ org_slug: org_slug,
57
+ params: overall_params
58
+ )
59
+
60
+ if overall_response[:status].between?(200, 299)
61
+ overall = parse_overall_response(overall_response[:json])
62
+ Actions.lane_context[SharedValues::SENTRY_TTID_OVERALL] = overall
63
+ UI.success("Overall TTID: p50=#{overall[:p50]}ms p75=#{overall[:p75]}ms p95=#{overall[:p95]}ms (#{overall[:count]} loads)")
64
+ else
65
+ UI.error("Failed to fetch overall TTID: #{overall_response[:status]}")
66
+ end
67
+ end
68
+
50
69
  result
51
70
  end
52
71
 
@@ -74,75 +93,81 @@ module Fastlane
74
93
  def available_options
75
94
  [
76
95
  FastlaneCore::ConfigItem.new(key: :auth_token,
77
- env_name: "SENTRY_AUTH_TOKEN",
78
- description: "Sentry API Bearer auth token",
79
- optional: false,
96
+ env_name: "SENTRY_AUTH_TOKEN",
97
+ description: "Sentry API Bearer auth token",
98
+ optional: false,
80
99
  type: String,
81
- sensitive: true,
82
- code_gen_sensitive: true,
83
- verify_block: proc do |value|
84
- UI.user_error!("No Sentry auth token given, pass using `auth_token: 'token'`") if value.to_s.empty?
85
- end),
100
+ sensitive: true,
101
+ code_gen_sensitive: true,
102
+ verify_block: proc do |value|
103
+ UI.user_error!("No Sentry auth token given, pass using `auth_token: 'token'`") if value.to_s.empty?
104
+ end),
86
105
  FastlaneCore::ConfigItem.new(key: :org_slug,
87
- env_name: "SENTRY_ORG_SLUG",
88
- description: "Sentry organization slug",
89
- optional: false,
106
+ env_name: "SENTRY_ORG_SLUG",
107
+ description: "Sentry organization slug",
108
+ optional: false,
90
109
  type: String,
91
- verify_block: proc do |value|
92
- UI.user_error!("No Sentry org slug given, pass using `org_slug: 'my-org'`") if value.to_s.empty?
93
- end),
110
+ verify_block: proc do |value|
111
+ UI.user_error!("No Sentry org slug given, pass using `org_slug: 'my-org'`") if value.to_s.empty?
112
+ end),
94
113
  FastlaneCore::ConfigItem.new(key: :project_id,
95
- env_name: "SENTRY_PROJECT_ID",
96
- description: "Sentry numeric project ID",
97
- optional: false,
114
+ env_name: "SENTRY_PROJECT_ID",
115
+ description: "Sentry numeric project ID",
116
+ optional: false,
98
117
  type: String,
99
- verify_block: proc do |value|
100
- UI.user_error!("No Sentry project ID given, pass using `project_id: '12345'`") if value.to_s.empty?
101
- end),
118
+ verify_block: proc do |value|
119
+ UI.user_error!("No Sentry project ID given, pass using `project_id: '12345'`") if value.to_s.empty?
120
+ end),
102
121
  FastlaneCore::ConfigItem.new(key: :environment,
103
- env_name: "SENTRY_ENVIRONMENT",
104
- description: "Environment filter (e.g. 'production')",
105
- optional: true,
106
- default_value: "production",
122
+ env_name: "SENTRY_ENVIRONMENT",
123
+ description: "Environment filter (e.g. 'production')",
124
+ optional: true,
125
+ default_value: "production",
107
126
  type: String),
108
127
  FastlaneCore::ConfigItem.new(key: :stats_period,
109
- description: "Rolling time window (e.g. '7d', '14d', '30d')",
110
- optional: true,
111
- default_value: "7d",
128
+ description: "Rolling time window (e.g. '7d', '14d', '30d')",
129
+ optional: true,
130
+ default_value: "7d",
112
131
  type: String),
113
132
  FastlaneCore::ConfigItem.new(key: :start_date,
114
- description: "Start date in ISO 8601 format. Use with end_date instead of stats_period",
115
- optional: true,
133
+ description: "Start date in ISO 8601 format. Use with end_date instead of stats_period",
134
+ optional: true,
116
135
  type: String),
117
136
  FastlaneCore::ConfigItem.new(key: :end_date,
118
- description: "End date in ISO 8601 format. Use with start_date instead of stats_period",
119
- optional: true,
137
+ description: "End date in ISO 8601 format. Use with start_date instead of stats_period",
138
+ optional: true,
120
139
  type: String),
121
140
  FastlaneCore::ConfigItem.new(key: :release,
122
- description: "Filter by specific release version",
123
- optional: true,
141
+ description: "Filter by specific release version",
142
+ optional: true,
124
143
  type: String),
125
144
  FastlaneCore::ConfigItem.new(key: :transaction_op,
126
- description: "Transaction operation filter (e.g. 'ui.load', 'ui.action')",
127
- optional: true,
128
- default_value: "ui.load",
145
+ description: "Transaction operation filter (e.g. 'ui.load', 'ui.action')",
146
+ optional: true,
147
+ default_value: "ui.load",
129
148
  type: String),
130
149
  FastlaneCore::ConfigItem.new(key: :per_page,
131
- description: "Number of screens to return (max 100)",
132
- optional: true,
133
- default_value: 20,
150
+ description: "Number of screens to return (max 100)",
151
+ optional: true,
152
+ default_value: 20,
134
153
  type: Integer),
135
154
  FastlaneCore::ConfigItem.new(key: :sort,
136
- description: "Sort order (e.g. '-count()', '-p95(measurements.time_to_initial_display)')",
137
- optional: true,
138
- default_value: "-count()",
139
- type: String)
155
+ description: "Sort order (e.g. '-count()', '-p95(measurements.time_to_initial_display)')",
156
+ optional: true,
157
+ default_value: "-count()",
158
+ type: String),
159
+ FastlaneCore::ConfigItem.new(key: :include_overall,
160
+ description: "Also fetch overall/aggregate TTID percentiles across all screens",
161
+ optional: true,
162
+ default_value: false,
163
+ type: Fastlane::Boolean)
140
164
  ]
141
165
  end
142
166
 
143
167
  def output
144
168
  [
145
169
  ['SENTRY_TTID_DATA', 'Array of hashes with :transaction, :p50, :p75, :p95, :count per screen'],
170
+ ['SENTRY_TTID_OVERALL', 'Hash with :p50, :p75, :p95, :count for overall aggregate TTID (when include_overall is true)'],
146
171
  ['SENTRY_TTID_STATUS_CODE', 'HTTP status code from the Sentry API'],
147
172
  ['SENTRY_TTID_JSON', 'Raw JSON response from the Sentry API']
148
173
  ]
@@ -217,6 +242,48 @@ module Fastlane
217
242
  query_params
218
243
  end
219
244
 
245
+ def build_overall_query_params(params, project_id)
246
+ fields = [
247
+ 'p50(measurements.time_to_initial_display)',
248
+ 'p75(measurements.time_to_initial_display)',
249
+ 'p95(measurements.time_to_initial_display)',
250
+ 'count()'
251
+ ]
252
+
253
+ query_parts = ['event.type:transaction']
254
+ query_parts << "transaction.op:#{params[:transaction_op]}" if params[:transaction_op]
255
+ query_parts << "release:#{params[:release]}" if params[:release]
256
+
257
+ query_params = {
258
+ dataset: 'metrics',
259
+ field: fields,
260
+ project: project_id.to_s,
261
+ query: query_parts.join(' '),
262
+ per_page: '1'
263
+ }
264
+
265
+ if params[:start_date] && params[:end_date]
266
+ query_params[:start] = params[:start_date]
267
+ query_params[:end] = params[:end_date]
268
+ else
269
+ query_params[:statsPeriod] = params[:stats_period] || '7d'
270
+ end
271
+
272
+ query_params[:environment] = params[:environment] if params[:environment]
273
+
274
+ query_params
275
+ end
276
+
277
+ def parse_overall_response(json)
278
+ row = json&.dig('data', 0) || {}
279
+ {
280
+ p50: round_ms(row['p50(measurements.time_to_initial_display)']),
281
+ p75: round_ms(row['p75(measurements.time_to_initial_display)']),
282
+ p95: round_ms(row['p95(measurements.time_to_initial_display)']),
283
+ count: row['count()']
284
+ }
285
+ end
286
+
220
287
  def parse_response(json)
221
288
  data = json&.dig('data') || []
222
289
 
@@ -92,7 +92,7 @@ module Fastlane
92
92
  params.each do |key, value|
93
93
  next if value.nil?
94
94
 
95
- if value.is_a?(Array)
95
+ if value.kind_of?(Array)
96
96
  value.each { |v| pairs << [key.to_s, v.to_s] }
97
97
  else
98
98
  pairs << [key.to_s, value.to_s]
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module SentryApi
3
- VERSION = "0.1.0"
3
+ VERSION = "0.2.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastlane-plugin-sentry_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - crazymanish
@@ -18,6 +18,7 @@ files:
18
18
  - README.md
19
19
  - lib/fastlane/plugin/sentry_api.rb
20
20
  - lib/fastlane/plugin/sentry_api/actions/sentry_api_action.rb
21
+ - lib/fastlane/plugin/sentry_api/actions/sentry_app_launch_action.rb
21
22
  - lib/fastlane/plugin/sentry_api/actions/sentry_crash_free_sessions_action.rb
22
23
  - lib/fastlane/plugin/sentry_api/actions/sentry_crash_free_users_action.rb
23
24
  - lib/fastlane/plugin/sentry_api/actions/sentry_list_issues_action.rb