Continuous Integration is important. You probably wouldn't read this, if you didn't agree with me . That's why I don't want to get into this blog's episode why you should be doing Continuous Integration (CI) but how to do it with Travis CI in regards to Swift. There are several other CI services out there like for example Circle CI or Cloud Bees. The big advantage Travis has over them is that Travis is free.
As with any other CI Service, all you basically need is a Script. A Travis script is a YAML file and hence named .travis.yml. (Pay attention to the leading dot.) It needs to be in in your project's home directory. The two things a Travis script needs are
a) the language to use (which is 'objective-c' for Swift) and
b) the image to use. Travis uses Docker images, which you can actually use to debug your script in case it doesn't do what you expect. You can read more about it here.
Apart from that, you can either get away with environment variables or a scripting section. Since latter gives you more control, it is usually my preferred choice. You can read more about the former here. The scripting section consists of commands you'd normally run in your console. Using CI, we actually want to make sure of two things:
- A build is compilable i.e. it has no build errors
- All tests are passing i.e. the resulting binary does what it is supposed to do.
Hence the scripting sections should contain two commands to verify these:
- xcodebuild -workspace <project>.xcworkspace -scheme <scheme> -destination 'platform=iOS Simulator,name=iPhone SE,OS=10.1' -sdk iphonesimulator build CODE_SIGNING_REQUIRED=NO ONLY_ACTIVE_ARCH=NO RUN_CLANG_STATIC_ANALYZER=YES GCC_TREAT_WARNINGS_AS_ERRORS=YES
- travis_retry xcodebuild -workspace <project>.xcworkspace -scheme <scheme> -destination 'platform=iOS Simulator,name=iPhone SE,OS=10.1' -sdk iphonesimulator clean test CODE_SIGNING_REQUIRED=NO ONLY_ACTIVE_ARCH=NO
Let me elaborate a little bit about what those two lines mean. Xcode builds are triggered on the command line via xcodebuild. So we have one line to ascertain that the build is compilable and without any errors and another one to prove that all the tests are running fine.
In regards to the first line, we instruct Xcode to run the Static Analyzer (SA). Tools like SA report warnings if they assume there's something wrong. In this case we want to the build to fail, so Travis can let us know about it. Hence the use of GCC_TREAT_WARNINGS_AS_ERRORS and RUN_CLANG_STATIC_ANALYZER.
In regards to the second line where we run our tests, I prefixed the line with travis_retry. No build environment is perfect and neither is Travis. To avoid any false positives, we use travis_retry to rerun the tests again if they fail. So if they fail, it probably means there's something wrong with our project.
If you are interested in some actual working Travis YAML file, you can find one here. I set one up while I was working on one of my previous projects.
Apart from providing a script to instruct Travis what to do, your Swift project needs to meet certain requirements for Travis to be able to work: It needs to share its scheme. If you use CocoaPods, make sure you choose the right setting under scheme -> Manage schemes. It needs to be set to the project's workspace. If you don't use CocoaPods, it should be set to the project's project file i.e. <project.xcodeproject>. The screenshot below shows the setting for a project using CocoaPods. That's actually all you need.
Again, Continuous Integration is important. Especially if you're depending on other people to compile your source code. Travis is not perfect. The thing that bothers me most about Travis is that you don't get immediate feedback. It usually takes an hour (or more) for Travis to handle your request and tell you about its status. If you need something more instantaneous, take a look at the two aforementioned CI solutions CircleCI and Cloudbees. If you need more control, I recommend to run your local Jenkins server. Choose whatever fits your needs, but do use CI. Your users and customers will appreciate the extra effort.