Class: Omnibus::BuildVersion

Inherits:
Object
  • Object
show all
Includes:
Logging, Util
Defined in:
lib/omnibus/build_version.rb

Overview

TODO:

Rename this class to reflect its absolute dependence on running in a Git repository.

Note:

Requires a Git repository

Provides methods for generating Omnibus project build version strings automatically from Git repository information.

Constant Summary collapse

TIMESTAMP_FORMAT =

Formatting string for the timestamp component of our SemVer build specifier.

See Also:

"%Y%m%d%H%M%S".freeze

Constants included from Util

Util::SHELLOUT_OPTIONS

Version Generator Methods collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Util

#compiler_safe_path, #copy_file, #create_directory, #create_file, #create_link, included, #path_key, #remove_directory, #remove_file, #retry_block, #shellout, #shellout!, #windows_safe_path

Methods included from Logging

included

Constructor Details

#initialize(path = Config.project_root) ⇒ BuildVersion

Create a new BuildVersion

Parameters:

  • path (String) (defaults to: Config.project_root)

    Path from which to read git version information



59
60
61
# File 'lib/omnibus/build_version.rb', line 59

def initialize(path = Config.project_root)
  @path = path
end

Class Method Details

.build_start_timeObject



50
51
52
# File 'lib/omnibus/build_version.rb', line 50

def build_start_time
  new.build_start_time
end

.git_describeObject

See Also:

  • (BuildVersion(BuildVersion#git_describe)


41
42
43
# File 'lib/omnibus/build_version.rb', line 41

def git_describe
  new.git_describe
end

.semverObject

See Also:

  • (BuildVersion(BuildVersion#semver)


46
47
48
# File 'lib/omnibus/build_version.rb', line 46

def semver
  new.semver
end

Instance Method Details

#build_start_timeObject

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.



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# 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

#commits_since_tagFixnum

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

Returns:

  • (Fixnum)


262
263
264
265
266
# 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

#git_describeString

Generates a version string by running git describe in the root of the Omnibus project.

Produces a version string of the format

MOST_RECENT_TAG-COMMITS_SINCE-gGIT_SHA

Examples:

11.0.0-alpha.1-207-g694b062

Returns:

  • (String)


178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# 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

#git_sha_tagString?

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

Returns:

  • (String)

    the truncated SHA1

  • (nil)

    if no SHA1 is present in the output of #git_describe



245
246
247
248
249
# 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

#prerelease_tagString?

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

Returns:

  • (String)

    if a pre-release tag was found

  • (nil)

    if no pre-release tag was found



224
225
226
227
228
229
230
231
232
# 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

#prerelease_version?Boolean

Indicates whether the version represents a pre-release or not, as signalled by the presence of a pre-release tag in the version string.

Returns:

  • (Boolean)

See Also:



274
275
276
277
278
279
280
# File 'lib/omnibus/build_version.rb', line 274

def prerelease_version?
  if prerelease_tag
    true
  else
    false
  end
end

#semverString

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.

Generate a / 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 TIMESTAMP_FORMAT). This option is configurable via the Config.

Examples:

11.0.0-alpha.1+20121218164140.git.207.694b062

Returns:

  • (String)

See Also:



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# 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

#version_tagString

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

Returns:

  • (String)


209
210
211
# File 'lib/omnibus/build_version.rb', line 209

def version_tag
  version_composition.join(".")
end