Upload
garriguv
View
518
Download
3
Embed Size (px)
DESCRIPTION
In the past year at SoundCloud, we've improved our CI from a single machine running our limited unit test suite to several machines running a linter, unit tests, acceptance tests and building several versions of our app including the AppStore version for every commit. This enabled us to move away from pull-requests and code reviews and use trunk based development and pairing, as well as scale the team from 3 to 7 developers. We've stopped relying on Xcode Schemes for builds, we're using instead command line tools and compile-time parameters to automatically build internal versions of our app and distribute it internally. In order to make our release process more reliable, the AppStore version of the app is created by re-signing an AdHoc build. This enables us to test the exact same binary that will be submitted to the AppStore. This talk will focus on 3 areas of our continuous integration: testing, building with user defined build settings and signing apps.
Citation preview
Continuous Integration at SoundCloud
iOSDevUK september 2014 !
Vincent Garrigues @garriguv
What is CI?
“Continuous integration (CI) is the practice, in software engineering, of merging all developer working copies with a shared mainline several times a day.”
http://en.wikipedia.org/wiki/Continuous_integration
• trunk based development • lots of testing • CI pipeline
Why CI?
• move fast • keep codebase healthy • ship reliable apps
• move fast • keep codebase healthy • ship reliable apps
• started from scratch • months in development • millions of users
iOS Crash Complaints (avg per Week)
0
35
70
105
140
April May June July August
SoundCloud community team
How to get started?
Start simple and iterate
• run unit test suite • α and β versions • sign .app builds
Rake
require 'rake' !desc 'say Hello World!' task :hello do puts 'Hello World!' end
require 'rake' !desc 'say Hello World!' task :hello do puts 'Hello World!' end
require 'rake' !desc 'say Hello World!' task :hello do puts 'Hello World!' end
require 'rake' !desc 'say Hello World!' task :hello do puts 'Hello World!' end
Running the unit tests
use xcodebuild or xctool
xcodebuild -workspace ci.xcworkspace -scheme ci -configuration Debug -sdk iphonesimulator7.1 -destination "platform=iOS Simulator,name=iPhone Retina (4-inch)" test
xcodebuild -workspace ci.xcworkspace -scheme ci -configuration Debug -sdk iphonesimulator7.1 -destination "platform=iOS Simulator,name=iPhone Retina (4-inch)" test
xcodebuild -workspace ci.xcworkspace -scheme ci -configuration Debug -sdk iphonesimulator7.1 -destination "platform=iOS Simulator,name=iPhone Retina (4-inch)" test
xcodebuild -workspace ci.xcworkspace -scheme ci -configuration Debug -sdk iphonesimulator7.1 -destination "platform=iOS Simulator,name=iPhone Retina (4-inch)" test
xcodebuild -workspace ci.xcworkspace -scheme ci -configuration Debug -sdk iphonesimulator7.1 -destination "platform=iOS Simulator,name=iPhone Retina (4-inch)" test
xcodebuild -workspace ci.xcworkspace -scheme ci -configuration Debug -sdk iphonesimulator7.1 -destination "platform=iOS Simulator,name=iPhone Retina (4-inch)" clean
xcodebuild -workspace ci.xcworkspace -scheme ci -configuration Debug -sdk iphonesimulator7.1 -destination "platform=iOS Simulator,name=iPhone Retina (4-inch)" build
rake tasks • rake clean • rake build • rake test
α and β versions
User-defined build settings
Override user-defined build settings when
running xcodebuild
xcodebuild -workspace ci.xcworkspace -scheme ci -configuration Debug -sdk iphonesimulator7.1 -destination "platform=iOS Simulator,name=iPhone Retina (4-inch)” build
xcodebuild (…) VG_BUNDLE_ID=com.company.app-alpha build
xcodebuild (…) VG_BUNDLE_ID=com.company.app-alpha VG_DISPLAY_NAME=α build
xcodebuild (…) VG_BUNDLE_ID=com.company.app-alpha VG_DISPLAY_NAME=α VG_CODE_SIGNING="'iPhone Distribution: Vincent Garrigues'" build
Where can we store those settings?
We use a YAML file
defaults: &DEFAULTS app: &APP_DEFAULTS workspace: ci.xcworkspace scheme: ci configuration: Release display_name: ci-test bundle_identifier: com.company.ci-test codesign: &CODESIGN_DEFAULTS signing_identity: '"iPhone Distribution: Vincent Garrigues (X73EL3QFZB)"' provisioning_profile: provisioning/app_store.mobileprovision
defaults: &DEFAULTS app: &APP_DEFAULTS workspace: ci.xcworkspace scheme: ci configuration: Release display_name: ci-test bundle_identifier: com.company.ci-test codesign: &CODESIGN_DEFAULTS signing_identity: '"iPhone Distribution: Vincent Garrigues (X73EL3QFZB)"' provisioning_profile: provisioning/app_store.mobileprovision
defaults: &DEFAULTS app: &APP_DEFAULTS workspace: ci.xcworkspace scheme: ci configuration: Release display_name: ci-test bundle_identifier: com.company.ci-test codesign: &CODESIGN_DEFAULTS signing_identity: '"iPhone Distribution: Vincent Garrigues (X73EL3QFZB)"' provisioning_profile: provisioning/app_store.mobileprovision
defaults: &DEFAULTS app: &APP_DEFAULTS workspace: ci.xcworkspace scheme: ci configuration: Release display_name: ci-test bundle_identifier: com.company.ci-test codesign: &CODESIGN_DEFAULTS signing_identity: '"iPhone Distribution: Vincent Garrigues (X73EL3QFZB)"' provisioning_profile: provisioning/app_store.mobileprovision
defaults: &DEFAULTS app: &APP_DEFAULTS workspace: ci.xcworkspace scheme: ci configuration: Release display_name: ci-test bundle_identifier: com.company.ci-test codesign: &CODESIGN_DEFAULTS signing_identity: '"iPhone Distribution: Vincent Garrigues (X73EL3QFZB)"' provisioning_profile: provisioning/app_store.mobileprovision
defaults: &DEFAULTS app: &APP_DEFAULTS workspace: ci.xcworkspace scheme: ci configuration: Release display_name: ci-test bundle_identifier: com.company.ci-test codesign: &CODESIGN_DEFAULTS signing_identity: '"iPhone Distribution: Vincent Garrigues (X73EL3QFZB)"' provisioning_profile: provisioning/app_store.mobileprovision
defaults: (..) !alpha: <<: *DEFAULTS app: <<: *APP_DEFAULTS display_name: α bundle_identifier: com.company.ci-test-alpha codesign: <<: *CODESIGN_DEFAULTS provisioning_profile: provisioning/alpha.mobileprovision
defaults: (..) !alpha: <<: *DEFAULTS app: <<: *APP_DEFAULTS display_name: α bundle_identifier: com.company.ci-test-alpha codesign: <<: *CODESIGN_DEFAULTS provisioning_profile: provisioning/alpha.mobileprovision
defaults: (..) !alpha: <<: *DEFAULTS app: <<: *APP_DEFAULTS display_name: α bundle_identifier: com.company.ci-test-alpha codesign: <<: *CODESIGN_DEFAULTS provisioning_profile: provisioning/alpha.mobileprovision
rake build BUILD_ENV=alpha rake build BUILD_ENV=beta rake build BUILD_ENV=adhoc rake build BUILD_ENV=release
rake build BUILD_ENV=alpha rake build BUILD_ENV=beta rake build BUILD_ENV=adhoc rake build BUILD_ENV=release
rake build BUILD_ENV=alpha rake build BUILD_ENV=beta rake build BUILD_ENV=adhoc rake build BUILD_ENV=appstore
rake build creates a .app
We need a .ipa
xcrun
xcrun -v -sdk iphoneos PackageApplication ci-test-alpha.app -o ci-test-alpha.ipa --sign "iPhone Distribution: Vincent Garrigues" --embed provisioning/alpha.mobileprovision
xcrun -v -sdk iphoneos PackageApplication ci-test-alpha.app -o ci-test-alpha.ipa --sign "iPhone Distribution: Vincent Garrigues" --embed provisioning/alpha.mobileprovision
xcrun -v -sdk iphoneos PackageApplication ci-test-alpha.app -o ci-test-alpha.ipa --sign "iPhone Distribution: Vincent Garrigues" --embed provisioning/alpha.mobileprovision
xcrun -v -sdk iphoneos PackageApplication ci-test-alpha.app -o ci-test-alpha.ipa --sign "iPhone Distribution: Vincent Garrigues" --embed provisioning/alpha.mobileprovision
xcrun -v -sdk iphoneos PackageApplication ci-test-alpha.app -o ci-test-alpha.ipa --sign "iPhone Distribution: Vincent Garrigues" --embed provisioning/alpha.mobileprovision
xcrun -v -sdk iphoneos PackageApplication ci-test-alpha.app -o ci-test-alpha.ipa --sign "iPhone Distribution: Vincent Garrigues" --embed provisioning/alpha.mobileprovision
xcrun -v -sdk iphoneos PackageApplication ci-test-alpha.app -o ci-test-alpha.ipa --sign "iPhone Distribution: Vincent Garrigues" --embed provisioning/alpha.mobileprovision
xcrun -v -sdk iphoneos PackageApplication ci-test-alpha.app -o ci-test-alpha.ipa --sign "iPhone Distribution: Vincent Garrigues" --embed provisioning/alpha.mobileprovision
rake sign
• rake clean • rake test • rake build • rake sign
How can we use those rake tasks?
• rake build sign BUILD_ENV=alpha • rake build sign BUILD_ENV=beta • rake build sign BUILD_ENV=adhoc
• rake build sign BUILD_ENV=alpha • rake build sign BUILD_ENV=beta • rake build sign BUILD_ENV=adhoc
• rake build sign BUILD_ENV=alpha • rake build sign BUILD_ENV=beta • rake build sign BUILD_ENV=adhoc
• rake build sign BUILD_ENV=alpha • rake build sign BUILD_ENV=beta • rake build sign BUILD_ENV=adhoc • rake build sign BUILD_ENV=appstore
Ad-Hoc and AppStore builds have the same
bundle id
rake build BUILD_ENV=appstore
ci-test-appstore.app ci-test-appstore.dSYM ci-test-appstore.dSYM.zip
rake build BUILD_ENV=appstore rake ipa BUILD_ENV=appstore
ci-test-appstore.app ci-test-appstore.dSYM ci-test-appstore.dSYM.zip ci-test-appstore.ipa
rake build BUILD_ENV=appstore rake ipa BUILD_ENV=appstore rake ipa BUILD_ENV=adhoc
ci-test-appstore.app ci-test-appstore.dSYM ci-test-appstore.dSYM.zip ci-test-appstore.ipa ci-test-adhoc.ipa
rake build BUILD_ENV=appstore rake ipa BUILD_ENV=appstore rake ipa BUILD_ENV=adhoc
ci-test-appstore.app ci-test-appstore.dSYM ci-test-appstore.dSYM.zip ci-test-appstore.ipa ci-test-adhoc.ipa
ci-test-appstore.app ci-test-appstore.dSYM ci-test-appstore.dSYM.zip ci-test-appstore.ipa ci-test-adhoc.ipa
rake build BUILD_ENV=appstore rake ipa BUILD_ENV=appstore rake ipa BUILD_ENV=adhoc
The same binary, signed twice
Sample project !
github.com/garriguv/ci-test
• linter (Xcode project, data model, acceptance tests, ruby, ObjC)
• static analysis • unit tests (ruby and ObjC) • acceptance tests • custom app icon • deploy to HockeyApp • …
Thank you!http://github.com/garriguv/ci-talk
!
!
Vincent Garrigues @garriguv