Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Intro to Continuous Integration at SoundCloud

Intro to Continuous Integration at SoundCloud

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.

Vincent Garrigues

September 04, 2014
Tweet

More Decks by Vincent Garrigues

Other Decks in Programming

Transcript

  1. View Slide

  2. Continuous Integration at
    SoundCloud
    iOSDevUK september 2014
    !
    Vincent Garrigues
    @garriguv

    View Slide

  3. What is CI?

    View Slide

  4. “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

    View Slide

  5. • trunk based development
    • lots of testing
    • CI pipeline

    View Slide

  6. View Slide

  7. View Slide

  8. View Slide

  9. View Slide

  10. View Slide

  11. View Slide

  12. View Slide

  13. View Slide

  14. View Slide

  15. Why CI?

    View Slide

  16. • move fast
    • keep codebase healthy
    • ship reliable apps

    View Slide

  17. • move fast
    • keep codebase healthy
    • ship reliable apps

    View Slide

  18. View Slide

  19. View Slide

  20. • started from scratch
    • months in development
    • millions of users

    View Slide

  21. iOS Crash Complaints (avg per Week)
    0
    35
    70
    105
    140
    April May June July August
    SoundCloud community team

    View Slide

  22. View Slide

  23. How to get
    started?

    View Slide

  24. Start simple and
    iterate

    View Slide

  25. • run unit test suite
    • α and β versions
    • sign .app builds

    View Slide

  26. View Slide

  27. Rake

    View Slide

  28. require 'rake'
    !
    desc 'say Hello World!'
    task :hello do
    puts 'Hello World!'
    end

    View Slide

  29. require 'rake'
    !
    desc 'say Hello World!'
    task :hello do
    puts 'Hello World!'
    end

    View Slide

  30. require 'rake'
    !
    desc 'say Hello World!'
    task :hello do
    puts 'Hello World!'
    end

    View Slide

  31. require 'rake'
    !
    desc 'say Hello World!'
    task :hello do
    puts 'Hello World!'
    end

    View Slide

  32. Running the unit tests

    View Slide

  33. use xcodebuild or xctool

    View Slide

  34. xcodebuild
    -workspace ci.xcworkspace
    -scheme ci
    -configuration Debug
    -sdk iphonesimulator7.1
    -destination "platform=iOS Simulator,name=iPhone Retina (4-inch)"
    test

    View Slide

  35. xcodebuild
    -workspace ci.xcworkspace
    -scheme ci
    -configuration Debug
    -sdk iphonesimulator7.1
    -destination "platform=iOS Simulator,name=iPhone Retina (4-inch)"
    test

    View Slide

  36. xcodebuild
    -workspace ci.xcworkspace
    -scheme ci
    -configuration Debug
    -sdk iphonesimulator7.1
    -destination "platform=iOS Simulator,name=iPhone Retina (4-inch)"
    test

    View Slide

  37. xcodebuild
    -workspace ci.xcworkspace
    -scheme ci
    -configuration Debug
    -sdk iphonesimulator7.1
    -destination "platform=iOS Simulator,name=iPhone Retina (4-inch)"
    test

    View Slide

  38. xcodebuild
    -workspace ci.xcworkspace
    -scheme ci
    -configuration Debug
    -sdk iphonesimulator7.1
    -destination "platform=iOS Simulator,name=iPhone Retina (4-inch)"
    test

    View Slide

  39. xcodebuild
    -workspace ci.xcworkspace
    -scheme ci
    -configuration Debug
    -sdk iphonesimulator7.1
    -destination "platform=iOS Simulator,name=iPhone Retina (4-inch)"
    clean

    View Slide

  40. xcodebuild
    -workspace ci.xcworkspace
    -scheme ci
    -configuration Debug
    -sdk iphonesimulator7.1
    -destination "platform=iOS Simulator,name=iPhone Retina (4-inch)"
    build

    View Slide

  41. rake tasks
    • rake clean
    • rake build
    • rake test

    View Slide

  42. α and β versions

    View Slide

  43. View Slide

  44. User-defined build settings

    View Slide

  45. View Slide

  46. View Slide

  47. View Slide

  48. View Slide

  49. View Slide

  50. Override user-defined
    build settings when
    running xcodebuild

    View Slide

  51. xcodebuild
    -workspace ci.xcworkspace
    -scheme ci
    -configuration Debug
    -sdk iphonesimulator7.1
    -destination "platform=iOS Simulator,name=iPhone Retina (4-inch)”
    build

    View Slide

  52. xcodebuild
    (…)
    VG_BUNDLE_ID=com.company.app-alpha
    build

    View Slide

  53. xcodebuild
    (…)
    VG_BUNDLE_ID=com.company.app-alpha
    VG_DISPLAY_NAME=α
    build

    View Slide

  54. xcodebuild
    (…)
    VG_BUNDLE_ID=com.company.app-alpha
    VG_DISPLAY_NAME=α
    VG_CODE_SIGNING="'iPhone
    Distribution: Vincent Garrigues'"
    build

    View Slide

  55. Where can we store
    those settings?

    View Slide

  56. We use a YAML file

    View Slide

  57. 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

    View Slide

  58. 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

    View Slide

  59. 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

    View Slide

  60. 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

    View Slide

  61. 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

    View Slide

  62. 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

    View Slide

  63. defaults:
    (..)
    !
    alpha:
    <<: *DEFAULTS
    app:
    <<: *APP_DEFAULTS
    display_name: α
    bundle_identifier: com.company.ci-test-alpha
    codesign:
    <<: *CODESIGN_DEFAULTS
    provisioning_profile: provisioning/alpha.mobileprovision

    View Slide

  64. defaults:
    (..)
    !
    alpha:
    <<: *DEFAULTS
    app:
    <<: *APP_DEFAULTS
    display_name: α
    bundle_identifier: com.company.ci-test-alpha
    codesign:
    <<: *CODESIGN_DEFAULTS
    provisioning_profile: provisioning/alpha.mobileprovision

    View Slide

  65. defaults:
    (..)
    !
    alpha:
    <<: *DEFAULTS
    app:
    <<: *APP_DEFAULTS
    display_name: α
    bundle_identifier: com.company.ci-test-alpha
    codesign:
    <<: *CODESIGN_DEFAULTS
    provisioning_profile: provisioning/alpha.mobileprovision

    View Slide

  66. rake build BUILD_ENV=alpha
    rake build BUILD_ENV=beta
    rake build BUILD_ENV=adhoc
    rake build BUILD_ENV=release

    View Slide

  67. rake build BUILD_ENV=alpha
    rake build BUILD_ENV=beta
    rake build BUILD_ENV=adhoc
    rake build BUILD_ENV=release

    View Slide

  68. rake build BUILD_ENV=alpha
    rake build BUILD_ENV=beta
    rake build BUILD_ENV=adhoc
    rake build BUILD_ENV=appstore

    View Slide

  69. rake build creates a .app

    View Slide

  70. We need a .ipa

    View Slide

  71. xcrun

    View Slide

  72. xcrun -v
    -sdk iphoneos
    PackageApplication
    ci-test-alpha.app
    -o ci-test-alpha.ipa
    --sign "iPhone Distribution: Vincent Garrigues"
    --embed provisioning/alpha.mobileprovision

    View Slide

  73. xcrun -v
    -sdk iphoneos
    PackageApplication
    ci-test-alpha.app
    -o ci-test-alpha.ipa
    --sign "iPhone Distribution: Vincent Garrigues"
    --embed provisioning/alpha.mobileprovision

    View Slide

  74. xcrun -v
    -sdk iphoneos
    PackageApplication
    ci-test-alpha.app
    -o ci-test-alpha.ipa
    --sign "iPhone Distribution: Vincent Garrigues"
    --embed provisioning/alpha.mobileprovision

    View Slide

  75. xcrun -v
    -sdk iphoneos
    PackageApplication
    ci-test-alpha.app
    -o ci-test-alpha.ipa
    --sign "iPhone Distribution: Vincent Garrigues"
    --embed provisioning/alpha.mobileprovision

    View Slide

  76. xcrun -v
    -sdk iphoneos
    PackageApplication
    ci-test-alpha.app
    -o ci-test-alpha.ipa
    --sign "iPhone Distribution: Vincent Garrigues"
    --embed provisioning/alpha.mobileprovision

    View Slide

  77. xcrun -v
    -sdk iphoneos
    PackageApplication
    ci-test-alpha.app
    -o ci-test-alpha.ipa
    --sign "iPhone Distribution: Vincent Garrigues"
    --embed provisioning/alpha.mobileprovision

    View Slide

  78. xcrun -v
    -sdk iphoneos
    PackageApplication
    ci-test-alpha.app
    -o ci-test-alpha.ipa
    --sign "iPhone Distribution: Vincent Garrigues"
    --embed provisioning/alpha.mobileprovision

    View Slide

  79. xcrun -v
    -sdk iphoneos
    PackageApplication
    ci-test-alpha.app
    -o ci-test-alpha.ipa
    --sign "iPhone Distribution: Vincent Garrigues"
    --embed provisioning/alpha.mobileprovision

    View Slide

  80. rake sign

    View Slide

  81. • rake clean
    • rake test
    • rake build
    • rake sign

    View Slide

  82. How can we use
    those rake tasks?

    View Slide

  83. View Slide

  84. • rake build sign BUILD_ENV=alpha
    • rake build sign BUILD_ENV=beta
    • rake build sign BUILD_ENV=adhoc

    View Slide

  85. • rake build sign BUILD_ENV=alpha
    • rake build sign BUILD_ENV=beta
    • rake build sign BUILD_ENV=adhoc

    View Slide

  86. • rake build sign BUILD_ENV=alpha
    • rake build sign BUILD_ENV=beta
    • rake build sign BUILD_ENV=adhoc

    View Slide

  87. • rake build sign BUILD_ENV=alpha
    • rake build sign BUILD_ENV=beta
    • rake build sign BUILD_ENV=adhoc
    • rake build sign BUILD_ENV=appstore

    View Slide

  88. Ad-Hoc and AppStore
    builds have the same
    bundle id

    View Slide

  89. rake build BUILD_ENV=appstore
    ci-test-appstore.app
    ci-test-appstore.dSYM
    ci-test-appstore.dSYM.zip

    View Slide

  90. 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

    View Slide

  91. 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

    View Slide

  92. 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

    View Slide

  93. 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

    View Slide

  94. The same binary,
    signed twice

    View Slide

  95. Sample project
    !
    github.com/garriguv/ci-test

    View Slide

  96. View Slide

  97. • linter (Xcode project, data
    model, acceptance tests,
    ruby, ObjC)
    • static analysis
    • unit tests (ruby and ObjC)
    • acceptance tests
    • custom app icon
    • deploy to HockeyApp
    • …

    View Slide

  98. View Slide

  99. View Slide

  100. Thank you!
    http://github.com/garriguv/ci-talk
    !
    !
    Vincent Garrigues
    @garriguv

    View Slide