Top 5 Tips for Integrating SwiftLint Into iOS CI/CD Pipelines
This tips will help you in the integration with SwiftLint in iOS CI/CD pipelines, from installation to smart build phases and reporting.
Join the DZone community and get the full member experience.
Join For Freeswift is getting to be a popular programming language for developing ios apps these days. being a type-safe language, it's important to focus on code styling and conventions of swift code. swiftlint is an open source tool to enforce swift style and convention. swiftlint allows us to enforce code style rules and stick to it during the development of ios apps. there are various blog posts about integrating swiftlint into the development process, as well as swiftlint itself has good documentation about its usage, however, there are some tricks we can use while integrating swiftlint into continuous deployment pipelines. we will cover some of the tips for setting swiftlint on ci server and embedding it into build pipeline. note that, this post assumes that you have selected rules and configured.swiftlint.yml files. let's see how to integrate those rules on ci servers.
note: source code for this post is available on gith]hub swiftlint-ci repo, and travisci build is available here .
1] install swiftlint with cocoapods
there are four methods of installing swiftlint, as mentioned in the documentation. it's important to select the method of installation for a ci server as each of them has its own pros and cons.
homebrew
swiftlint can be easily installed using homebrew package manager.
$ brew install swiftlint
this seems to be the easiest method of installing swiftlint on any ci server. some of the cloud ci servers like travisci have swiftlint pre-installed in the macos images . there are some pros and cons of this method of installation
pros
- easy to install with one command.
- some cloud ci servers have a pre-installed version of swiftlint using homebrew.
- no need to make any changes in the application code.
- a script can run independently on a ci server without making any changes in the xcode project.
cons
-
homebrew
installs the latest version of swiftlint every time we run the
$ brew install swiftlint
command. it's hard to go back to previous versions if needed. - there might be a different version of swiftlint running on the local machine and ci server. the team needs to stick to the version of swiftlint installed on the ci server. for example, travisci has swiftlint version 0.17.0 installed in an xcode 8.3 macos image. the latest version of swiftlint at the time writing this post is swiftlint 0.21.0; it's bit hard to go back to old version using homebrew
cocoapods
swiftlint can also be used with
cocoapods
; there is detailed documentation on how to install swiftlint using cocoapods
here,
but in summary, we need to get the swiftlint pod by adding the pod 'swiftlint' into podfile and install swiftlint using the
pod install
command. this will create an executable binary inside ./pods/swiftlint/swiftlint, which can be added to build phases of the target. this is the recommended approach to installation in the swiftlint
readme
file, but it also has some pros and cons. still, cocoapods is the best way to install swiftlint on a ci server.
pros
- we can install a specific version of swiftlint rather than simply the latest.
- versions are locked inside the podfile.lock file so everyone in the team will be using the same version of swiftlint, including ci.
- we can execute swiftlint using the binary located at./pods/swiftlint/swiftlint.
cons
- we have to add another dependency in our application source code.
- it will add dependencies and binaries inside pods/ directory, which needs to be checked into the scm.
there are other methods of swftlint installation like compiling from source and downloading a pre-built package are available there but compiling from source isn't a good idea at all. some users found the downloading pre-built package is faster on ci. we can download and install the package using the following command.
$ wget --output-document /tmp/swiftlint.pkg https://github.com/realm/swiftlint/releases/download/0.21.0/swiftlint.pkg
$ sudo installer -pkg /tmp/swiftlint.pkg -target /
the best idea is to pick the cocoapods way of installing swiftlint.
2] succinct podfile
swiftlint can be used to lint multiple targets of an ios app by using a simple ruby technique; we can apply swiftlint to multiple targets. we can write the podfile like this:
targets_to_lint = ["swiftlint-ci", "swiftlint-citests", "swiftlint-ciuitests"]
targets_to_lint.each do |target|
target "#{target}" do
use_frameworks!
pod 'swiftlint'
end
end
this will apply swiftlint for all the targets mentioned in the targets_to_lint array once we run the
pod install
command.
3] run early & independently on ci
swiftlint being a static analysis tool, we have to run linting before running any other development task like building, testing, or archiving. this will help us to fail early if there are some issues in the code quality. we can have a separate build phase in our ci pipeline to run the static analysis with swiftlint. the script we want to run is
$ ./pods/swiftlint/swiftlint
this makes sure that the correct swiftlint binary is getting executed as part of the build script rather than executing the pre-installed binary. in our example app, we have configured a separate phase for swiftlint. check out the .travis. yml.
4] balance local and ci linting
the ios developers mostly work with xcode , however, ci servers have to run some automated scripts on the server to run the development tasks. in order to make both developers and ci happy, we need to balance how to run swiftlint without making them upset. there are a couple of things, we can focus on while development and ci phase like xcode build phases and reporting of swiftlint results.
smart build phases
swiftlint works perfectly when run from command line however, ios developers would love to integrate it with xcode . in order to integrate it with xcode, we need to add run swiftlint as part of the build phase of the targets but we don't want to repeat the execution for each build on ci. we can add a run script in the build phase smartly so that we can still run the swiftlint from local xcode as well as on ci. we can achieve it by creating a ci environmental variable (most ci servers have this similar variable already set) and adding a conditional execution script in the build phases of the target.
if [ -z "$ci" ]; then
${pods_root}/swiftlint/swiftlint
fi
this will make sure that there won't be repeated execution of swiftlint scripts on the ci server, but developers can still run it from the local xcode.
smart reporting
swiftlint has different reporting types, including xcode, json, csv, checkstyle, junit, html, and emoji. the default reporter type is xcode. it's a good idea to keep the xcode reporting for the local execution and generate fancy reports using html or junit on the ci server. we can change the reporter style using
./pods/swiftlint/swiftlint --reporter junit
5] mind the fastlane
fastlane has become a very popular tool to automate ios development tasks for continuous deployment. fastlane comes with various tools and actions to perform specific tasks. fastlane has an action for swiftlint which looks great but it's not required to execute swiftlint as fastlane action. if we using swiftlint with cocoapods, then actions must set an executable parameter, pointing to the binary located at./pods/swiftlint/swiftlint path. otherwise, fastlane will pick a default binary, if there is any. the swiftlint fastlane config should look like this:
swiftlint(
mode: :lint,
output_file: "swiftlint.result.json",
executable: "./pods/swiftlint/swiftlint"
)
this will make sure that we are executing the correct binary of swiftlint with fastlane.
hope you like these tips!
Published at DZone with permission of Shashikant Jagtap, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments