Jenkins
Your personal butler for
continuous integration and
build automation in iOS
Friday, March 8, 13
Slide 2
Slide 2 text
Hi, I’m Ben
@subdigital (Twitter)
@bens (adn)
benscheirman.com
Friday, March 8, 13
Slide 3
Slide 3 text
I work for
Houston, TX
iOS, Android, Rails,
Coffee, Beer
I’m hiring!
Friday, March 8, 13
Slide 4
Slide 4 text
I make screencasts
Weekly screencasts on
iOS Development
$9/month
http://nsscreencast.com
NSScreencast
Friday, March 8, 13
Slide 5
Slide 5 text
Continuous Integration
Friday, March 8, 13
Slide 6
Slide 6 text
Integration Problems
• Machine-specific configuration
• Merge conflicts
• Contention on core files (project.pbxproj)
• Bad changes committed
• Updating certificates / profiles
Friday, March 8, 13
Slide 7
Slide 7 text
Actions, Pain, &
Frequency
Pain
Time between actions
http://martinfowler.com/bliki/FrequencyReducesDifficulty.html
Friday, March 8, 13
Slide 8
Slide 8 text
When something is
painful, do it more often
Friday, March 8, 13
Slide 9
Slide 9 text
“Many teams find that this
approach leads to significantly
reduced integration problems
and allows a team to develop
cohesive software more rapidly”
- Martin Fowler
Friday, March 8, 13
Slide 10
Slide 10 text
Fowler’s Tenets of CI
Friday, March 8, 13
Slide 11
Slide 11 text
Maintain a single
repository
Friday, March 8, 13
Slide 12
Slide 12 text
Automate the build
Friday, March 8, 13
Slide 13
Slide 13 text
Build passes or fails
Friday, March 8, 13
Slide 14
Slide 14 text
Everyone commits to
master every day
Friday, March 8, 13
Slide 15
Slide 15 text
Build runs on every
commit
Friday, March 8, 13
Slide 16
Slide 16 text
Easy to retrieve
latest build
Friday, March 8, 13
Slide 17
Slide 17 text
Automate Deployment
Friday, March 8, 13
Slide 18
Slide 18 text
...more!
Friday, March 8, 13
Slide 19
Slide 19 text
Ben's Tenet of CI:
Friday, March 8, 13
Slide 20
Slide 20 text
GIVE A CRAP
WHEN THE BUILD
IS BROKEN
Friday, March 8, 13
Slide 21
Slide 21 text
Build a culture
concerned with quality
Friday, March 8, 13
Slide 22
Slide 22 text
Friday, March 8, 13
Slide 23
Slide 23 text
Friday, March 8, 13
Slide 24
Slide 24 text
Friday, March 8, 13
Slide 25
Slide 25 text
Friday, March 8, 13
Slide 26
Slide 26 text
CI Servers
• Jenkins
• Travis
• TeamCity
• CruiseControl (.NET)
• CI Joe
Friday, March 8, 13
Slide 27
Slide 27 text
Installing Jenkins
$ brew install jenkins
Friday, March 8, 13
Slide 28
Slide 28 text
Useful plugins
Git plugin
Xcode
Testflight
Sounds
HTML Publisher
Friday, March 8, 13
Slide 29
Slide 29 text
More useful plugins
Github Plugin
IM Notifier
Status Monitor
Hipchat Notifier (or Campfire)
100’s of others
Friday, March 8, 13
Slide 30
Slide 30 text
So we have a CI Server,
now what?
Friday, March 8, 13
Slide 31
Slide 31 text
Have it run the build on
every commit
Friday, March 8, 13
Slide 32
Slide 32 text
What is “the build” ?
Friday, March 8, 13
Slide 33
Slide 33 text
⌘B
Friday, March 8, 13
Slide 34
Slide 34 text
A Definition of
“the Build”
Friday, March 8, 13
Slide 35
Slide 35 text
Compiles
Runs Static
Analyzer
Runs Unit Tests
Packages IPAs
Generates Documentation
Archives dSYMs
Uploads to
Testflight
Increments build
number
Installs the latest
distribution
certificates & profiles
Publishes Code
Coverage Reports
Inspects
for code
smells
Friday, March 8, 13
Slide 36
Slide 36 text
1command
Friday, March 8, 13
Slide 37
Slide 37 text
Set up your CI Machine
just like your Dev
Machines
Friday, March 8, 13
Slide 38
Slide 38 text
Our Mission:
Figure out how to do all that....
ON THE COMMAND LINE
Friday, March 8, 13
Slide 39
Slide 39 text
Rake
Easy
Awesome
Better than Bash
scripting
Friday, March 8, 13
Slide 40
Slide 40 text
Building the Xcode
Project
xcodebuild -workspace Foo.xcworkspace \
-scheme Foo \
-sdk iphonesimulator \
-configuration Debug \
ONLY_ACTIVE_ARCH=NO
clean build
Friday, March 8, 13
Red / Green Test Output
https://gist.github.com/subdigital/3931414 * Works best with Kiwi
Friday, March 8, 13
Slide 43
Slide 43 text
Xcodebuild-rb
XcodeBuild::Tasks::BuildTask.new do |t|
t.sdk = "iphoneos"
t.configuration = "Release"
t.workspace = workspace
t.scheme = scheme
t.add_build_setting("ONLY_ACTIVE_ARCH", "NO")
t.after_build do |build|
derived_dir = build.environment['BUILT_PRODUCTS_DIR']
`rm -rf #{output_dir} && mkdir -p #{output_dir}"`
`cp -R #{derived_dir}/* #{output_dir}"`
end
t.formatter =
XcodeBuild::Formatters::ProgressFormatter.new
end
Friday, March 8, 13
Slide 44
Slide 44 text
Xcodebuild-rb
$ rake -T
rake xcode:archive # Creates an archive build of
the specified target(s).
rake xcode:build # Builds the specified
target(s).
rake xcode:clean # Cleans the build using the
same build settings.
rake xcode:cleanbuild # Builds the specified
target(s) from a clean slate.
rake xcode:install # Builds and installs the
target
rake xcode:settings # Prints the full Xcode build
settings
Friday, March 8, 13
Slide 45
Slide 45 text
Why Xcodebuild-rb?
• Integration with Rake
• Easily find BUILT_PRODUCTS_DIR
• Progress Formatter!
Friday, March 8, 13
Slide 46
Slide 46 text
Progress formatter
Friday, March 8, 13
Slide 47
Slide 47 text
Building an IPA
/usr/bin/xcrun -sdk iphoneos \
PackageApplication \
-v \
"build/Foo.app"
-o "build/Foo.ipa"
Friday, March 8, 13
Slide 48
Slide 48 text
What about Code
Signing?
Friday, March 8, 13
Slide 49
Slide 49 text
Installing certificates
TIP: create a keychain for Jenkins
Friday, March 8, 13
Dir["provisioning/*.mobileprovision"].each do |f|
`scripts/install_provisioning_profile.sh #{f}`
end
Installing Provisioning
Profiles
https://gist.github.com/subdigital/5049635
Friday, March 8, 13
Slide 52
Slide 52 text
BOOM.
Renewed Certificate?
Updated ad-hoc profile?
just drop in provisioning/
Friday, March 8, 13