raider_reporter 0.5.1 → 0.6.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/CHANGELOG.md +6 -0
- data/README.md +1 -1
- data/lib/raider_reporter/app_frame.rb +57 -0
- data/lib/raider_reporter/cucumber/formatter.rb +8 -1
- data/lib/raider_reporter/models.rb +5 -1
- data/lib/raider_reporter/payload.rb +3 -1
- data/lib/raider_reporter/rspec/formatter.rb +17 -1
- data/lib/raider_reporter/version.rb +1 -1
- data/lib/raider_reporter.rb +4 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e5bb1cd462fbac0bd6a44635be2b0e14f6da29667e6cb4cf0a5f358aed7581be
|
|
4
|
+
data.tar.gz: c814a3009d7e7e6ac0857bc34636ad1fdc913d3e3489ff64c3e5b62cd7f50dbb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a1064490905e372f3392d056343cc3b8304d1de127e785d122e5ef6e3c50622873583f7ceedece6f87bbf633d8fbe4e2b94a0111f3d325ff98ba6280ba84e75c
|
|
7
|
+
data.tar.gz: a91849038df0a28f54023e411d4115636ce97e1aa6a4ad83ec03a298f7f87e438e0b94583a6248e568c8c14af9c9176e813ddb0b287962e5ebd2021737a8748d
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.0 — 2026-10-14
|
|
4
|
+
|
|
5
|
+
- Schema v1, additive: optional `failure.app_frame`, the first line of the raw exception backtrace that lies inside the project root (`Dir.pwd` when the reporter starts), outside `vendor/`, `.bundle/`, `Gem.path` and Ruby's library directory, and not `<internal:...>`. The path is made project-relative and the rest of the line is unchanged, e.g. `spec/pages/login_page.rb:42:in 'LoginPage#submit'`; at most 500 characters. The key is omitted when no line qualifies or computing it fails, so payloads without it are unchanged. Raider uses it to group failures by error
|
|
6
|
+
- Reported by both the RSpec and Cucumber reporters
|
|
7
|
+
- No breaking changes
|
|
8
|
+
|
|
3
9
|
## 0.5.1 — 2026-10-13
|
|
4
10
|
|
|
5
11
|
- Fix: a failed upload now reports one short line. An HTML error page (for example a server 500) is summarised as `the server returned an HTML error page` instead of being printed, other bodies are collapsed to one line of at most 200 characters, and the token is redacted from upload errors, including exception messages
|
data/README.md
CHANGED
|
@@ -305,7 +305,7 @@ Tip: run `rm -rf raider-results` before a parallel run. Each process only cleans
|
|
|
305
305
|
|
|
306
306
|
## Schema
|
|
307
307
|
|
|
308
|
-
`run.json` follows schema v1, documented in [docs/schema-v1.md](docs/schema-v1.md). Statuses are exactly `passed`, `failed`, `pending` and `skipped`.
|
|
308
|
+
`run.json` follows schema v1, documented in [docs/schema-v1.md](docs/schema-v1.md). Statuses are exactly `passed`, `failed`, `pending` and `skipped`. In both RSpec and Cucumber, a failure may carry `app_frame` (when a project frame is found): the first backtrace line inside your project, for example `spec/pages/login_page.rb:42:in 'LoginPage#submit'`, which Raider uses to group failures with the same error.
|
|
309
309
|
|
|
310
310
|
## Contributing
|
|
311
311
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rbconfig"
|
|
4
|
+
|
|
5
|
+
module RaiderReporter
|
|
6
|
+
# Finds the first project frame of a raw backtrace, so the server can group
|
|
7
|
+
# failures by where the project's own code raised them.
|
|
8
|
+
module AppFrame
|
|
9
|
+
MAX_LENGTH = 500
|
|
10
|
+
|
|
11
|
+
# Returns "relative/path.rb:42:in 'Class#method'" or nil when no line
|
|
12
|
+
# of the backtrace lies in project code.
|
|
13
|
+
def self.from(backtrace, root:)
|
|
14
|
+
return nil if backtrace.nil? || backtrace.empty? || root.nil?
|
|
15
|
+
|
|
16
|
+
base = "#{File.expand_path(root.to_s).chomp("/")}/"
|
|
17
|
+
excluded = excluded_prefixes
|
|
18
|
+
Array(backtrace).each do |line|
|
|
19
|
+
line = line.to_s
|
|
20
|
+
path = line[/\A(.+?):\d+/, 1]
|
|
21
|
+
next if path.nil? || path.start_with?("<internal:", "(", "-")
|
|
22
|
+
|
|
23
|
+
absolute = File.expand_path(path, base)
|
|
24
|
+
next unless File.file?(absolute)
|
|
25
|
+
|
|
26
|
+
absolute = inside_root(absolute, base)
|
|
27
|
+
next unless absolute
|
|
28
|
+
next if excluded.any? { |prefix| absolute.start_with?(prefix) }
|
|
29
|
+
|
|
30
|
+
relative = absolute.delete_prefix(base)
|
|
31
|
+
next if relative.start_with?("vendor/", ".bundle/") || relative.include?("/.bundle/")
|
|
32
|
+
|
|
33
|
+
return Text.utf8("#{relative}#{line[path.length..]}")[0, MAX_LENGTH]
|
|
34
|
+
end
|
|
35
|
+
nil
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Returns the path (rewritten under base when only the real paths match,
|
|
39
|
+
# e.g. a symlinked tmpdir) or nil when it lies outside the root.
|
|
40
|
+
def self.inside_root(absolute, base)
|
|
41
|
+
return absolute if absolute.start_with?(base)
|
|
42
|
+
|
|
43
|
+
real_base = "#{File.realpath(base)}/"
|
|
44
|
+
real = File.realpath(absolute)
|
|
45
|
+
real.start_with?(real_base) ? "#{base}#{real.delete_prefix(real_base)}" : nil
|
|
46
|
+
rescue SystemCallError
|
|
47
|
+
nil
|
|
48
|
+
end
|
|
49
|
+
private_class_method :inside_root
|
|
50
|
+
|
|
51
|
+
def self.excluded_prefixes
|
|
52
|
+
dirs = Array(Gem.path) + [RbConfig::CONFIG["rubylibdir"]]
|
|
53
|
+
dirs.compact.map(&:to_s).reject(&:empty?).map { |dir| "#{File.expand_path(dir).chomp("/")}/" }
|
|
54
|
+
end
|
|
55
|
+
private_class_method :excluded_prefixes
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -199,10 +199,17 @@ module RaiderReporter
|
|
|
199
199
|
Failure.new(
|
|
200
200
|
message: Text.utf8("#{step_label(step_info, test_case)}\n\n#{exception.message}")[0, Text::MAX_MESSAGE],
|
|
201
201
|
exception_class: Text.utf8(exception.class.name),
|
|
202
|
-
backtrace: (exception.backtrace || []).first(Text::MAX_BACKTRACE).map { |line| Text.utf8(line) }
|
|
202
|
+
backtrace: (exception.backtrace || []).first(Text::MAX_BACKTRACE).map { |line| Text.utf8(line) },
|
|
203
|
+
app_frame: app_frame_for(exception)
|
|
203
204
|
)
|
|
204
205
|
end
|
|
205
206
|
|
|
207
|
+
def app_frame_for(exception)
|
|
208
|
+
AppFrame.from(exception.backtrace, root: RaiderReporter.project_root || Dir.pwd)
|
|
209
|
+
rescue StandardError
|
|
210
|
+
nil
|
|
211
|
+
end
|
|
212
|
+
|
|
206
213
|
def step_label(step_info, test_case)
|
|
207
214
|
return "Step" unless step_info
|
|
208
215
|
|
|
@@ -4,7 +4,11 @@ module RaiderReporter
|
|
|
4
4
|
SCHEMA_VERSION = 1
|
|
5
5
|
STATUSES = %w[passed failed pending skipped].freeze
|
|
6
6
|
|
|
7
|
-
Failure = Data.define(:message, :exception_class, :backtrace)
|
|
7
|
+
Failure = Data.define(:message, :exception_class, :backtrace, :app_frame) do
|
|
8
|
+
def initialize(message:, exception_class:, backtrace:, app_frame: nil)
|
|
9
|
+
super
|
|
10
|
+
end
|
|
11
|
+
end
|
|
8
12
|
Attachment = Data.define(:name, :source_path, :content_type)
|
|
9
13
|
TestResult = Data.define(
|
|
10
14
|
:identifier, :full_name, :file_path, :line_number, :status,
|
|
@@ -73,11 +73,13 @@ module RaiderReporter
|
|
|
73
73
|
end
|
|
74
74
|
|
|
75
75
|
def failure_hash(failure)
|
|
76
|
-
{
|
|
76
|
+
hash = {
|
|
77
77
|
"message" => failure.message,
|
|
78
78
|
"exception_class" => failure.exception_class,
|
|
79
79
|
"backtrace" => failure.backtrace
|
|
80
80
|
}
|
|
81
|
+
hash["app_frame"] = failure.app_frame if failure.app_frame
|
|
82
|
+
hash
|
|
81
83
|
end
|
|
82
84
|
|
|
83
85
|
def attachment_hash(entry, mode)
|
|
@@ -74,10 +74,26 @@ module RaiderReporter
|
|
|
74
74
|
Failure.new(
|
|
75
75
|
message: utf8(exception.message)[0, MAX_MESSAGE],
|
|
76
76
|
exception_class: utf8(exception.class.name),
|
|
77
|
-
backtrace: backtrace.first(MAX_BACKTRACE).map { |line| utf8(line) }
|
|
77
|
+
backtrace: backtrace.first(MAX_BACKTRACE).map { |line| utf8(line) },
|
|
78
|
+
app_frame: app_frame_for(exception)
|
|
78
79
|
)
|
|
79
80
|
end
|
|
80
81
|
|
|
82
|
+
# From the raw backtrace: RSpec's formatter strips gem and project-support frames.
|
|
83
|
+
# MultipleExceptionError (aggregate_failures) has no backtrace of its own.
|
|
84
|
+
def raw_backtrace(exception)
|
|
85
|
+
return exception.backtrace if exception.backtrace
|
|
86
|
+
return nil unless exception.respond_to?(:all_exceptions)
|
|
87
|
+
|
|
88
|
+
exception.all_exceptions.first&.backtrace
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def app_frame_for(exception)
|
|
92
|
+
AppFrame.from(raw_backtrace(exception), root: RaiderReporter.project_root || Dir.pwd)
|
|
93
|
+
rescue StandardError
|
|
94
|
+
nil
|
|
95
|
+
end
|
|
96
|
+
|
|
81
97
|
def utf8(value)
|
|
82
98
|
Text.utf8(value)
|
|
83
99
|
end
|
data/lib/raider_reporter.rb
CHANGED
|
@@ -5,6 +5,7 @@ require "rbconfig"
|
|
|
5
5
|
require_relative "raider_reporter/version"
|
|
6
6
|
require_relative "raider_reporter/text"
|
|
7
7
|
require_relative "raider_reporter/models"
|
|
8
|
+
require_relative "raider_reporter/app_frame"
|
|
8
9
|
require_relative "raider_reporter/payload"
|
|
9
10
|
require_relative "raider_reporter/configuration"
|
|
10
11
|
require_relative "raider_reporter/content_types"
|
|
@@ -19,7 +20,7 @@ require_relative "raider_reporter/comment/azure_client"
|
|
|
19
20
|
|
|
20
21
|
module RaiderReporter
|
|
21
22
|
class << self
|
|
22
|
-
attr_reader :collector
|
|
23
|
+
attr_reader :collector, :project_root
|
|
23
24
|
|
|
24
25
|
def configuration
|
|
25
26
|
@configuration ||= Configuration.new
|
|
@@ -37,10 +38,12 @@ module RaiderReporter
|
|
|
37
38
|
@collector&.cleanup
|
|
38
39
|
@configuration = nil
|
|
39
40
|
@collector = nil
|
|
41
|
+
@project_root = nil
|
|
40
42
|
end
|
|
41
43
|
|
|
42
44
|
def start_collector!
|
|
43
45
|
@dry_run = false
|
|
46
|
+
@project_root = Dir.pwd
|
|
44
47
|
@collector = Collector.new(
|
|
45
48
|
max_attachment_bytes: configuration.max_attachment_bytes,
|
|
46
49
|
warn: ->(message) { warn(message) }
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: raider_reporter
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Augustin Gottlieb
|
|
@@ -24,6 +24,7 @@ files:
|
|
|
24
24
|
- README.md
|
|
25
25
|
- exe/raider-reporter
|
|
26
26
|
- lib/raider_reporter.rb
|
|
27
|
+
- lib/raider_reporter/app_frame.rb
|
|
27
28
|
- lib/raider_reporter/azure_env.rb
|
|
28
29
|
- lib/raider_reporter/ci_detector.rb
|
|
29
30
|
- lib/raider_reporter/cli.rb
|