-
Notifications
You must be signed in to change notification settings - Fork 68
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
When the airbrake-ruby config doesn't specify `app_version` (99% of Rails apps), then `GitRevisionFilter` tries to find current revision of the app and attach it as `context/version`.
- Loading branch information
Showing
5 changed files
with
195 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
module Airbrake | ||
module Filters | ||
# Attaches current git revision to `context`. | ||
# @api private | ||
# @since v2.11.0 | ||
class GitRevisionFilter | ||
# @return [Integer] | ||
attr_reader :weight | ||
|
||
# @return [String] | ||
PREFIX = 'ref: '.freeze | ||
|
||
def initialize(root_directory) | ||
@git_path = File.join(root_directory, '.git') | ||
@weight = 120 | ||
end | ||
|
||
# @macro call_filter | ||
def call(notice) | ||
return if notice[:context].key?(:version) | ||
return unless File.exist?(@git_path) | ||
|
||
revision = find_revision | ||
notice[:context][:version] = revision if revision | ||
end | ||
|
||
private | ||
|
||
def find_revision | ||
head_path = File.join(@git_path, 'HEAD') | ||
return unless File.exist?(head_path) | ||
|
||
head = File.read(head_path) | ||
return head unless head.start_with?(PREFIX) | ||
head = head.chomp[PREFIX.size..-1] | ||
|
||
ref_path = File.join(@git_path, head) | ||
return File.read(ref_path).chomp if File.exist?(ref_path) | ||
|
||
find_from_packed_refs(head) | ||
end | ||
|
||
def find_from_packed_refs(head) | ||
packed_refs_path = File.join(@git_path, 'packed-refs') | ||
return head unless File.exist?(packed_refs_path) | ||
|
||
File.readlines(packed_refs_path).each do |line| | ||
next if %w[# ^].include?(line[0]) | ||
next unless (parts = line.split(' ')).size == 2 | ||
return parts.first if parts.last == head | ||
end | ||
|
||
nil | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
require 'spec_helper' | ||
|
||
RSpec.describe Airbrake::Filters::GitRevisionFilter do | ||
subject { described_class.new('root/dir') } | ||
|
||
let(:notice) do | ||
Airbrake::Notice.new(Airbrake::Config.new, AirbrakeTestError.new) | ||
end | ||
|
||
context "when context/version is defined" do | ||
it "doesn't attach anything to context/version" do | ||
notice[:context][:version] = '1.2.3' | ||
subject.call(notice) | ||
expect(notice[:context][:version]).to eq('1.2.3') | ||
end | ||
end | ||
|
||
context "when .git directory doesn't exist" do | ||
it "doesn't attach anything to context/version" do | ||
subject.call(notice) | ||
expect(notice[:context][:version]).to be_nil | ||
end | ||
end | ||
|
||
context "when .git directory exists" do | ||
before do | ||
expect(File).to receive(:exist?).with('root/dir/.git').and_return(true) | ||
end | ||
|
||
context "and when HEAD doesn't exist" do | ||
before do | ||
expect(File).to receive(:exist?).with('root/dir/.git/HEAD').and_return(false) | ||
end | ||
|
||
it "doesn't attach anything to context/version" do | ||
subject.call(notice) | ||
expect(notice[:context][:version]).to be_nil | ||
end | ||
end | ||
|
||
context "and when HEAD exists" do | ||
before do | ||
expect(File).to receive(:exist?).with('root/dir/.git/HEAD').and_return(true) | ||
end | ||
|
||
context "and also when HEAD doesn't start with 'ref: '" do | ||
before do | ||
expect(File).to( | ||
receive(:read).with('root/dir/.git/HEAD').and_return('refs/foo') | ||
) | ||
end | ||
|
||
it "attaches the content of HEAD to context/version" do | ||
subject.call(notice) | ||
expect(notice[:context][:version]).to eq('refs/foo') | ||
end | ||
end | ||
|
||
context "and also when HEAD starts with 'ref: " do | ||
before do | ||
expect(File).to( | ||
receive(:read).with('root/dir/.git/HEAD').and_return("ref: refs/foo\n") | ||
) | ||
end | ||
|
||
context "when the ref exists" do | ||
before do | ||
expect(File).to( | ||
receive(:exist?).with('root/dir/.git/refs/foo').and_return(true) | ||
) | ||
expect(File).to( | ||
receive(:read).with('root/dir/.git/refs/foo').and_return("d34db33f\n") | ||
) | ||
end | ||
|
||
it "attaches the revision from the ref to context/version" do | ||
subject.call(notice) | ||
expect(notice[:context][:version]).to eq('d34db33f') | ||
end | ||
end | ||
|
||
context "when the ref doesn't exist" do | ||
before do | ||
expect(File).to( | ||
receive(:exist?).with('root/dir/.git/refs/foo').and_return(false) | ||
) | ||
end | ||
|
||
context "and when '.git/packed-refs' exists" do | ||
before do | ||
expect(File).to( | ||
receive(:exist?).with('root/dir/.git/packed-refs').and_return(true) | ||
) | ||
expect(File).to( | ||
receive(:readlines).with('root/dir/.git/packed-refs').and_return( | ||
[ | ||
"# pack-refs with: peeled fully-peeled\n", | ||
"ccb316eecff79c7528d1ad43e5fa165f7a44d52e refs/tags/v3.0.30\n", | ||
"^d358900f73ee5bfd6ca3a592cf23ac6e82df83c1", | ||
"d34db33f refs/foo\n" | ||
] | ||
) | ||
) | ||
end | ||
|
||
it "attaches the revision from 'packed-refs' to context/version" do | ||
subject.call(notice) | ||
expect(notice[:context][:version]).to eq('d34db33f') | ||
end | ||
end | ||
|
||
context "and when '.git/packed-refs' doesn't exist" do | ||
before do | ||
expect(File).to( | ||
receive(:exist?).with('root/dir/.git/packed-refs').and_return(false) | ||
) | ||
end | ||
|
||
it "attaches the content of HEAD to context/version" do | ||
subject.call(notice) | ||
expect(notice[:context][:version]).to eq('refs/foo') | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |