saboteur 0.2.0 → 0.4.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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +153 -1
  3. data/README.md +526 -73
  4. data/lib/generators/saboteur/install/install_generator.rb +21 -0
  5. data/lib/saboteur/agent_skill.rb +40 -0
  6. data/lib/saboteur/baseline_health.rb +116 -0
  7. data/lib/saboteur/cli.rb +305 -30
  8. data/lib/saboteur/config.rb +65 -19
  9. data/lib/saboteur/config_file.rb +97 -0
  10. data/lib/saboteur/custom_map.rb +170 -0
  11. data/lib/saboteur/doctor.rb +88 -0
  12. data/lib/saboteur/engine/baseline_guard.rb +116 -0
  13. data/lib/saboteur/engine/boot.rb +9 -0
  14. data/lib/saboteur/engine/candidate_selection.rb +35 -0
  15. data/lib/saboteur/engine/coverage_store.rb +40 -6
  16. data/lib/saboteur/engine/data_inputs.rb +43 -0
  17. data/lib/saboteur/engine/diagnostics.rb +28 -0
  18. data/lib/saboteur/engine/diff_scope.rb +8 -0
  19. data/lib/saboteur/engine/distribution.rb +4 -2
  20. data/lib/saboteur/engine/run_fingerprint.rb +344 -0
  21. data/lib/saboteur/engine/scheduler.rb +7 -16
  22. data/lib/saboteur/engine/suite_files.rb +8 -1
  23. data/lib/saboteur/engine/verdict_check.rb +4 -2
  24. data/lib/saboteur/engine.rb +125 -25
  25. data/lib/saboteur/execution/fork_readiness.rb +46 -0
  26. data/lib/saboteur/execution/reevaluator.rb +7 -4
  27. data/lib/saboteur/execution/supervisor.rb +23 -11
  28. data/lib/saboteur/frameworks/rails.rb +329 -13
  29. data/lib/saboteur/help.rb +210 -0
  30. data/lib/saboteur/ignore_list.rb +71 -17
  31. data/lib/saboteur/install.rb +132 -0
  32. data/lib/saboteur/integration/base.rb +8 -0
  33. data/lib/saboteur/integration/rspec.rb +69 -4
  34. data/lib/saboteur/mutation_source/argument_removal.rb +86 -0
  35. data/lib/saboteur/mutation_source/builtin.rb +14 -3
  36. data/lib/saboteur/mutation_source/filter_replacement.rb +60 -0
  37. data/lib/saboteur/mutation_source/literal_replacement.rb +74 -0
  38. data/lib/saboteur/mutation_source/pair_removal.rb +101 -0
  39. data/lib/saboteur/replay.rb +33 -0
  40. data/lib/saboteur/reporter/agent.rb +87 -0
  41. data/lib/saboteur/reporter/agent_clipping.rb +29 -0
  42. data/lib/saboteur/reporter/agent_commands.rb +61 -0
  43. data/lib/saboteur/reporter/agent_incomplete.rb +37 -0
  44. data/lib/saboteur/reporter/agent_summary.rb +131 -0
  45. data/lib/saboteur/reporter/findings.rb +131 -0
  46. data/lib/saboteur/reporter/html.rb +213 -0
  47. data/lib/saboteur/reporter/replay.rb +23 -0
  48. data/lib/saboteur/reporter/stryker.rb +21 -4
  49. data/lib/saboteur/reporter/terminal.rb +76 -2
  50. data/lib/saboteur/result.rb +61 -9
  51. data/lib/saboteur/score.rb +89 -0
  52. data/lib/saboteur/version.rb +1 -1
  53. data/lib/saboteur/working_tree.rb +48 -0
  54. data/lib/saboteur.rb +7 -0
  55. metadata +30 -2
@@ -0,0 +1,48 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # frozen_string_literal: true
3
+
4
+ require "open3"
5
+
6
+ module Saboteur
7
+ # The state of the working source a run looked at: the commit it was on and
8
+ # (the full SHA) and whether files differed from it, tracked changes and each
9
+ # untracked file alike.
10
+ # Saboteur's own output (cache and reports) is passed in as ignored paths, so a
11
+ # report from an earlier run does not make the tree look dirty. Without git, or
12
+ # outside a repository, the state is unknown.
13
+ class WorkingTree
14
+ State = Data.define(:head, :dirty, :changed_files) do
15
+ def label
16
+ return "unknown" if dirty.nil?
17
+
18
+ dirty ? "dirty" : "clean"
19
+ end
20
+ end
21
+
22
+ UNKNOWN = State.new(head: nil, dirty: nil, changed_files: nil)
23
+
24
+ # ignored: paths relative to root that are not source (saboteur's cache and reports).
25
+ def initialize(root, ignored: [])
26
+ @root = root
27
+ @ignored = ignored
28
+ end
29
+
30
+ def state
31
+ head, head_status = Open3.capture2e("git", "rev-parse", "HEAD", chdir: @root)
32
+ changes, changes_status = Open3.capture2e(*status_command, chdir: @root)
33
+ return UNKNOWN unless head_status.success? && changes_status.success?
34
+
35
+ count = changes.lines.size
36
+ State.new(head: head.strip, dirty: count.positive?, changed_files: count)
37
+ rescue SystemCallError
38
+ UNKNOWN
39
+ end
40
+
41
+ private
42
+
43
+ def status_command
44
+ excluded = @ignored.map { |path| ":(exclude)#{path}" }
45
+ ["git", "status", "--porcelain", "--untracked-files=all", "--", ".", *excluded]
46
+ end
47
+ end
48
+ end
data/lib/saboteur.rb CHANGED
@@ -38,14 +38,21 @@ require_relative "saboteur/execution/supervisor"
38
38
  require_relative "saboteur/execution/reevaluator"
39
39
  require_relative "saboteur/execution/runner"
40
40
  require_relative "saboteur/execution/worker_pool"
41
+ require_relative "saboteur/execution/fork_readiness"
41
42
  require_relative "saboteur/selection/coverage_map"
42
43
  require_relative "saboteur/selection/recorder"
43
44
  require_relative "saboteur/selection/git_diff"
44
45
  require_relative "saboteur/result"
46
+ require_relative "saboteur/custom_map"
45
47
  require_relative "saboteur/config"
46
48
  require_relative "saboteur/ignore_list"
47
49
  require_relative "saboteur/frameworks/rails"
48
50
  require_relative "saboteur/reporter/diff"
51
+ require_relative "saboteur/reporter/findings"
52
+ require_relative "saboteur/reporter/agent"
53
+ require_relative "saboteur/working_tree"
54
+ require_relative "saboteur/agent_skill"
49
55
  require_relative "saboteur/reporter/terminal"
50
56
  require_relative "saboteur/reporter/stryker"
57
+ require_relative "saboteur/reporter/html"
51
58
  require_relative "saboteur/engine"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: saboteur
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vamsi Pavan Mahesh Gunturu
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-10-10 00:00:00.000000000 Z
11
+ date: 2026-10-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fiddle
@@ -58,21 +58,32 @@ files:
58
58
  - LICENSE
59
59
  - README.md
60
60
  - exe/saboteur
61
+ - lib/generators/saboteur/install/install_generator.rb
61
62
  - lib/saboteur.rb
63
+ - lib/saboteur/agent_skill.rb
64
+ - lib/saboteur/baseline_health.rb
62
65
  - lib/saboteur/cli.rb
63
66
  - lib/saboteur/config.rb
67
+ - lib/saboteur/config_file.rb
68
+ - lib/saboteur/custom_map.rb
69
+ - lib/saboteur/doctor.rb
64
70
  - lib/saboteur/engine.rb
71
+ - lib/saboteur/engine/baseline_guard.rb
65
72
  - lib/saboteur/engine/boot.rb
73
+ - lib/saboteur/engine/candidate_selection.rb
66
74
  - lib/saboteur/engine/candidates.rb
67
75
  - lib/saboteur/engine/coverage_store.rb
76
+ - lib/saboteur/engine/data_inputs.rb
68
77
  - lib/saboteur/engine/diagnostics.rb
69
78
  - lib/saboteur/engine/diff_scope.rb
70
79
  - lib/saboteur/engine/distribution.rb
71
80
  - lib/saboteur/engine/result_cache.rb
81
+ - lib/saboteur/engine/run_fingerprint.rb
72
82
  - lib/saboteur/engine/scheduler.rb
73
83
  - lib/saboteur/engine/subject_selection.rb
74
84
  - lib/saboteur/engine/suite_files.rb
75
85
  - lib/saboteur/engine/verdict_check.rb
86
+ - lib/saboteur/execution/fork_readiness.rb
76
87
  - lib/saboteur/execution/process_table.rb
77
88
  - lib/saboteur/execution/process_tree.rb
78
89
  - lib/saboteur/execution/protocol.rb
@@ -81,24 +92,41 @@ files:
81
92
  - lib/saboteur/execution/supervisor.rb
82
93
  - lib/saboteur/execution/worker_pool.rb
83
94
  - lib/saboteur/frameworks/rails.rb
95
+ - lib/saboteur/help.rb
84
96
  - lib/saboteur/hooks.rb
85
97
  - lib/saboteur/ignore_list.rb
98
+ - lib/saboteur/install.rb
86
99
  - lib/saboteur/integration/base.rb
87
100
  - lib/saboteur/integration/rspec.rb
101
+ - lib/saboteur/mutation_source/argument_removal.rb
88
102
  - lib/saboteur/mutation_source/base.rb
89
103
  - lib/saboteur/mutation_source/builtin.rb
90
104
  - lib/saboteur/mutation_source/edit.rb
105
+ - lib/saboteur/mutation_source/filter_replacement.rb
106
+ - lib/saboteur/mutation_source/literal_replacement.rb
91
107
  - lib/saboteur/mutation_source/mutation.rb
108
+ - lib/saboteur/mutation_source/pair_removal.rb
109
+ - lib/saboteur/replay.rb
110
+ - lib/saboteur/reporter/agent.rb
111
+ - lib/saboteur/reporter/agent_clipping.rb
112
+ - lib/saboteur/reporter/agent_commands.rb
113
+ - lib/saboteur/reporter/agent_incomplete.rb
114
+ - lib/saboteur/reporter/agent_summary.rb
92
115
  - lib/saboteur/reporter/diff.rb
116
+ - lib/saboteur/reporter/findings.rb
117
+ - lib/saboteur/reporter/html.rb
118
+ - lib/saboteur/reporter/replay.rb
93
119
  - lib/saboteur/reporter/stryker.rb
94
120
  - lib/saboteur/reporter/terminal.rb
95
121
  - lib/saboteur/result.rb
122
+ - lib/saboteur/score.rb
96
123
  - lib/saboteur/selection/coverage_map.rb
97
124
  - lib/saboteur/selection/git_diff.rb
98
125
  - lib/saboteur/selection/recorder.rb
99
126
  - lib/saboteur/subject.rb
100
127
  - lib/saboteur/subject_finder.rb
101
128
  - lib/saboteur/version.rb
129
+ - lib/saboteur/working_tree.rb
102
130
  homepage: https://github.com/vamsipavanmahesh/saboteur
103
131
  licenses:
104
132
  - MIT