Module: Fastlane::Helper::Ios::VersionHelper

Defined in:
lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_version_helper.rb

Overview

A module containing helper methods to manipulate/extract/bump iOS version strings in xcconfig files

Constant Summary collapse

MAJOR_NUMBER =

The index for the major version number part

0
MINOR_NUMBER =

The index for the minor version number part

1
HOTFIX_NUMBER =

The index for the hotfix version number part

2
BUILD_NUMBER =

The index for the build version number part

3

Class Method Summary collapse

Class Method Details

.bump_build_number(build_number) ⇒ Int

Return the build number value incremented by one.

Parameters:

  • build_number (String|Int|nil)

    The build number to increment

Returns:

  • (Int)

    The incremented build number, or 0 if it was ‘nil`.



175
176
177
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_version_helper.rb', line 175

def self.bump_build_number(build_number)
  build_number.nil? ? 0 : build_number.to_i + 1
end

.bump_version_releaseString

Prints the current and next release version numbers to stdout, then return the next release version

Returns:

  • (String)

    The next release version to use after bumping the currently used public version.



212
213
214
215
216
217
218
219
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_version_helper.rb', line 212

def self.bump_version_release
  # Bump release
  current_version = get_public_version
  UI.message("Current version: #{current_version}")
  new_version = calc_next_release_version(current_version)
  UI.message("New version: #{new_version}")
  verify_version(new_version)
end

.calc_next_build_version(version) ⇒ String

Compute the name of the next build version.

Parameters:

  • version (String)

    The current version we want to increment

Returns:

  • (String)

    The predicted next build version, in the form of “X.Y.Z.N”. Corresponds to incrementing the last (4th) component N of the version.



109
110
111
112
113
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_version_helper.rb', line 109

def self.calc_next_build_version(version)
  vp = get_version_parts(version)
  vp[BUILD_NUMBER] += 1
  "#{vp[MAJOR_NUMBER]}.#{vp[MINOR_NUMBER]}.#{vp[HOTFIX_NUMBER]}.#{vp[BUILD_NUMBER]}"
end

.calc_next_hotfix_version(version) ⇒ String

Compute the name of the next hotfix version.

Parameters:

  • version (String)

    The current version we want to increment

Returns:

  • (String)

    The predicted next hotfix version, in the form of “X.Y.Z”. Corresponds to incrementing the 3rd component of the version.



122
123
124
125
126
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_version_helper.rb', line 122

def self.calc_next_hotfix_version(version)
  vp = get_version_parts(version)
  vp[HOTFIX_NUMBER] += 1
  "#{vp[MAJOR_NUMBER]}.#{vp[MINOR_NUMBER]}.#{vp[HOTFIX_NUMBER]}"
end

.calc_next_release_version(version) ⇒ String

Compute the name of the next release version.

Parameters:

  • version (String)

    The current version that we want to increment

Returns:

  • (String)

    The predicted next version, in the form of “X.Y”. Corresponds to incrementing the minor part, except if it reached 10 (in that case we go to the next major version, as decided in our versioning conventions)



61
62
63
64
65
66
67
68
69
70
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_version_helper.rb', line 61

def self.calc_next_release_version(version)
  vp = get_version_parts(version)
  vp[MINOR_NUMBER] += 1
  if vp[MINOR_NUMBER] == 10
    vp[MAJOR_NUMBER] += 1
    vp[MINOR_NUMBER] = 0
  end

  "#{vp[MAJOR_NUMBER]}.#{vp[MINOR_NUMBER]}"
end

.calc_prev_build_version(version) ⇒ String

Compute the name of the previous build version.

Parameters:

  • version (String)

    The current version we want to decrement

Returns:

  • (String)

    The predicted previous build version, in the form of “X.Y.Z.N”. Corresponds to decrementing the last (4th) component N of the version.



135
136
137
138
139
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_version_helper.rb', line 135

def self.calc_prev_build_version(version)
  vp = get_version_parts(version)
  vp[BUILD_NUMBER] -= 1 unless (vp[BUILD_NUMBER]).zero?
  "#{vp[MAJOR_NUMBER]}.#{vp[MINOR_NUMBER]}.#{vp[HOTFIX_NUMBER]}.#{vp[BUILD_NUMBER]}"
end

.calc_prev_hotfix_version(version) ⇒ String

Compute the name of the previous hotfix version.

Parameters:

  • version (String)

    The current version we want to decrement

Returns:

  • (String)

    The predicted previous hotfix version, in the form of “X.Y.Z”, or “X.Y” if Z is 0. Corresponds to decrementing the 3rd component Z of the version, striping it if it ends up being zero.



148
149
150
151
152
153
154
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_version_helper.rb', line 148

def self.calc_prev_hotfix_version(version)
  vp = get_version_parts(version)
  vp[HOTFIX_NUMBER] -= 1 unless (vp[HOTFIX_NUMBER]).zero?
  return "#{vp[MAJOR_NUMBER]}.#{vp[MINOR_NUMBER]}.#{vp[HOTFIX_NUMBER]}" unless (vp[HOTFIX_NUMBER]).zero?

  "#{vp[MAJOR_NUMBER]}.#{vp[MINOR_NUMBER]}"
end

.calc_prev_release_version(version) ⇒ String

Compute the name of the previous release version.

Parameters:

  • version (String)

    The current version we want to decrement

Returns:

  • (String)

    The predicted previous version, in the form of “X.Y”. Corresponds to decrementing the minor part, or decrement the major and set minor to 9 if minor was 0.



90
91
92
93
94
95
96
97
98
99
100
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_version_helper.rb', line 90

def self.calc_prev_release_version(version)
  vp = get_version_parts(version)
  if (vp[MINOR_NUMBER]).zero?
    vp[MAJOR_NUMBER] -= 1
    vp[MINOR_NUMBER] = 9
  else
    vp[MINOR_NUMBER] -= 1
  end

  "#{vp[MAJOR_NUMBER]}.#{vp[MINOR_NUMBER]}"
end

.create_internal_version(version) ⇒ String

Create an internal version number, for which the build number is based on today’s date.

Parameters:

  • version (String)

    The current version to create an internal version name for.

Returns:

  • (String)

    The internal version, in the form of “X.Y.Z.YYYYMMDD”.



162
163
164
165
166
167
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_version_helper.rb', line 162

def self.create_internal_version(version)
  vp = get_version_parts(version)
  d = DateTime.now
  today_date = d.strftime('%Y%m%d')
  "#{vp[MAJOR_NUMBER]}.#{vp[MINOR_NUMBER]}.#{vp[HOTFIX_NUMBER]}.#{today_date}"
end

.get_build_versionString

Returns the current value of the ‘VERSION_LONG` key from the public xcconfig file

Returns:

  • (String)

    The current version according to the public xcconfig file.



194
195
196
197
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_version_helper.rb', line 194

def self.get_build_version
  xcconfig_file = ENV['PUBLIC_CONFIG_FILE']
  read_long_version_from_config_file(xcconfig_file)
end

.get_internal_versionString

Returns the current value of the ‘VERSION_LONG` key from the internal xcconfig file

Returns:

  • (String)

    The current version according to the internal xcconfig file.



203
204
205
206
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_version_helper.rb', line 203

def self.get_internal_version
  xcconfig_file = ENV['INTERNAL_CONFIG_FILE']
  read_long_version_from_config_file(xcconfig_file)
end

.get_public_versionString

Deprecated.

This method is going to be removed soon due to it’s dependency on ‘ENV` via `get_build_version`.

Returns the public-facing version string.

Returns:

  • (String)

    The public-facing version number, extracted from the VERSION_LONG entry of the xcconfig file.

    • If this version is a hotfix (more than 2 parts and 3rd part is non-zero), returns the “X.Y.Z” formatted string

    • Otherwise (not a hotfix / 3rd part of version is 0), returns “X.Y” formatted version number



45
46
47
48
49
50
51
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_version_helper.rb', line 45

def self.get_public_version
  version = get_build_version
  vp = get_version_parts(version)
  return "#{vp[MAJOR_NUMBER]}.#{vp[MINOR_NUMBER]}" unless is_hotfix?(version)

  "#{vp[MAJOR_NUMBER]}.#{vp[MINOR_NUMBER]}.#{vp[HOTFIX_NUMBER]}"
end

.get_short_version_string(version) ⇒ String

Return the short version string “X.Y” from the full version.

Parameters:

  • version (String)

    The version to convert to a short version

Returns:

  • (String)

    A version string consisting of only the first 2 parts “X.Y”



78
79
80
81
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_version_helper.rb', line 78

def self.get_short_version_string(version)
  vp = get_version_parts(version)
  "#{vp[MAJOR_NUMBER]}.#{vp[MINOR_NUMBER]}"
end

.get_version_parts(version) ⇒ Array<String>

Note:

If the original version string contains less than 4 parts, the returned array is filled with zeros at the end to always contain 4 items.

Split a version string into its 4 parts, ensuring its parts count is valid

Parameters:

  • version (String)

    The version string to split into parts

Returns:

  • (Array<String>)

    An array of exactly 4 elements, containing each part of the version string.

Raises:

  • (UserError)

    Interrupts the lane if the provided version contains more than 4 parts



268
269
270
271
272
273
274
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_version_helper.rb', line 268

def self.get_version_parts(version)
  parts = version.split('.')
  parts = parts.fill('0', parts.length...4).map(&:to_i)
  UI.user_error!("Bad version string: #{version}") if parts.length > 4

  parts
end

.get_xcconfig_public_version(xcconfig_file:) ⇒ String

Returns the public-facing version string.

Parameters:

  • xcconfig_file (String)

    The path for the .xcconfig file containing the public-facing version

Returns:

  • (String)

    The public-facing version number, extracted from the VERSION_LONG entry of the xcconfig file.

    • If this version is a hotfix (more than 2 parts and 3rd part is non-zero), returns the “X.Y.Z” formatted string

    • Otherwise (not a hotfix / 3rd part of version is 0), returns “X.Y” formatted version number



26
27
28
29
30
31
32
33
34
35
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_version_helper.rb', line 26

def self.get_xcconfig_public_version(xcconfig_file:)
  version = read_long_version_from_config_file(xcconfig_file)

  UI.user_error!(".xcconfig file doesn't have a version configured") if version.nil?

  vp = get_version_parts(version)
  return "#{vp[MAJOR_NUMBER]}.#{vp[MINOR_NUMBER]}" unless is_hotfix?(version)

  "#{vp[MAJOR_NUMBER]}.#{vp[MINOR_NUMBER]}.#{vp[HOTFIX_NUMBER]}"
end

.is_hotfix?(version) ⇒ Bool

Determines if a version number corresponds to a hotfix

Parameters:

  • version (String)

    The version number to test

Returns:

  • (Bool)

    True if the version number has a non-zero 3rd component, meaning that it is a hotfix version.



185
186
187
188
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_version_helper.rb', line 185

def self.is_hotfix?(version)
  vp = get_version_parts(version)
  (vp.length > 2) && (vp[HOTFIX_NUMBER] != 0)
end

.is_int?(string) ⇒ Bool

Check if a string is an integer

Parameters:

  • string (String)

    The string to test

Returns:

  • (Bool)

    true if the string is representing an integer value, false if not



330
331
332
333
334
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_version_helper.rb', line 330

def self.is_int?(string)
  true if Integer(string)
rescue StandardError
  false
end

.read_build_number_from_config_file(file_path) ⇒ String

Extract the BUILD_NUMBER entry from an ‘xcconfig` file

Parameters:

  • file_path (String)

    The path to the ‘.xcconfig` file to read the value from

Returns:

  • (String)

    The build number found in said xcconfig file, or nil if not found



290
291
292
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_version_helper.rb', line 290

def self.read_build_number_from_config_file(file_path)
  read_from_config_file('BUILD_NUMBER', file_path)
end

.read_from_config_file(key, file_path) ⇒ String

Read the value of a given key from an ‘.xcconfig` file.

Parameters:

  • key (String)

    The xcconfig key to get the value for

  • file_path (String)

    The path to the ‘.xcconfig` file to read the value from

Returns:

  • (String)

    The value for the given key, or ‘nil` if the key was not found.



301
302
303
304
305
306
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_version_helper.rb', line 301

def self.read_from_config_file(key, file_path)
  UI.user_error!(".xcconfig file #{file_path} not found") unless File.exist?(file_path)

  config = Xcodeproj::Config.new(file_path)
  config.attributes[key]
end

.read_long_version_from_config_file(file_path) ⇒ String

Extract the VERSION_LONG entry from an ‘xcconfig` file

Parameters:

  • file_path (String)

    The path to the ‘.xcconfig` file to read the value from

Returns:

  • (String)

    The long version found in said xcconfig file, or nil if not found



281
282
283
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_version_helper.rb', line 281

def self.read_long_version_from_config_file(file_path)
  read_from_config_file('VERSION_LONG', file_path)
end

.update_xc_config(file_path, new_version, new_version_short) ⇒ Object

Updates an xcconfig file with new values for VERSION_SHORT and VERSION_LONG entries. Also bumps the BUILD_NUMBER value from that config file if there is one present.

Parameters:

  • file_path (String)

    The path to the xcconfig file

  • new_version (String)

    The new version number to use for VERSION_LONG

  • new_version_short (String)

    The new version number to use for VERSION_SHORT

Raises:

  • (UserError)

    If the xcconfig file was not found



243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_version_helper.rb', line 243

def self.update_xc_config(file_path, new_version, new_version_short)
  if File.exist?(file_path)
    UI.message("Updating #{file_path} to version #{new_version_short}/#{new_version}")
    Action.sh("sed -i '' \"$(awk '/^VERSION_SHORT/{ print NR; exit }' \"#{file_path}\")s/=.*/=#{new_version_short}/\" \"#{file_path}\"")
    Action.sh("sed -i '' \"$(awk '/^VERSION_LONG/{ print NR; exit }' \"#{file_path}\")s/=.*/=#{new_version}/\" \"#{file_path}\"")

    build_number = read_build_number_from_config_file(file_path)
    unless build_number.nil?
      new_build_number = bump_build_number(build_number)
      Action.sh("sed -i '' \"$(awk '/^BUILD_NUMBER/{ print NR; exit }' \"#{file_path}\")s/=.*/=#{new_build_number}/\" \"#{file_path}\"")
    end
  else
    UI.user_error!("#{file_path} not found")
  end
end

.update_xc_configs(new_version, new_version_short, internal_version) ⇒ Object

Update the ‘.xcconfig` files (the public one, and the internal one if it exists) with the new version strings.

Parameters:

  • new_version (String)

    The new version number to use as ‘VERSION_LONG` for the public xcconfig file

  • new_version_short (String)

    The new version number to use for ‘VERSION_SHORT` (for both public and internal xcconfig files)

  • internal_version (String)

    The new version number to use as ‘VERSION_LONG` for the interrnal xcconfig file, if it exists



230
231
232
233
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_version_helper.rb', line 230

def self.update_xc_configs(new_version, new_version_short, internal_version)
  update_xc_config(ENV['PUBLIC_CONFIG_FILE'], new_version, new_version_short)
  update_xc_config(ENV['INTERNAL_CONFIG_FILE'], internal_version, new_version_short) unless ENV['INTERNAL_CONFIG_FILE'].nil?
end

.verify_version(version) ⇒ String

Ensure that the version provided is only composed of number parts and return the validated string

Parameters:

  • version (String)

    The version string to validate

Returns:

  • (String)

    The version string, re-validated as being a string of the form ‘X.Y.Z.T`

Raises:

  • (UserError)

    Interrupts the lane with a user_error! if the version contains non-numberic parts



314
315
316
317
318
319
320
321
322
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_version_helper.rb', line 314

def self.verify_version(version)
  v_parts = get_version_parts(version)

  v_parts.each do |part|
    UI.user_error!('Version value can only contains numbers.') unless is_int?(part)
  end

  "#{v_parts[MAJOR_NUMBER]}.#{v_parts[MINOR_NUMBER]}.#{v_parts[HOTFIX_NUMBER]}.#{v_parts[BUILD_NUMBER]}"
end