lib/airbrake-ruby/filters/git_last_checkout_filter.rb
require 'date' module Airbrake module Filters # Attaches git checkout info to `context`. The info includes: # * username # * email # * revision # * time # # This information is used to track deploys automatically. # # @api private # @since v2.12.0 class GitLastCheckoutFilter # @return [Integer] attr_reader :weight # @return [Integer] least possible amount of columns in git's `logs/HEAD` # file (checkout information is omitted) MIN_HEAD_COLS = 6 include Loggable # @param [String] root_directory def initialize(root_directory) @git_path = File.join(root_directory, '.git') @weight = 116 @last_checkout = nil @deploy_username = ENV.fetch('AIRBRAKE_DEPLOY_USERNAME', nil) end # @macro call_filter def call(notice) return if notice[:context].key?(:lastCheckout) if @last_checkout notice[:context][:lastCheckout] = @last_checkout return end return unless File.exist?(@git_path) return unless (checkout = last_checkout) notice[:context][:lastCheckout] = checkout end private def last_checkout return unless (line = last_checkout_line) parts = line.chomp.split("\t").first.split if parts.size < MIN_HEAD_COLS logger.error( "#{LOG_LABEL} Airbrake::#{self.class.name}: can't parse line: #{line}", ) return end author = parts[2..-4] @last_checkout = { username: @deploy_username || author[0..1].join(' '), email: parts[-3][1..-2], revision: parts[1], time: timestamp(parts[-2].to_i), } end def last_checkout_line head_path = File.join(@git_path, 'logs', 'HEAD') return unless File.exist?(head_path) last_line = nil File.foreach(head_path) do |line| last_line = line if checkout_line?(line) end last_line end def checkout_line?(line) line.include?("\tclone:") || line.include?("\tpull:") || line.include?("\tcheckout:") end def timestamp(utime) Time.at(utime).to_datetime.rfc3339 end end end end