Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ _None_

### New Features

_None_
- Add `ios_get_build_number` action to get the current build number from an `xcconfig` file. [#458]


### Bug Fixes

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
module Fastlane
module Actions
class IosGetBuildNumberAction < Action
def self.run(params)
require_relative '../../helper/ios/ios_version_helper'

xcconfig_file_path = params[:xcconfig_file_path]
Fastlane::Helper::Ios::VersionHelper.read_build_number_from_config_file(xcconfig_file_path)
end

#####################################################
# @!group Documentation
#####################################################

def self.description
'Gets the build number of the app'
end

def self.details
'Gets the build number of the app'
end

def self.available_options
[
FastlaneCore::ConfigItem.new(
key: :xcconfig_file_path,
env_name: 'FL_IOS_XCCONFIG_FILE_PATH',
description: 'Path to the .xcconfig file containing the build number',
type: String,
optional: false
),
]
end

def self.output
# Define the shared values you are going to provide
end

def self.return_value
# If you method provides a return value, you can describe here what it does
'Return the build number of the app'
end

def self.authors
# So no one will ever forget your contribution to fastlane :) You are awesome btw!
['Automattic']
end

def self.is_supported?(platform)
[:ios, :mac].include?(platform)
end
end
end
end
64 changes: 64 additions & 0 deletions spec/ios_get_build_number_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
require 'spec_helper'

describe Fastlane::Actions::IosGetBuildNumberAction do
describe 'getting the build number from the provided .xcconfig file' do
it 'parses an xcconfig file with keys without spacing and returns the correct build number' do
xcconfig_mock_content = <<~CONTENT
// a comment
VERSION_SHORT=6
VERSION_LONG=6.30.0
BUILD_NUMBER=1940
CONTENT

expect_build_number(xcconfig_mock_content: xcconfig_mock_content, expected_build_number: '1940')
end

it 'parses an xcconfig file with keys with spaces and returns a nil build number' do
xcconfig_mock_content = <<~CONTENT
VERSION_SHORT = 6
VERSION_LONG = 6.30.1
BUILD_NUMBER = 1940
CONTENT

expect_build_number(xcconfig_mock_content: xcconfig_mock_content, expected_build_number: nil)
end
Comment on lines +16 to +24
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was surprised by this because key = value is a valid xcconfig syntax. Looking at the pre-existing, underlying implementation, I can see why this is required given that we manually parse the xcconfig files

# Read the value of a given key from an `.xcconfig` file.
#
# @param [String] key The xcconfig key to get the value for
# @param [String] filePath The path to the `.xcconfig` file to read the value from
#
# @return [String] The value for the given key, or `nil` if the key was not found.
#
def self.read_from_config_file(key, filePath)
File.open(filePath, 'r') do |f|
f.each_line do |line|
line = line.strip()
return line.split('=')[1] if line.start_with?("#{key}=")
end
end
return nil
end

We should be able to replace that bespoke logic with the API provided by the xcodeproj gem like we do in Jetpack and WordPress iOS:

version_config_path = File.join(PROJECT_ROOT_FOLDER, 'config', 'Version.internal.xcconfig')
versions = Xcodeproj::Config.new(File.new(version_config_path)).to_hash

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like @iangmaia already started working on using xcodeproj instead of the manual parsing: #451

I decided to implement this as-is and update it as needed after Ian's PRs are fully merged into the project.


it 'parses an xcconfig file with an invalid format and returns a nil build number' do
xcconfig_mock_content = <<~CONTENT
VERSION_SHORT = 6
VERSION_LONG = 6.30.1
BUILD_NUMBER 1940
CONTENT

expect_build_number(xcconfig_mock_content: xcconfig_mock_content, expected_build_number: nil)
end

it 'parses an xcconfig file with no build number and returns a nil build number' do
xcconfig_mock_content = <<~CONTENT
VERSION_SHORT = 6
// a comment
CONTENT

expect_build_number(xcconfig_mock_content: xcconfig_mock_content, expected_build_number: nil)
end

it 'throws an error when the xcconfig file does not exist' do
expect do
run_described_fastlane_action(
xcconfig_file_path: 'file/not/found'
)
# Ruby error for 'No such file or directory': https://ruby-doc.org/core-2.7.4/SystemCallError.html
end.to raise_error(Errno::ENOENT)
end

def expect_build_number(xcconfig_mock_content:, expected_build_number:)
with_tmp_file(named: 'mock_xcconfig.xcconfig', content: xcconfig_mock_content) do |tmp_file_path|
build_number_result = run_described_fastlane_action(
xcconfig_file_path: tmp_file_path
)

expect(build_number_result).to eq(expected_build_number)
end
end
end
end