8

I have two Jenkins jobs that run our functional tests. One job is for whenever something is submitted for code review and the other job runs whenever something is pushed to master.

Because these are functional tests they test entire flows of the application which end up modifiying the user state. The issue we are having right is that every job uses the same account so whenever two Jenkins jobs are running in parallel they modify the same account which can put them in an unexpected state and fail the test.

My plan was to use Jenkins' BUILD_NUMBER environment variable and by applying a bit of arthimetic to it I could have a guaranteed unique number for the job. This unique number could then be passed into xcodebuild as an environment variable and the tests could use this number to ensure that every Jenkins' is working on a unique account.

The problem is that I cannot find any way to pass environment variables into xcodebuild. I know it is possible for you to pass in user-defined build settings via xcodebuild (or xcargs if you're using Fastlane) but those values do not seem to be accessible as environment variables. They are accessible by the preprocessor and so you could use it to export the value to your Info.plist and then read it from there. But then you have baked these value into your binary and it cannot be changed unless you rebuild it which is not ideal. Also at this point in time I could just have Jenkins write to a file on disk and have the tests read from it. It is essentially the same functionality and saves me from having to pass in build settings.

Reid Main
  • 3,394
  • 3
  • 25
  • 42

2 Answers2

3

I remember using something like GCC_PREPROCESSOR_DEFINITIONS to pass my own var

I had to shell escape the quotes. I ended up coding it into my fastlane build file.

in ruby it looked like this:

tmp_other_flags = {
  GCC_PREPROCESSOR_DEFINITIONS: '"DISABLE_PUSH_NOTIFICATIONS=1"',
  TARGETED_DEVICE_FAMILY: '1',
  DEBUG: '1'
}
other_flags = tmp_other_flags.map do |k, v|
  "#{k.to_s.shellescape}=#{v.shellescape}"
end.join ' '
puts "___ Custom Flags also know as xcargs:"
puts other_flags

gym(
  clean: true,
  silent: false,
  project: proj_xcodeproj_file,
  archive_path: "build-ios-xcarchive",
  destination: 'generic/platform=iOS',
  use_legacy_build_api: true,
  output_directory: 'build-ios',
  output_name: "MyApp.ipa",
  export_method: 'ad-hoc',
  codesigning_identity: 'iPhone Distribution: company (12345)',
  provisioning_profile_path: './dl_profile_com.company.myapp.iphone.prod_ad_hoc.mobileprovision',
  scheme: 'MyApp',
  configuration: 'Debug',
  xcargs: other_flags
)

it ended up getting called in the shell something like this:

set -o pipefail && xcodebuild -scheme 'MyApp' -project 'platforms/ios/MyApp.xcodeproj' -configuration 'Debug' -destination 'generic/platform=iOS' -archivePath 'build-ios-xcarchive.xcarchive' GCC_PREPROCESSOR_DEFINITIONS=\"DISABLE_PUSH_NOTIFICATIONS\=1\" TARGETED_DEVICE_FAMILY=1 DEBUG=1 clean archive CODE_SIGN_IDENTITY='iPhone Distribution: My Company (Blah)' | tee '/Users/andxyz/Library/Logs/gym/MyApp-MyApp.log' | xcpretty

xcodebuild - how to define preprocessor macro?

So, perhaps you could pull in your own environment variable using ruby inside of fastlane. by adding your var into the GCC_PREPROCESSOR_DEFINITIONS section

ruby can access the environment, for example:

ENV.fetch('TERM_PROGRAM') #returns "iTerm.app" on my machine

so following along with above:

tmp_other_flags = {
  GCC_PREPROCESSOR_DEFINITIONS: "MY_VARIABLE=#{ENV.fetch('MY_VARIABLE')}" ,
  TARGETED_DEVICE_FAMILY: '1',
  DEBUG: '1'
}

HTH

Community
  • 1
  • 1
andxyz
  • 3,848
  • 2
  • 18
  • 18
  • 2
    We use something similar in our Fastfile `gym( scheme: options[:scheme], configuration: options[:config], use_legacy_build_api: options[:ad_hoc], clean: true, xcargs: "GCC_PREPROCESSOR_DEFINITIONS='${inherited} GIT_BRANCH=#{branch}'" ) ` As far as runtime variables accessed with `NSProcessInfo` I could have sworn there was a way but can't seem to find it – tapi Sep 13 '16 at 21:33
  • This is the mechanism I was referring to with "The only ability I have found is to pass in a user defined build setting which you could then output to the Info.plist and pull the information from there". I've used the xcargs parameter inside our Fastfile as well but I couldn't find anyway such that what I passed into xcargs was a environment variable, not something that was only accessible by the preprocessor macro. – Reid Main Sep 13 '16 at 21:39
2

Via @alisoftware, you can use xcargs to pass additional variables in:

gym(
  scheme: scheme,
  xcargs: {
    :PROVISIONING_PROFILE => 'profile-uuid',
    :PROVISIONING_PROFILE_SPECIFIER => 'match AppStore com.bigco.App'
  },
  codesigning_identity: "iPhone Distribution: BigCo, Inc. ()",
)

emits this during the build:

+---------------------+-------------------------------------------------------------------------------------------------+
|                                             Summary for gym 2.53.1                                                    |
+---------------------+-------------------------------------------------------------------------------------------------+
| scheme              | Bespoke-iOS                                                                                     |
| xcargs              | PROVISIONING_PROFILE=profile-uuid PROVISIONING_PROFILE_SPECIFIER=match\ AppStore\ com.bigco.App |
…
cbowns
  • 6,295
  • 5
  • 47
  • 64