Slide 1

Slide 1 text

Using Continuous Integration with Xamarin Apps Senior Engineer, Olo @gshackles [email protected] Greg Shackles

Slide 2

Slide 2 text

Ship It A Cautionary Tale

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

The Worst by Vitruvius This app is just…the worst.

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

How can we deliver Continuous Awesomeness?

Slide 13

Slide 13 text

Continuous Integration Let your tools work for you on every commit

Slide 14

Slide 14 text

What is Continuous Integration?

Slide 15

Slide 15 text

What is Continuous Integration? VCS

Slide 16

Slide 16 text

What is Continuous Integration? VCS CI Server

Slide 17

Slide 17 text

What is Continuous Integration? VCS CI Server CI Agent

Slide 18

Slide 18 text

What is Continuous Integration? VCS CI Server CI Agent

Slide 19

Slide 19 text

Options TFS Jenkins …and more

Slide 20

Slide 20 text

Delivery TestFlight HockeyApp …and more

Slide 21

Slide 21 text

CI with Xamarin Apps

Slide 22

Slide 22 text

Build Agent Setup

Slide 23

Slide 23 text

Build Agent Setup ■ OS X machine for iOS builds - Mac Mini works well

Slide 24

Slide 24 text

Build Agent Setup ■ OS X machine for iOS builds - Mac Mini works well ■ OS X or Windows machine for Android

Slide 25

Slide 25 text

Build Agent Setup ■ OS X machine for iOS builds - Mac Mini works well ■ OS X or Windows machine for Android ■ Install platform SDKs

Slide 26

Slide 26 text

Build Agent Setup ■ OS X machine for iOS builds - Mac Mini works well ■ OS X or Windows machine for Android ■ Install platform SDKs ■ Install Xamarin

Slide 27

Slide 27 text

Build Agent Setup ■ OS X machine for iOS builds - Mac Mini works well ■ OS X or Windows machine for Android ■ Install platform SDKs ■ Install Xamarin ■ Install agent software for chosen CI server

Slide 28

Slide 28 text

iOS: Build mdtool build -t:Build -c:AppStore MyAwesomeApp.sln /Applications/Xamarin Studio.app/Contents/MacOS/mdtool

Slide 29

Slide 29 text

iOS: Package zip -r -y MyAwesomeIosApp.zip path/to/MyAwesomeIosApp.app

Slide 30

Slide 30 text

Android: Build Windows: msbuild OS X: xbuild xbuild build /t:Build /p:Configuration=Release MyAwesomeApp.sln

Slide 31

Slide 31 text

Android: Package (Part 1) Windows: msbuild OS X: xbuild xbuild build /t:PackageForAndroid /p:Configuration=Release MyAwesomeAndroidApp.csproj

Slide 32

Slide 32 text

Android: Package (Part 2) jarsigner -sigalg SHA1withRSA -digestalg SHA1 -keystore -storepass -signedjar path/to/MyAwesomeAndroidApp-Signed.apk path/to/MyAwesomeAndroidApp.apk

Slide 33

Slide 33 text

Android: Package (Part 2) jarsigner -sigalg SHA1withRSA -digestalg SHA1 -keystore -storepass -signedjar path/to/MyAwesomeAndroidApp-Signed.apk path/to/MyAwesomeAndroidApp.apk zipalign -f -v 4 path/to/MyAwesomeAndroidApp-Signed.apk path/to/MyAwesomeAndroidApp-Aligned.apk

Slide 34

Slide 34 text

Package Restore NuGet mono NuGet.exe restore path/to/App.sln

Slide 35

Slide 35 text

Package Restore NuGet mono NuGet.exe restore path/to/App.sln Xamarin Components mono xamarin-component.exe restore path/to/App.sln

Slide 36

Slide 36 text

Xamarin.UITest Run using any NUnit runner nunit-console4 path/to/TestAssembly.dll -xml testresults.xml

Slide 37

Slide 37 text

Pro Tip: Allow Build to Access UI jetbrains.teamcity.BuildAgent.plist

Slide 38

Slide 38 text

Pro Tip: Allow Build to Access UI jetbrains.teamcity.BuildAgent.plist ■ Set username UserName your_user

Slide 39

Slide 39 text

Pro Tip: Allow Build to Access UI jetbrains.teamcity.BuildAgent.plist ■ Set username UserName your_user ■ Copy to /Library/LaunchAgents

Slide 40

Slide 40 text

TestCloud Run your UI tests on hundreds of devices test-cloud.exe submit path/to/myapp.[ipa|apk] --devices --series "master" --locale "en_US" --assembly-dir “path/to/bin“ --nunit-xml testresults.xml

Slide 41

Slide 41 text

FAKE #r @"FAKE/tools/FakeLib.dll"
 #load "build-helpers/iOS.fsx"
 
 open Fake
 
 Target "ios-build" (fun () ->
 iOS.build "Debug|iPhoneSimulator"
 )
 
 Target "ios-adhoc" (fun () ->
 iOS.build "AdHoc|iPhone"
 )
 
 Target "ios-testflight" (fun () ->
 iOS.publishToTestFlight()
 )
 
 "ios-adhoc"
 ==> "ios-testflight"
 
 RunTarget()


Slide 42

Slide 42 text

FAKE #r @"FAKE/tools/FakeLib.dll"
 #load "build-helpers/iOS.fsx"
 
 open Fake
 
 Target "ios-build" (fun () ->
 iOS.build "Debug|iPhoneSimulator"
 )
 
 Target "ios-adhoc" (fun () ->
 iOS.build "AdHoc|iPhone"
 )
 
 Target "ios-testflight" (fun () ->
 iOS.publishToTestFlight()
 )
 
 "ios-adhoc"
 ==> "ios-testflight"
 
 RunTarget()
 TeamCityHelper.PublishArtifact "path/to/App.zip"
 Helpers

Slide 43

Slide 43 text

FAKE #r @"FAKE/tools/FakeLib.dll"
 #load "build-helpers/iOS.fsx"
 
 open Fake
 
 Target "ios-build" (fun () ->
 iOS.build "Debug|iPhoneSimulator"
 )
 
 Target "ios-adhoc" (fun () ->
 iOS.build "AdHoc|iPhone"
 )
 
 Target "ios-testflight" (fun () ->
 iOS.publishToTestFlight()
 )
 
 "ios-adhoc"
 ==> "ios-testflight"
 
 RunTarget()
 TeamCityHelper.PublishArtifact "path/to/App.zip"
 TeamCityHelper.sendTeamCityNUnitImport "results.xml"
 Helpers

Slide 44

Slide 44 text

FAKE #r @"FAKE/tools/FakeLib.dll"
 #load "build-helpers/iOS.fsx"
 
 open Fake
 
 Target "ios-build" (fun () ->
 iOS.build "Debug|iPhoneSimulator"
 )
 
 Target "ios-adhoc" (fun () ->
 iOS.build "AdHoc|iPhone"
 )
 
 Target "ios-testflight" (fun () ->
 iOS.publishToTestFlight()
 )
 
 "ios-adhoc"
 ==> "ios-testflight"
 
 RunTarget()
 TeamCityHelper.PublishArtifact "path/to/App.zip"
 TeamCityHelper.sendTeamCityNUnitImport "results.xml"
 TestFlight(fun p ->
 {p with
 File: "path/to/App.app"
 Notes: "Now with 42% more awesome!"
 })
 Helpers

Slide 45

Slide 45 text

FAKE #r @"FAKE/tools/FakeLib.dll"
 #load "build-helpers/iOS.fsx"
 
 open Fake
 
 Target "ios-build" (fun () ->
 iOS.build "Debug|iPhoneSimulator"
 )
 
 Target "ios-adhoc" (fun () ->
 iOS.build "AdHoc|iPhone"
 )
 
 Target "ios-testflight" (fun () ->
 iOS.publishToTestFlight()
 )
 
 "ios-adhoc"
 ==> "ios-testflight"
 
 RunTarget()
 TeamCityHelper.PublishArtifact "path/to/App.zip"
 TeamCityHelper.sendTeamCityNUnitImport "results.xml"
 HipChatNotification(fun p ->
 {p with 
 From = "App BuildBot"
 Message = "Published to TestFlight"
 Color = "green"
 })
 TestFlight(fun p ->
 {p with
 File: "path/to/App.app"
 Notes: "Now with 42% more awesome!"
 })
 Helpers

Slide 46

Slide 46 text

FAKE Helpers for Xamarin “path/to/MyApp.sln“ |> RestoreComponents (fun defaults -> {defaults with ToolPath = “...” })


Slide 47

Slide 47 text

FAKE Helpers for Xamarin “path/to/MyApp.sln“ |> RestoreComponents (fun defaults -> {defaults with ToolPath = “...” })
 iOSBuild (fun defaults ->
 {defaults with
 ProjectPath = “path/to/MyApp.sln”
 Configuration = “AppStore”
 Target = “Build”
 })


Slide 48

Slide 48 text

FAKE Helpers for Xamarin iOSBuild (fun defaults ->
 {defaults with
 ProjectPath = “path/to/MyApp.sln”
 Configuration = “AppStore”
 Target = “Build”
 })
 “path/to/MyApp.sln“ |> RestoreComponents (fun defaults -> {defaults with ToolPath = “...” })
 AndroidPackage (fun defaults ->
 {defaults with
 ProjectPath = “path/to/MyApp.csproj”
 })
 |> AndroidSignAndAlign (fun defaults ->
 {defaults with
 KeystorePath = “...”
 KeystorePassword = “...”
 KeystoreAlias = “...”
 })
 |> fun file -> TeamCityHelper.PublishArtifact file.FullName


Slide 49

Slide 49 text

How We Work At

Slide 50

Slide 50 text

No content

Slide 51

Slide 51 text

No content

Slide 52

Slide 52 text

No content

Slide 53

Slide 53 text

Git / GitHub ■ Feature branches ■ Every app builds on every branch ■ Any branch can be pushed to TestFlight ■ Pull Requests for code review

Slide 54

Slide 54 text

Test-Driven Core

Slide 55

Slide 55 text

UI Tests and Test Cloud

Slide 56

Slide 56 text

Deployment and Distribution

Slide 57

Slide 57 text

Deployment and Distribution

Slide 58

Slide 58 text

Deployment and Distribution

Slide 59

Slide 59 text

Continuous Monitoring

Slide 60

Slide 60 text

Demo github.com/gshackles/xamarin-ci-sample

Slide 61

Slide 61 text

Questions? @gshackles [email protected] ! github.com/gshackles speakerdeck.com/u/gshackles