Class: VersionFooter

Inherits:
Object
  • Object
show all
Defined in:
app/models/version_footer.rb

Overview

Retrieves version information from Capistrano’s files. The general approach is to read the version information (branch name, git SHA, and date deployed) out of Capistrano’s revisions.log file.

The code is a bit more complicated than it should because Capistrano does not always update the revision.log file before the application reads this information. Therefore there is logic in this class to detect if the version information is stale and re-read it until it is up to date. Because re-reading this file is an expensive operation we cache the information as soon as we are sure it’s current.

rubocop:disable Style/ClassVars

Constant Summary collapse

@@stale =
true
@@git_sha =
nil
@@branch =
nil
@@version =
nil

Class Method Summary collapse

Class Method Details

.branchObject



62
63
64
65
66
67
68
69
70
# File 'app/models/version_footer.rb', line 62

def self.branch
  @@branch ||= if File.exist?(revisions_logfile)
                 log_line(revisions_logfile).chomp.split(" ")[1]
               elsif Rails.env.development? || Rails.env.test?
                 `git rev-parse --abbrev-ref HEAD`.chomp
               else
                 "Unknown branch"
               end
end

.git_shaObject



47
48
49
50
51
52
53
54
55
# File 'app/models/version_footer.rb', line 47

def self.git_sha
  @@git_sha ||= if File.exist?(revisions_logfile)
                  log_line(revisions_logfile).chomp.split(" ")[3].gsub(/\)$/, "")
                elsif Rails.env.development? || Rails.env.test?
                  `git rev-parse HEAD`.chomp
                else
                  "Unknown SHA"
                end
end

.infoObject

Returns a hash with version information.



22
23
24
25
26
27
# File 'app/models/version_footer.rb', line 22

def self.info
  reset! if stale?
  { sha: git_sha, branch:, version:, stale: stale?, tagged_release: tagged_release? }
rescue StandardError => ex
  { error: "Error retrieving version information: #{ex.message}" }
end

.log_line(revisions_logfile) ⇒ Object



104
105
106
107
108
109
110
111
# File 'app/models/version_footer.rb', line 104

def self.log_line(revisions_logfile)
  log_line = `tail -1 #{revisions_logfile}`
  if log_line.include?("rolled back")
    grep_lines = `grep #{log_line.chomp.split(" ").last} #{revisions_logfile}`.split("\n")
    log_line = grep_lines.first
  end
  log_line
end

.reset!Object



29
30
31
32
33
34
# File 'app/models/version_footer.rb', line 29

def self.reset!
  # Initalize these values so that they recalculated
  @@git_sha = nil
  @@branch = nil
  @@version = nil
end

.revision_fileObject

This file is local to the application. This file only has the git SHA of the version deployed (i.e. no date or branch)



83
84
85
# File 'app/models/version_footer.rb', line 83

def self.revision_file
  @@revision_file ||= Rails.root.join("REVISION")
end

.revision_file=(x) ⇒ Object

These assignment methods are needed to facilitate testing



94
95
96
97
# File 'app/models/version_footer.rb', line 94

def self.revision_file=(x)
  @@stale = true
  @@revision_file = x
end

.revisions_logfileObject

Capistrano keeps this file a couple of levels up outside the application. This file includes all the information that we need (git SHA, branch name, date)



89
90
91
# File 'app/models/version_footer.rb', line 89

def self.revisions_logfile
  @@revisions_logfile ||= Rails.root.join("..", "..", "revisions.log")
end

.revisions_logfile=(x) ⇒ Object



99
100
101
102
# File 'app/models/version_footer.rb', line 99

def self.revisions_logfile=(x)
  @@stale = true
  @@revisions_logfile = x
end

.stale?Boolean

Returns:

  • (Boolean)


36
37
38
39
40
41
42
43
44
45
# File 'app/models/version_footer.rb', line 36

def self.stale?
  return false if @@stale == false
  # Only read the file when version information is stale
  if File.exist?(revision_file)
    local_sha = File.read(revision_file).chomp.gsub(/\)$/, "")
    @@stale = local_sha != git_sha
  else
    @@stale = true
  end
end

.tagged_release?Boolean

Returns:

  • (Boolean)


57
58
59
60
# File 'app/models/version_footer.rb', line 57

def self.tagged_release?
  # e.g. v0.8.0
  branch.match(/^v[\d+\.+]+/) != nil
end

.versionObject



72
73
74
75
76
77
78
79
# File 'app/models/version_footer.rb', line 72

def self.version
  @@version ||= if File.exist?(revisions_logfile)
                  deployed = log_line(revisions_logfile).chomp.split(" ")[7]
                  Date.parse(deployed).strftime("%d %B %Y")
                else
                  "Not in deployed environment"
                end
end