Class: Fastlane::Actions::GetVersionNumberAction

Inherits:
Fastlane::Action show all
Defined in:
fastlane/lib/fastlane/actions/get_version_number.rb

Constant Summary

Constants inherited from Fastlane::Action

Fastlane::Action::AVAILABLE_CATEGORIES, Fastlane::Action::RETURN_TYPES

Documentation collapse

Class Method Summary collapse

Methods inherited from Fastlane::Action

action_name, author, deprecated_notes, lane_context, method_missing, other_action, return_value, sample_return_value, shell_out_should_use_bundle_exec?, step_text

Class Method Details

.authorsObject



162
163
164
# File 'fastlane/lib/fastlane/actions/get_version_number.rb', line 162

def self.authors
  ["Liquidsoul", "joshdholtz"]
end

.available_optionsObject



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'fastlane/lib/fastlane/actions/get_version_number.rb', line 135

def self.available_options
  [
    FastlaneCore::ConfigItem.new(key: :xcodeproj,
                       env_name: "FL_VERSION_NUMBER_PROJECT",
                       description: "Path to the main Xcode project to read version number from, optional. By default will use the first Xcode project found within the project root directory",
                       optional: true,
                       verify_block: proc do |value|
                         UI.user_error!("Please pass the path to the project, not the workspace") if value.end_with?(".xcworkspace")
                         UI.user_error!("Could not find Xcode project at path '#{File.expand_path(value)}'") if !File.exist?(value) && !Helper.test?
                       end),
    FastlaneCore::ConfigItem.new(key: :target,
                       env_name: "FL_VERSION_NUMBER_TARGET",
                       description: "Target name, optional. Will be needed if you have more than one non-test target to avoid being prompted to select one",
                       optional: true),
    FastlaneCore::ConfigItem.new(key: :configuration,
                       env_name: "FL_VERSION_NUMBER_CONFIGURATION",
                       description: "Configuration name, optional. Will be needed if you have altered the configurations from the default or your version number depends on the configuration selected",
                       optional: true)
  ]
end

.categoryObject



184
185
186
# File 'fastlane/lib/fastlane/actions/get_version_number.rb', line 184

def self.category
  :project
end

.descriptionObject



127
128
129
# File 'fastlane/lib/fastlane/actions/get_version_number.rb', line 127

def self.description
  "Get the version number of your project"
end

.detailsObject



131
132
133
# File 'fastlane/lib/fastlane/actions/get_version_number.rb', line 131

def self.details
  "This action will return the current version number set on your project."
end

.example_codeObject



170
171
172
173
174
175
176
177
178
# File 'fastlane/lib/fastlane/actions/get_version_number.rb', line 170

def self.example_code
  [
    'version = get_version_number(xcodeproj: "Project.xcodeproj")',
    'version = get_version_number(
      xcodeproj: "Project.xcodeproj",
      target: "App"
    )'
  ]
end

.get_plist!(folder, target, configuration = nil) ⇒ Object



87
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
# File 'fastlane/lib/fastlane/actions/get_version_number.rb', line 87

def self.get_plist!(folder, target, configuration = nil)
  plist_files = target.resolved_build_setting("INFOPLIST_FILE")
  plist_files_count = plist_files.values.compact.uniq.count

  # Get plist file for specified configuration
  # Or: Prompt for configuration if plist has different files in each configurations
  # Else: Get first(only) plist value
  if configuration
    plist_file = plist_files[configuration]
  elsif plist_files_count > 1
    options = plist_files.keys
    selected = UI.select("What build configuration would you like to use?", options)
    plist_file = plist_files[selected]
  else
    plist_file = plist_files.values.first
  end

  # $(SRCROOT) is the path of where the XcodeProject is
  # We can just set this as empty string since we join with `folder` below
  if plist_file.include?("$(SRCROOT)/")
    plist_file.gsub!("$(SRCROOT)/", "")
  end

  plist_file = File.absolute_path(File.join(folder, plist_file))
  UI.user_error!("Cannot find plist file: #{plist_file}") unless File.exist?(plist_file)

  plist_file
end

.get_project!(folder) ⇒ Object



36
37
38
39
40
41
42
43
44
# File 'fastlane/lib/fastlane/actions/get_version_number.rb', line 36

def self.get_project!(folder)
  require 'xcodeproj'
  project_path = Dir.glob("#{folder}/*.xcodeproj").first
  if project_path
    return Xcodeproj::Project.open(project_path)
  else
    UI.user_error!("Unable to find Xcode project in folder: #{folder}")
  end
end

.get_target!(project, target_name) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'fastlane/lib/fastlane/actions/get_version_number.rb', line 46

def self.get_target!(project, target_name)
  targets = project.targets

  # Prompt targets if no name
  unless target_name

    # Gets non-test targets
    non_test_targets = targets.reject do |t|
      # Not all targets respond to `test_target_type?`
      t.respond_to?(:test_target_type?) && t.test_target_type?
    end

    # Returns if only one non-test target
    if non_test_targets.count == 1
      return targets.first
    end

    options = targets.map(&:name)
    target_name = UI.select("What target would you like to use?", options)
  end

  # Find target
  target = targets.find do |t|
    t.name == target_name
  end
  UI.user_error!("Cannot find target named '#{target_name}'") unless target

  target
end

.get_version_number_from_build_settings!(target, variable, configuration = nil) ⇒ Object



76
77
78
79
80
81
82
83
84
85
# File 'fastlane/lib/fastlane/actions/get_version_number.rb', line 76

def self.get_version_number_from_build_settings!(target, variable, configuration = nil)
  target.build_configurations.each do |config|
    if configuration.nil? || config.name == configuration
      value = config.build_settings[variable]
      return value if value
    end
  end

  UI.user_error!("Unable to find Xcode build setting: #{variable}")
end

.get_version_number_from_plist!(plist_file) ⇒ Object



116
117
118
119
120
121
# File 'fastlane/lib/fastlane/actions/get_version_number.rb', line 116

def self.get_version_number_from_plist!(plist_file)
  plist = Xcodeproj::Plist.read_from_path(plist_file)
  UI.user_error!("Unable to read plist: #{plist_file}") unless plist

  plist["CFBundleShortVersionString"]
end

.is_supported?(platform) ⇒ Boolean

Returns:



166
167
168
# File 'fastlane/lib/fastlane/actions/get_version_number.rb', line 166

def self.is_supported?(platform)
  [:ios, :mac].include?(platform)
end

.outputObject



156
157
158
159
160
# File 'fastlane/lib/fastlane/actions/get_version_number.rb', line 156

def self.output
  [
    ['VERSION_NUMBER', 'The version number']
  ]
end

.return_typeObject



180
181
182
# File 'fastlane/lib/fastlane/actions/get_version_number.rb', line 180

def self.return_type
  :string
end

.run(params) ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'fastlane/lib/fastlane/actions/get_version_number.rb', line 10

def self.run(params)
  folder = params[:xcodeproj] ? File.join(params[:xcodeproj], '..') : '.'
  target_name = params[:target]
  configuration = params[:configuration]

  # Get version_number
  project = get_project!(folder)
  target = get_target!(project, target_name)
  plist_file = get_plist!(folder, target, configuration)
  version_number = get_version_number_from_plist!(plist_file)

  # Get from build settings if needed (ex: $(MARKETING_VERSION) is default in Xcode 11)
  if version_number =~ /\$\(([\w\-]+)\)/
    version_number = get_version_number_from_build_settings!(target, $1, configuration)
  # ${MARKETING_VERSION} also works
  elsif version_number =~ /\$\{([\w\-]+)\}/
    version_number = get_version_number_from_build_settings!(target, $1, configuration)
  end

  # Store the number in the shared hash
  Actions.lane_context[SharedValues::VERSION_NUMBER] = version_number

  # Return the version number because Swift might need this return value
  return version_number
end