error_radar 0.4.0 → 0.5.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: 486749dc9fc6c6e2cc617340f184cf8dbeb4196199c3017eb7bf6f667718fe74
4
- data.tar.gz: 13da87d1772c71901b66fb4cd6b4d29a809b539b6fccaee5613defae97c0a04d
3
+ metadata.gz: 106881790c16306716c7588f317da722c0e589db0a0a2bbb6e7ad838c9a8d118
4
+ data.tar.gz: d4c9ccf1363b88637dc625418daf8553e15aad0796f42f79aadc6eafb3a4f554
5
5
  SHA512:
6
- metadata.gz: 6a9fe7aa11d7668ca353e0c6331eac9a339c43263f93bc3650085bd72f2072968376006f7481661037c7d9f80fdca0057b8a28d9779a92050b931fb4eccd441f
7
- data.tar.gz: f98150abaa5c7bd7695ddd38ba91d65db73bfe81ce7e739c9f91fac20c596b3303643fc282320b2366f9b1b6bd4da48c2bfca7bd8d182e1162c3a7786770384a
6
+ metadata.gz: c880963d54ef38274dbc226b970f848f7a9ced038c6d88ababffe1b3eb71ef2d8490695a0a256775a500e707a72b9af2a017a066e8af1f66b17ab842a18ac726
7
+ data.tar.gz: ba612e7cc8a547cd1bf7ffb8704347636bccc7f763fba3a73fbfe1919b86573421873b61c88f6c8b44da0ed661cf8cf73d4da62a54998828dfe1a767642580ad
data/CHANGELOG.md CHANGED
@@ -2,6 +2,35 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.5.0] - 2026-07-03
6
+
7
+ ### Added
8
+ - **REST API** at `/api/*` for external integrations (CI/CD, dashboards, scripts):
9
+ - `GET /api/errors` — paginated list with the same filters as the web UI
10
+ (`status`, `severity`, `category`, `q`, `from`, `to`, `sort`, `order`, `page`)
11
+ - `GET /api/errors/:id` — full detail including context, backtrace, and
12
+ `github_issue_url` (if column is present)
13
+ - `PATCH /api/errors/:id` — update status; resolve accepts optional `note`
14
+ and `resolved_by` params
15
+ - `GET /api/stats` — summary counts by status, severity, and category
16
+ - **Bearer-token API auth**: set `config.api_token` to protect all `/api/*`
17
+ endpoints with `Authorization: Bearer <token>`.
18
+ - **GitHub Issue integration**: "Create GitHub Issue" button on the error detail
19
+ page opens a pre-filled issue with error class, source, message, backtrace,
20
+ and a deep-link back to Error Radar. Requires `config.github_token` and
21
+ `config.github_repo`.
22
+ - **`github_issue_url` column**: stored on the error row so the button becomes
23
+ "View GitHub Issue" once an issue exists. Requires running the upgrade
24
+ migration: `bin/rails generate error_radar:upgrade_v050 && bin/rails db:migrate`.
25
+ - **`error_radar:upgrade_v050` generator**: generates the migration that adds
26
+ `github_issue_url` to `error_radar_error_logs`.
27
+
28
+ ### Notes
29
+ - The GitHub column is optional — the integration is gracefully degraded when the
30
+ migration has not been run (button appears but URL is not persisted).
31
+ - The API controllers live in `ErrorRadar::Api::*` to avoid polluting the host
32
+ app's controller namespace.
33
+
5
34
  ## [0.4.0] - 2026-07-03
6
35
 
7
36
  ### Added
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ErrorRadar
4
+ module Api
5
+ class BaseController < ActionController::Base
6
+ skip_before_action :verify_authenticity_token
7
+ before_action :authenticate_api!
8
+
9
+ private
10
+
11
+ def authenticate_api!
12
+ token = ErrorRadar.config.api_token
13
+ return if token.nil?
14
+
15
+ provided = request.headers['Authorization'].to_s.delete_prefix('Bearer ').strip
16
+ render json: { error: 'Unauthorized' }, status: :unauthorized unless provided == token
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ErrorRadar
4
+ module Api
5
+ class ErrorsController < BaseController
6
+ PER_PAGE = 50
7
+
8
+ # GET /api/errors
9
+ def index
10
+ scope = build_scope
11
+ total = scope.count
12
+ page = [params[:page].to_i, 1].max
13
+ total_pages = [(total.to_f / PER_PAGE).ceil, 1].max
14
+ page = [page, total_pages].min
15
+
16
+ errors = scope.limit(PER_PAGE).offset((page - 1) * PER_PAGE)
17
+
18
+ render json: {
19
+ data: errors.map { |e| serialize(e) },
20
+ meta: { total: total, page: page, per_page: PER_PAGE, total_pages: total_pages }
21
+ }
22
+ end
23
+
24
+ # GET /api/errors/:id
25
+ def show
26
+ log = ErrorLog.find(params[:id])
27
+ render json: { data: serialize(log, detail: true) }
28
+ rescue ActiveRecord::RecordNotFound
29
+ render json: { error: 'Not found' }, status: :not_found
30
+ end
31
+
32
+ # PATCH /api/errors/:id
33
+ def update
34
+ log = ErrorLog.find(params[:id])
35
+ new_status = params[:status].to_s
36
+
37
+ unless ErrorLog.statuses.key?(new_status)
38
+ return render json: { error: 'invalid status' }, status: :unprocessable_entity
39
+ end
40
+
41
+ if new_status == 'resolved'
42
+ log.resolve!(by: params[:resolved_by].presence, note: params[:note].presence)
43
+ else
44
+ log.update!(status: new_status, resolved_at: nil)
45
+ end
46
+
47
+ render json: { data: serialize(log) }
48
+ rescue ActiveRecord::RecordNotFound
49
+ render json: { error: 'Not found' }, status: :not_found
50
+ end
51
+
52
+ private
53
+
54
+ def build_scope
55
+ scope = ErrorLog.all
56
+ scope = scope.where(status: params[:status]) if params[:status].present? && ErrorLog.statuses.key?(params[:status])
57
+ scope = scope.where(severity: params[:severity]) if params[:severity].present? && ErrorLog.severities.key?(params[:severity])
58
+ scope = scope.where(category: params[:category]) if params[:category].present? && ErrorLog.categories.key?(params[:category])
59
+
60
+ if params[:q].present?
61
+ q = "%#{params[:q].downcase}%"
62
+ scope = scope.where('lower(message) LIKE :q OR lower(error_class) LIKE :q OR lower(source) LIKE :q', q: q)
63
+ end
64
+
65
+ from = params[:from].present? ? (Date.parse(params[:from]) rescue nil) : nil
66
+ to = params[:to].present? ? (Date.parse(params[:to]) rescue nil) : nil
67
+ scope = scope.where('last_seen_at >= ?', from) if from
68
+ scope = scope.where('last_seen_at <= ?', to.end_of_day) if to
69
+
70
+ sort = %w[last_seen_at first_seen_at occurrences].include?(params[:sort]) ? params[:sort] : 'last_seen_at'
71
+ dir = params[:order] == 'asc' ? :asc : :desc
72
+ scope.order(sort => dir)
73
+ end
74
+
75
+ def serialize(log, detail: false)
76
+ data = {
77
+ id: log.id,
78
+ error_class: log.error_class,
79
+ source: log.source,
80
+ message: log.message,
81
+ category: log.category,
82
+ severity: log.severity,
83
+ status: log.status,
84
+ occurrences: log.occurrences,
85
+ first_seen_at: log.first_seen_at&.iso8601,
86
+ last_seen_at: log.last_seen_at&.iso8601,
87
+ resolved_at: log.resolved_at&.iso8601,
88
+ resolved_by: log.resolved_by
89
+ }
90
+
91
+ if detail
92
+ data.merge!(
93
+ fingerprint: log.fingerprint,
94
+ resolution_note: log.resolution_note,
95
+ http_status: log.http_status,
96
+ request_url: log.request_url,
97
+ api_code: log.api_code,
98
+ api_subcode: log.api_subcode,
99
+ context: log.context,
100
+ backtrace: log.backtrace
101
+ )
102
+ end
103
+
104
+ if log.class.column_names.include?('github_issue_url')
105
+ data[:github_issue_url] = log.github_issue_url
106
+ end
107
+
108
+ data
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ErrorRadar
4
+ module Api
5
+ # GET /api/stats — summary counts for dashboards, CI gates, uptime monitors.
6
+ class StatsController < BaseController
7
+ def show
8
+ render json: {
9
+ total: ErrorLog.count,
10
+ open: ErrorLog.status_open.count,
11
+ in_progress: ErrorLog.status_in_progress.count,
12
+ resolved: ErrorLog.status_resolved.count,
13
+ ignored: ErrorLog.status_ignored.count,
14
+ unresolved: ErrorLog.unresolved.count,
15
+ by_severity: ErrorLog.group(:severity).count,
16
+ by_category: ErrorLog.group(:category).count,
17
+ generated_at: Time.current.iso8601
18
+ }
19
+ end
20
+ end
21
+ end
22
+ end
@@ -3,7 +3,7 @@
3
3
  module ErrorRadar
4
4
  class ErrorsController < ApplicationController
5
5
  before_action :authenticate_request!
6
- before_action :set_error, only: %i[show update_status destroy]
6
+ before_action :set_error, only: %i[show update_status destroy create_github_issue]
7
7
 
8
8
  rescue_from ActiveRecord::RecordNotFound do
9
9
  redirect_to errors_path, alert: 'Error not found.'
@@ -44,6 +44,35 @@ module ErrorRadar
44
44
  render json: { ok: true }
45
45
  end
46
46
 
47
+ def create_github_issue
48
+ unless github_configured?
49
+ return render json: { ok: false, error: 'GitHub not configured (set config.github_token and config.github_repo)' },
50
+ status: :unprocessable_entity
51
+ end
52
+
53
+ if ErrorLog.column_names.include?('github_issue_url') && @error.github_issue_url.present?
54
+ return render json: { ok: false, error: 'Issue already created', url: @error.github_issue_url },
55
+ status: :unprocessable_entity
56
+ end
57
+
58
+ require 'error_radar/integrations/github'
59
+ result = ErrorRadar::Integrations::Github.create_issue(
60
+ @error,
61
+ token: ErrorRadar.config.github_token,
62
+ repo: ErrorRadar.config.github_repo
63
+ )
64
+
65
+ if result['html_url']
66
+ @error.update!(github_issue_url: result['html_url']) if ErrorLog.column_names.include?('github_issue_url')
67
+ render json: { ok: true, url: result['html_url'], number: result['number'] }
68
+ else
69
+ render json: { ok: false, error: result['message'] || 'GitHub API error' },
70
+ status: :unprocessable_entity
71
+ end
72
+ rescue StandardError => e
73
+ render json: { ok: false, error: e.message }, status: :internal_server_error
74
+ end
75
+
47
76
  def bulk
48
77
  ids = Array(params[:ids]).map(&:to_i).select(&:positive?)
49
78
  action = params[:bulk_action].to_s
@@ -115,6 +144,10 @@ module ErrorRadar
115
144
  ids.size
116
145
  end
117
146
 
147
+ def github_configured?
148
+ ErrorRadar.config.github_token.present? && ErrorRadar.config.github_repo.present?
149
+ end
150
+
118
151
  def active_filter_params
119
152
  params.permit(:q, :status, :severity, :category, :from, :to, :sort, :order).to_h
120
153
  end
@@ -104,11 +104,37 @@
104
104
  </div>
105
105
  </div>
106
106
 
107
+ <%# ── GitHub Issue ── %>
108
+ <% if ErrorRadar.config.github_token.present? && ErrorRadar.config.github_repo.present? %>
109
+ <div class="panel" style="margin-top:16px">
110
+ <h2>GitHub</h2>
111
+ <% has_col = @error.class.column_names.include?('github_issue_url') %>
112
+ <% if has_col && @error.github_issue_url.present? %>
113
+ <a href="<%= @error.github_issue_url %>" target="_blank" rel="noopener"
114
+ class="er-btn" style="background:#24292e;display:inline-block;text-decoration:none">
115
+ &#9651; View GitHub Issue
116
+ </a>
117
+ <% else %>
118
+ <button id="github-btn" class="er-btn" style="background:#24292e" onclick="createGithubIssue()">
119
+ &#9651; Create GitHub Issue
120
+ </button>
121
+ <span id="github-status" style="font-size:13px;color:#6b7280;margin-left:10px"></span>
122
+ <% unless has_col %>
123
+ <p style="font-size:12px;color:#9ca3af;margin:10px 0 0">
124
+ Run <code style="background:#f3f4f6;padding:2px 6px;border-radius:4px">bin/rails generate error_radar:upgrade_v050 &amp;&amp; bin/rails db:migrate</code>
125
+ to enable issue tracking.
126
+ </p>
127
+ <% end %>
128
+ <% end %>
129
+ </div>
130
+ <% end %>
131
+
107
132
  <script>
108
133
  (function () {
109
134
  var CSRF = document.querySelector('meta[name="csrf-token"]').content;
110
135
  var STATUS_URL = '<%= error_status_path(@error) %>';
111
136
  var DELETE_URL = '<%= error_path(@error) %>';
137
+ var GITHUB_URL = '<%= error_github_issue_path(@error) %>';
112
138
 
113
139
  document.querySelectorAll('.status-btn').forEach(function (btn) {
114
140
  btn.addEventListener('click', function () { changeStatus(btn.dataset.status, null); });
@@ -154,6 +180,35 @@
154
180
  });
155
181
  };
156
182
 
183
+ window.createGithubIssue = function () {
184
+ var btn = document.getElementById('github-btn');
185
+ var status = document.getElementById('github-status');
186
+ if (!btn) return;
187
+ btn.disabled = true;
188
+ status.textContent = 'Creating issue…';
189
+
190
+ fetch(GITHUB_URL, {
191
+ method: 'POST',
192
+ headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': CSRF }
193
+ })
194
+ .then(function (r) { return r.json(); })
195
+ .then(function (d) {
196
+ if (d.ok) {
197
+ status.innerHTML = '✓ Created: <a href="' + d.url + '" target="_blank">#' + d.number + '</a>';
198
+ btn.style.display = 'none';
199
+ showToast('GitHub issue #' + d.number + ' created', true);
200
+ } else {
201
+ status.textContent = 'Error: ' + (d.error || 'failed');
202
+ btn.disabled = false;
203
+ showToast(d.error || 'GitHub error', false);
204
+ }
205
+ })
206
+ .catch(function () {
207
+ status.textContent = 'Network error';
208
+ btn.disabled = false;
209
+ });
210
+ };
211
+
157
212
  function showToast(msg, ok) {
158
213
  var t = document.getElementById('toast');
159
214
  t.textContent = msg;
data/config/routes.rb CHANGED
@@ -3,9 +3,17 @@
3
3
  ErrorRadar::Engine.routes.draw do
4
4
  root to: 'dashboard#index'
5
5
 
6
- get 'errors', to: 'errors#index', as: :errors
7
- post 'errors/bulk', to: 'errors#bulk', as: :errors_bulk
8
- get 'errors/:id', to: 'errors#show', as: :error
9
- patch 'errors/:id/status', to: 'errors#update_status', as: :error_status
10
- delete 'errors/:id', to: 'errors#destroy'
6
+ # REST API — JSON endpoints for CI/CD, external dashboards, scripts
7
+ namespace :api, defaults: { format: :json } do
8
+ resources :errors, only: %i[index show update]
9
+ resource :stats, only: [:show]
10
+ end
11
+
12
+ # Web UI
13
+ get 'errors', to: 'errors#index', as: :errors
14
+ post 'errors/bulk', to: 'errors#bulk', as: :errors_bulk
15
+ post 'errors/:id/github_issue', to: 'errors#create_github_issue', as: :error_github_issue
16
+ get 'errors/:id', to: 'errors#show', as: :error
17
+ patch 'errors/:id/status', to: 'errors#update_status', as: :error_status
18
+ delete 'errors/:id', to: 'errors#destroy'
11
19
  end
@@ -69,6 +69,16 @@ module ErrorRadar
69
69
  @error_callbacks << block
70
70
  end
71
71
 
72
+ # REST API ────────────────────────────────────────────────────────────────
73
+ # Bearer token for /api/* endpoints. nil = unauthenticated (not for prod).
74
+ attr_accessor :api_token
75
+
76
+ # GitHub integration ──────────────────────────────────────────────────────
77
+ # Personal access token with repo scope.
78
+ attr_accessor :github_token
79
+ # "owner/repo" string, e.g. "myorg/myapp".
80
+ attr_accessor :github_repo
81
+
72
82
  # Custom classification rules. Each is a callable `->(exception) { :category | nil }`.
73
83
  # The first rule that returns a non-nil category wins; built-in rules run after.
74
84
  attr_accessor :categorizers
@@ -124,6 +134,10 @@ module ErrorRadar
124
134
  @app_name = nil
125
135
  @app_host = nil
126
136
  @error_callbacks = []
137
+
138
+ @api_token = nil
139
+ @github_token = nil
140
+ @github_repo = nil
127
141
  @categorizers = []
128
142
  @detail_extractors = []
129
143
  @expected_servers = []
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'uri'
5
+ require 'json'
6
+
7
+ module ErrorRadar
8
+ module Integrations
9
+ # Creates GitHub issues from ErrorLog records via the GitHub REST API.
10
+ # Requires a personal access token with the `repo` scope and a repo in
11
+ # "owner/repo" format.
12
+ module Github
13
+ API_BASE = 'https://api.github.com'
14
+
15
+ # Returns the parsed JSON response from GitHub.
16
+ # Raises StandardError on network/API failure.
17
+ def self.create_issue(error_log, token:, repo:)
18
+ owner, repo_name = repo.split('/', 2)
19
+ uri = URI("#{API_BASE}/repos/#{owner}/#{repo_name}/issues")
20
+
21
+ http = Net::HTTP.new(uri.host, uri.port)
22
+ http.use_ssl = true
23
+ http.open_timeout = 10
24
+ http.read_timeout = 10
25
+
26
+ req = Net::HTTP::Post.new(uri)
27
+ req['Authorization'] = "Bearer #{token}"
28
+ req['Content-Type'] = 'application/json'
29
+ req['Accept'] = 'application/vnd.github+json'
30
+ req['X-GitHub-Api-Version'] = '2022-11-28'
31
+ req.body = {
32
+ title: issue_title(error_log),
33
+ body: issue_body(error_log),
34
+ labels: ['bug', 'error-radar']
35
+ }.to_json
36
+
37
+ response = http.request(req)
38
+ JSON.parse(response.body)
39
+ end
40
+
41
+ def self.issue_title(log)
42
+ short_msg = log.message.to_s.truncate(80).gsub(/\n/, ' ')
43
+ "[Error Radar] #{log.error_class}: #{short_msg}"
44
+ end
45
+
46
+ def self.issue_body(log)
47
+ url = ErrorRadar::Notifier.error_url(log)
48
+ backtrace = log.backtrace.to_s.split("\n").first(20).join("\n")
49
+
50
+ parts = []
51
+ parts << "## Error Details\n"
52
+ parts << "| Field | Value |"
53
+ parts << "|-------|-------|"
54
+ parts << "| **Error Class** | `#{log.error_class}` |"
55
+ parts << "| **Source** | #{log.source || 'unknown'} |"
56
+ parts << "| **Category** | #{log.category} |"
57
+ parts << "| **Severity** | #{log.severity} |"
58
+ parts << "| **Occurrences** | #{log.occurrences} |"
59
+ parts << "| **First seen** | #{log.first_seen_at&.strftime('%Y-%m-%d %H:%M UTC')} |"
60
+ parts << "| **Last seen** | #{log.last_seen_at&.strftime('%Y-%m-%d %H:%M UTC')} |"
61
+ parts << "\n## Message\n\n```\n#{log.message.to_s.truncate(1000)}\n```"
62
+
63
+ unless backtrace.empty?
64
+ parts << "\n## Backtrace\n\n```\n#{backtrace}\n```"
65
+ end
66
+
67
+ parts << "\n## Link\n\n[View in Error Radar](#{url})" if url
68
+
69
+ parts << "\n---\n*Created automatically by [Error Radar](https://github.com/chienbn9x/error_radar)*"
70
+ parts.join("\n")
71
+ end
72
+ end
73
+ end
74
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ErrorRadar
4
- VERSION = '0.4.0'
4
+ VERSION = '0.5.0'
5
5
  end
@@ -72,6 +72,17 @@ ErrorRadar.configure do |config|
72
72
  # config.expected_servers = [
73
73
  # { key: 'web', name: 'Web', tag: 'sidekiq_web', host: 'web', queue_hint: 'low' }
74
74
  # ]
75
+
76
+ # --- REST API ---
77
+ # Protect /api/* endpoints with a Bearer token.
78
+ # config.api_token = ENV['ERROR_RADAR_API_TOKEN']
79
+ # curl -H "Authorization: Bearer $TOKEN" https://myapp.com/error_radar/api/stats
80
+
81
+ # --- GitHub Integration ---
82
+ # Creates GitHub issues directly from the error detail page.
83
+ # Requires running: bin/rails generate error_radar:upgrade_v050 && bin/rails db:migrate
84
+ # config.github_token = ENV['GITHUB_TOKEN'] # PAT with repo scope
85
+ # config.github_repo = 'myorg/myapp' # "owner/repo" format
75
86
  end
76
87
 
77
88
  # ActiveJob is now captured automatically via install_active_job = true above.
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddGithubIssueToErrorRadarErrorLogs < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
4
+ def change
5
+ add_column :error_radar_error_logs, :github_issue_url, :string, limit: 500
6
+ end
7
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/generators'
4
+ require 'rails/generators/active_record'
5
+
6
+ module ErrorRadar
7
+ module Generators
8
+ class UpgradeV050Generator < Rails::Generators::Base
9
+ include Rails::Generators::Migration
10
+
11
+ source_root File.expand_path('templates', __dir__)
12
+
13
+ desc 'Generates the migration for Error Radar v0.5.0 (adds github_issue_url column).'
14
+
15
+ def self.next_migration_number(dirname)
16
+ ActiveRecord::Generators::Base.next_migration_number(dirname)
17
+ end
18
+
19
+ def create_migration_file
20
+ migration_template(
21
+ 'add_github_issue_to_error_radar_error_logs.rb.tt',
22
+ 'db/migrate/add_github_issue_to_error_radar_error_logs.rb'
23
+ )
24
+ end
25
+ end
26
+ end
27
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: error_radar
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - chienbn9x
@@ -57,6 +57,9 @@ files:
57
57
  - MIT-LICENSE
58
58
  - README.md
59
59
  - Rakefile
60
+ - app/controllers/error_radar/api/base_controller.rb
61
+ - app/controllers/error_radar/api/errors_controller.rb
62
+ - app/controllers/error_radar/api/stats_controller.rb
60
63
  - app/controllers/error_radar/application_controller.rb
61
64
  - app/controllers/error_radar/dashboard_controller.rb
62
65
  - app/controllers/error_radar/errors_controller.rb
@@ -75,6 +78,7 @@ files:
75
78
  - lib/error_radar/configuration.rb
76
79
  - lib/error_radar/engine.rb
77
80
  - lib/error_radar/integrations/active_job.rb
81
+ - lib/error_radar/integrations/github.rb
78
82
  - lib/error_radar/integrations/rails_admin.rb
79
83
  - lib/error_radar/integrations/rake.rb
80
84
  - lib/error_radar/integrations/sidekiq.rb
@@ -90,6 +94,8 @@ files:
90
94
  - lib/generators/error_radar/install/install_generator.rb
91
95
  - lib/generators/error_radar/install/templates/create_error_radar_error_logs.rb.tt
92
96
  - lib/generators/error_radar/install/templates/initializer.rb
97
+ - lib/generators/error_radar/upgrade_v050/templates/add_github_issue_to_error_radar_error_logs.rb.tt
98
+ - lib/generators/error_radar/upgrade_v050/upgrade_v050_generator.rb
93
99
  homepage: https://github.com/chienbn9x/error_radar
94
100
  licenses:
95
101
  - MIT