rails-informant 0.4.3 → 0.4.5

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: de6c6a1e4797ad9aa7ceb4f44bbe3555030872c05e2fa2d4f5fc3a89c1585add
4
- data.tar.gz: d9a7e18f30c905a304e881d4ab0bb39290db5efac899aa0bb6eb54e1b92c55af
3
+ metadata.gz: 6d0af47e9b626dfed7bcf7a29cb9817ff2fd41ada4700a61a0fab3579c863742
4
+ data.tar.gz: e130792dad9233646126fed6bcac17c339e50f5aeb566710307661078a0f7772
5
5
  SHA512:
6
- metadata.gz: 8b96cd324074c8a40e53704d24e2e52e74ef5b9f1f7b00a172fd3fc7c22650bdda50255d6a4f88921b12eaad168bf7ae29feba40eaeee1e003910ea977f4f836
7
- data.tar.gz: c6941002dceb643128d7549c0a1862d97d97a26a36b15fad28db592bdd33734b370c13773dfca97c53ec34b06470e774d00c9382514162af7b309132e6132ec3
6
+ metadata.gz: ab3256ce6ae5de9d3356346d9e5b4c0988f5170439b54a77945051980164a67e2c9e37a6ced0de22e7e68271ac3b5053a1292f4de8cc9f8c5c895e1aad651d0c
7
+ data.tar.gz: 46530d277944774af55b2b0012d45a76e471c690d35e5324385ade0a2c9cc67704dfcbf0aa545c4172dba8c75f031d00ee591478b8fd6cb2669a54ddeed42295
data/README.md CHANGED
@@ -100,6 +100,25 @@ Every option can be set via an environment variable. The initializer takes prece
100
100
 
101
101
  ## Noise Suppression
102
102
 
103
+ ### Default Ignored Exceptions
104
+
105
+ Informant ignores only exceptions that are noise in **every** context: `SignalException`
106
+ and `SystemExit` (process control), plus a few client/tamper errors
107
+ (`Rack::Utils::InvalidParameterError`, `Mime::Type::InvalidMimeType`,
108
+ `CGI::Session::CookieStore::TamperedWithCookie`).
109
+
110
+ It deliberately does **not** ignore Rails' HTTP client errors -- `RecordNotFound`,
111
+ `RoutingError`, `ParameterMissing`, and the rest of the 4xx family. On the request path
112
+ Rails already maps those to responses (404, 422, ...) and never reports them to
113
+ `Rails.error`, so suppressing them again here was redundant. Off the request path -- in a
114
+ **background job**, a rake task, or wrapped as the cause of another error -- those same
115
+ exceptions are real bugs, so Informant records them. A job that dies on an
116
+ `ActiveJob::DeserializationError` caused by a missing record now alerts instead of
117
+ vanishing silently.
118
+
119
+ Add your own classes with `config.ignored_exceptions`; it still walks the cause chain, so
120
+ ignoring a class also ignores exceptions that wrap it.
121
+
103
122
  ### Silenced Blocks
104
123
 
105
124
  ```ruby
@@ -1,9 +1,12 @@
1
+ require "json"
2
+ require "open3"
3
+
1
4
  module RailsInformant
2
5
  module Mcp
3
6
  module Tools
4
7
  class VerifyPendingFixes < BaseTool
5
8
  tool_name "verify_pending_fixes"
6
- description "Verify fix_pending errors by checking if their fix_sha is an ancestor of the deployed code. Resolves verified fixes. Requires git locally. Results reflect local git state — run git fetch first to ensure accuracy."
9
+ description "Verify fix_pending errors by checking whether the fix is in the deployed code: first by fix_sha ancestry, then — for squash/rebase merges, where fix_sha is not an ancestor of the deploy — by the fix PR's merge commit. Resolves verified fixes. Requires git locally (and gh for the PR fallback). Results reflect local git state — run git fetch first to ensure accuracy."
7
10
  input_schema(
8
11
  properties: {
9
12
  auto_resolve: { type: "boolean", description: "Resolve verified fixes automatically (default: true)" },
@@ -31,8 +34,7 @@ module RailsInformant
31
34
  pending = []
32
35
 
33
36
  errors.each do |error|
34
- fix_sha = error["fix_sha"]
35
- if fix_sha && ancestor?(fix_sha, ref)
37
+ if verified?(error, ref)
36
38
  verified << error
37
39
  else
38
40
  pending << error
@@ -55,10 +57,52 @@ module RailsInformant
55
57
 
56
58
  private
57
59
 
60
+ def verified?(error, target_ref)
61
+ fix_sha = error["fix_sha"]
62
+ return true if fix_sha && ancestor?(fix_sha, target_ref)
63
+
64
+ # Squash and rebase merges create a new commit unrelated to fix_sha, so the
65
+ # recorded SHA is never an ancestor of the deploy. Fall back to the PR's merge
66
+ # commit, which is in the deployed history regardless of merge strategy.
67
+ merge_sha = merged_pr_commit error["fix_pr_url"]
68
+ !merge_sha.nil? && ancestor?(merge_sha, target_ref)
69
+ end
70
+
58
71
  def ancestor?(fix_sha, target_ref)
59
72
  system "git", "merge-base", "--is-ancestor", fix_sha, target_ref, out: File::NULL, err: File::NULL
60
73
  end
61
74
 
75
+ # Returns the merge commit SHA of a merged PR, or nil if the PR is unmerged, the
76
+ # URL is blank, or gh is unavailable. Best-effort fetches the commit so the
77
+ # subsequent ancestry check can see it. Uses the array form (no shell) so the
78
+ # PR URL can't be interpreted as a command.
79
+ def merged_pr_commit(pr_url)
80
+ return if pr_url.nil? || pr_url.empty?
81
+ return unless gh_available?
82
+
83
+ output, status = Open3.capture2 "gh", "pr", "view", pr_url, "--json", "state,mergeCommit", err: File::NULL
84
+ return unless status.success? && !output.strip.empty?
85
+
86
+ data = JSON.parse output
87
+ return unless data["state"] == "MERGED"
88
+
89
+ merge_sha = data.dig "mergeCommit", "oid"
90
+ return if merge_sha.nil? || merge_sha.empty?
91
+
92
+ fetch_commit merge_sha
93
+ merge_sha
94
+ rescue JSON::ParserError
95
+ nil
96
+ end
97
+
98
+ def fetch_commit(sha)
99
+ system "git", "fetch", "--quiet", "origin", sha, out: File::NULL, err: File::NULL
100
+ end
101
+
102
+ def gh_available?
103
+ system "gh", "--version", out: File::NULL, err: File::NULL
104
+ end
105
+
62
106
  def fetch_all_fix_pending(client)
63
107
  errors = []
64
108
  page = 1
@@ -5,25 +5,17 @@ module RailsInformant
5
5
  InvalidParameterError = Class.new(StandardError)
6
6
  NotifierError = Class.new(StandardError)
7
7
 
8
+ # Only exceptions that are noise in *every* context. Rails 8.1 maps HTTP
9
+ # client errors (404s, routing, bad params) via rescue_responses and never
10
+ # reports them to Rails.error on the request path, so listing them here was
11
+ # redundant for requests and wrongly suppressed the same exceptions when they
12
+ # are real bugs in background jobs (e.g. a job's RecordNotFound). Those are
13
+ # recorded now; what remains is process-control and client/tamper noise.
8
14
  IGNORED_EXCEPTIONS_DEFAULT = %w[
9
- AbstractController::ActionNotFound
10
- ActionController::BadRequest
11
- ActionController::InvalidAuthenticityToken
12
- ActionController::InvalidCrossOriginRequest
13
- ActionController::MethodNotAllowed
14
- ActionController::NotImplemented
15
- ActionController::ParameterMissing
16
- ActionController::RoutingError
17
15
  ActionController::UnknownAction
18
- ActionController::UnknownFormat
19
- ActionController::UnknownHttpMethod
20
16
  ActionController::UrlGenerationError
21
- ActionDispatch::Http::MimeNegotiation::InvalidType
22
- ActiveRecord::RecordNotFound
23
17
  CGI::Session::CookieStore::TamperedWithCookie
24
18
  Mime::Type::InvalidMimeType
25
- Rack::QueryParser::InvalidParameterError
26
- Rack::QueryParser::ParameterTypeError
27
19
  Rack::Utils::InvalidParameterError
28
20
  SignalException
29
21
  SystemExit
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-informant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.3
4
+ version: 0.4.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel López Prat
@@ -195,7 +195,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
195
195
  - !ruby/object:Gem::Version
196
196
  version: '0'
197
197
  requirements: []
198
- rubygems_version: 4.0.6
198
+ rubygems_version: 4.0.10
199
199
  specification_version: 4
200
200
  summary: Self-hosted error monitoring for Rails with MCP server for agentic workflows
201
201
  test_files: []