class Omnibus::BuildVersion
Provides methods for generating Omnibus
project build version strings automatically from Git repository information.
@see Omnibus::Project#build_version
@note Requires a Git repository
@todo Rename this class to reflect its absolute dependence on running in a
Git repository.
Constants
- TIMESTAMP_FORMAT
Formatting string for the timestamp component of our SemVer build specifier.
@see
Omnibus::BuildVersion#semver
@see Time#strftime
Public Class Methods
# File lib/omnibus/build_version.rb, line 50 def build_start_time new.build_start_time end
@see (BuildVersion#git_describe
)
# File lib/omnibus/build_version.rb, line 41 def git_describe new.git_describe end
Create a new BuildVersion
@param [String] path
Path from which to read git version information
# File lib/omnibus/build_version.rb, line 59 def initialize(path = Config.project_root) @path = path end
@see (BuildVersion#semver
)
# File lib/omnibus/build_version.rb, line 46 def semver new.semver end
Public Instance Methods
We’ll attempt to retrieve the timestamp from the Jenkin’s set BUILD_TIMESTAMP or fall back to BUILD_ID environment variable. This will ensure platform specfic packages for the same build will share the same timestamp.
# File lib/omnibus/build_version.rb, line 141 def build_start_time @build_start_time ||= begin if ENV["BUILD_TIMESTAMP"] begin Time.strptime(ENV["BUILD_TIMESTAMP"], "%Y-%m-%d_%H-%M-%S") rescue ArgumentError error_message = "BUILD_TIMESTAMP environment variable " error_message << "should be in YYYY-MM-DD_hh-mm-ss " error_message << "format." raise ArgumentError, error_message end elsif ENV["BUILD_ID"] begin Time.strptime(ENV["BUILD_ID"], "%Y-%m-%d_%H-%M-%S") rescue ArgumentError error_message = "BUILD_ID environment variable " error_message << "should be in YYYY-MM-DD_hh-mm-ss " error_message << "format." raise ArgumentError, error_message end else Time.now.utc end end.strftime(TIMESTAMP_FORMAT) end
Extracts the number of commits since the most recent Git tag, as determined by {#git_describe}.
Here are some illustrative examples:
1.2.7-208-ge908a52 -> 208 11.0.0-alpha-59-gf55b180 -> 59 11.0.0-alpha2 -> 0 10.16.2.rc.1 -> 0
@return [Fixnum]
# File lib/omnibus/build_version.rb, line 262 def commits_since_tag commits_regexp = /^.*-(\d+)\-g[0-9a-f]+$/ match = commits_regexp.match(git_describe) match ? match[1].to_i : 0 end
Generates a version string by running {www.kernel.org/pub/software/scm/git/docs/git-describe.html git describe} in the root of the Omnibus
project.
Produces a version string of the format
MOST_RECENT_TAG-COMMITS_SINCE-gGIT_SHA
@example
11.0.0-alpha.1-207-g694b062
@return [String]
# File lib/omnibus/build_version.rb, line 178 def git_describe @git_describe ||= begin cmd = shellout("git describe --tags", cwd: @path) if cmd.exitstatus == 0 cmd.stdout.chomp else log.warn(log_key) do "Could not extract version information from 'git describe'! " \ "Setting version to 0.0.0." end "0.0.0" end end end
Extracts the 7-character truncated Git SHA1 from the output of {#git_describe}.
Here are some illustrative examples:
1.2.7-208-ge908a52 -> e908a52 11.0.0-alpha-59-gf55b180 -> f55b180 11.0.0-alpha2 -> nil 10.16.2.rc.1 -> nil
@return [String] the truncated SHA1 @return [nil] if no SHA1 is present in the output of #{git_describe}
# File lib/omnibus/build_version.rb, line 245 def git_sha_tag sha_regexp = /g([0-9a-f]+)$/ match = sha_regexp.match(git_describe) match ? match[1] : nil end
Return a prerelease tag string (if it exists), as extracted from {#git_describe}.
Here are some illustrative examples:
1.2.7-208-ge908a52 -> nil 11.0.0-alpha-59-gf55b180 -> alpha 11.0.0-alpha2 -> alpha2 10.16.2.rc.1 -> rc.1
@return [String] if a pre-release tag was found @return [nil] if no pre-release tag was found
# File lib/omnibus/build_version.rb, line 224 def prerelease_tag prerelease_regex = if commits_since_tag > 0 /^v?\d+\.\d+\.\d+(?:-|\.)([0-9A-Za-z.-]+)-\d+-g[0-9a-f]+$/ else /^v?\d+\.\d+\.\d+(?:-|\.)([0-9A-Za-z.-]+)$/ end match = prerelease_regex.match(git_describe) match ? match[1] : nil end
Indicates whether the version represents a pre-release or not, as signalled by the presence of a pre-release tag in the version string.
@return [Boolean] @see prerelease_tag
# File lib/omnibus/build_version.rb, line 274 def prerelease_version? if prerelease_tag true else false end end
Generate a {semver.org/ SemVer 2.0.0-rc.1 compliant} version string for an Omnibus
project.
This relies on the Omnibus
project being a Git repository, as well as having tags named according to SemVer conventions (specifically, the ‘MAJOR.MINOR.PATCH-PRERELEASE` aspects)
The specific format of the version string is:
MAJOR.MINOR.PATCH-PRERELEASE+TIMESTAMP.git.COMMITS_SINCE.GIT_SHA
By default, a timestamp is incorporated into the build component of version string (see {Omnibus::BuildVersion::TIMESTAMP_FORMAT}). This option is configurable via the {Config}.
@example 11.0.0-alpha.1+20121218164140.git.207.694b062 @return [String] @see git_describe
@todo Issue a warning or throw an exception if the tags of the
repository are not themselves SemVer-compliant?
@todo Consider making the {#build_start_time} method public, as
its function influences how build timestamps are generated, and can be influenced by users.
# File lib/omnibus/build_version.rb, line 88 def semver build_tag = version_tag log.debug(log_key) { "#{self.class}##{__method__} - build tag: #{build_tag}" } # PRERELEASE VERSION log.debug(log_key) { "#{self.class}##{__method__} - prerelease_version?: #{prerelease_version?}" } if prerelease_version? # ensure all dashes are dots per precedence rules (#12) in Semver # 2.0.0-rc.1 log.debug(log_key) { "#{self.class}##{__method__} - prerelease_tag: #{prerelease_tag}" } prerelease = prerelease_tag.tr("-", ".") build_tag << "-" << prerelease log.debug(log_key) { "#{self.class}##{__method__} - build_tag after prerelease: #{build_tag}" } end # BUILD VERSION # Follows SemVer conventions and the build version begins with a '+'. build_version_items = [] # By default we will append a timestamp to every build. This behavior can # be overriden by setting the OMNIBUS_APPEND_TIMESTAMP environment # variable to a 'falsey' value (ie false, f, no, n or 0). # # format: YYYYMMDDHHMMSS example: 20130131123345 if Config.append_timestamp log.debug(log_key) { "#{self.class}##{__method__} - build_start_time: #{build_start_time}" } build_version_items << build_start_time end # We'll append the git describe information unless we are sitting right # on an annotated tag. # # format: git.COMMITS_SINCE_TAG.GIT_SHA example: git.207.694b062 unless commits_since_tag == 0 log.debug(log_key) { "#{self.class}##{__method__} - commits_since_tag: #{commits_since_tag}" } log.debug(log_key) { "#{self.class}##{__method__} - git_sha_tag: #{git_sha_tag}" } build_version_items << ["git", commits_since_tag, git_sha_tag].join(".") end unless build_version_items.empty? log.debug(log_key) { "#{self.class}##{__method__} - build_version_items: #{build_version_items}" } build_tag << "-" << build_version_items.join(".") end log.debug(log_key) { "#{self.class}##{__method__} - final build_tag returned: #{build_tag}" } build_tag end
Return a ‘MAJOR.MINOR.PATCH` version string, as extracted from {#git_describe}.
Here are some illustrative examples:
1.2.7-208-ge908a52 -> 1.2.7 11.0.0-alpha-59-gf55b180 -> 11.0.0 11.0.0-alpha2 -> 11.0.0 10.16.2.rc.1 -> 10.16.2
@return [String]
# File lib/omnibus/build_version.rb, line 209 def version_tag version_composition.join(".") end
Private Instance Methods
Pulls out the major, minor, and patch components from the output of {#git_describe}.
Relies on the most recent Git tag being SemVer compliant (i.e., starting with a ‘MAJOR.MINOR.PATCH` string)
@return [Array<(String, String, String)>]
@todo Compute this once and store the result in an instance variable
# File lib/omnibus/build_version.rb, line 293 def version_composition version_regexp = /^v?(\d+)\.(\d+)\.(\d+)/ if match = version_regexp.match(git_describe) match[1..3] else raise "Invalid semver tag `#{git_describe}'!" end end