At his company, Łukasz and his colleagues wanted to set up a CI, but ended up only arguling about it. Then he had to figure out how to add a Xamarin app to Bitrise himself. This is his story.
Guest post by Łukasz Ławicki, software developer. The original post appeared on his blog.
Łukasz is a Xamarin developer from Wrocław, Poland, mostly specialized in Xamarin.Forms. He has developed several apps & is still developing others. He's mostly focused on .NET framework & C#, but tries other technologies and is constantly trying to write cleaner & better code. The admirer of Software craftsmanship approach. Big fan of Scrum.
At some point in my life, when I heard CI (continuous integration) or CD (continuous deployment) I was struggling. Why? Because in the company I was working for, on several team meetings, senior developers were discussing which CI/CD should they use. This topic implicated a quarrel: if we want to have a CI/CD we should not use Bitbucket repo. We should use GitLab. Another developer said, “GitLab sucks, let’s use GitHub”. And the fight began. After a few meetings, we were still using Bitbucket and nothing was done with CI/CD. Mostly, because we couldn’t agree on which repo to choose. Great! After some time, those developers left and I was on my own, having the repo on Bitbucket and without CI. And people were asking: are you using CI? Which one do you use? Why do you use it? etc. I was frustrated so I decided that as everyone (who was capable of integrating) is gone, I should do it on my own. So I started digging. In my side project (done in Android native) we were using Bitrise, so the choice was quite clear. Bitrise it is.
At that moment, I was working on an app in Xamarin.Forms. Both iOS and Android were supported, so I wanted the CI to build for both platforms. A little worried, I did the research if Bitrise is a good choice. I found great articles (links at the end of this article — I suggest you read them!) about it & it happened that James Montemagno did an awesome video about it! After reading and watching, I took a piece of paper and planned my workflow. This helped me understand what steps I am taking to deploy the app & what should the CI cover. So here is what I’ve found out:
- I run the Unit tests to check if everything is still ok
- If the tests are passed, I bump the version of each of the iOS and Android apps
- Time to archive & sign the version
- If the versions are ok, I upload them to Fabric (I believe that Fabric sucks on Xamarin, but my company is using it for Native projects, so I have to stick with it — maybe I’ll write about it in the future)
- When the new version is uploaded, I notify clients about it.
Having this on a paper, I planned how the CI process should look like. At this point, I was thinking “how should it look on a computer with Visual Studio only?”. Here is what I’ve come up with:
- Clone the repo
Quite an obvious one. How can you archive the code if you are not having it?
- Set the certificates
If you want to archive the version for Android & iOS you should have both certificates and provisioning profile for iOS. Still an obvious one.
- Run the UI/Unit tests.
Depending on what you have in your projects, you want to run them for sure to see if they are passed. As I am still missing the UI tests, I just wanted to run my Unit Tests.
- Build and archive the versions
As written above, I want to make two archives: iOS & Android, so let’s do it!
- Upload the archives to Fabric
… or any other distribution channel you are using, so the clients can download and test them
- Get notified if the build was a success or not
As we are using Slack in the company, I wanted to receive a message on a #build channel saying if the build was a success or not. If it was, I’d like to receive a link to a new version.
And it got complicated. On a paper, it was looking good but now we need to integrate it into Bitrise. Damn. But I must say it is not that hard as it is looking. Let’s take a look.
Set up Bitrise account
I won’t tell much about this point. Right now (mid-2018) the registration process is very simple. You are a developer, so I believe you can do it. I can only add that I chose to log in with my Bitbucket account.
Add new app
In this, Bitrise will guide you. You should not have a problem. What is worth mentioning is the fact you’d better be a repo admin. Let’s go step by step.
- choose the connected account you want to use
- choose the repo you want to add a CI to
- decide whether you need to add an additional private repo — I don’t use one so I clicked “No, auto add SSH key”
- type the name of the branch you want to use — I was hesitating between master or dev, but finally chose dev — production builds are not so frequent, so I can either connect a new CI in the future or build them manually
- wait for Bitrise to configure your project
It should auto-detect that it is a Xamarin project.
What you need to fill in is the solution configuration (Debug or Release by default) and the solution platform (most of the times Any CPU builds both the iOS and Android projects)
- if your repo allows you to have a webhook, you can create one. If not, sorry but you’ll have to run the builds manually (login to Bitrise and click Build yourself)
Right now, you should have everything done.
Now, let’s take a quick tour through tabs:
- In „Builds” you can either start or schedule a build manually and see the list of all previous builds. Nothing complicated to be honest.
- In „Team", you can invite whoever you want to this project and give them permissions. That is nice.
- But the heart of Bitrise is the “Workflow”.
- In “Workflows”, you will be defining your flow/s.
- In “Code Signing”, you should upload your code signing files (iOS certificates and provisioning profiles & Android keystore files).
- In “Secrets”, you can define the secret variables that won’t be visible in the build log, if you turn on the secret filtering.
- In “Env Vars”, you can define your custom variables.
- In “Triggers”, you can specify mapping between git events (code push, pull request and tagging) and which workflow to run. I will describe it later.
Being honest, for now, I don't feel like I should use Secrets or “Env vars”, so what interests me is the “Workflows”, “Code Signing” & “Triggers”.
Default Bitrise workflow for Xamarin
What do you think: if you run the build now, will it succeed? The answer is no. Let’s take a look at why.
In order to do it, go to your app and click “Workflow”. You should see something like this
Let’s go through each step & modify then so the build is a success.
- Activate SSH key
- In this step, we are setting the SSH key so we can access the repo
- An additional step that I didn’t realize was needed.
- Git Clone Repository
Perfectly fine and obvious one.
- Do everything with the Script step
You can write your script and run it in this step. Nice!
- Certificate and profile installer
As I’ve said: “Install certificates”. This is the first thing that will fail if you are building for iOS. As of now, you don’t have anything installed. In order to have, go to “Code signing” and upload everything your project needs (you can use codesigndoc). Of course, you'll need to provide the passwords! Shouldn’t be that hard. Go back to your workflow & let’s proceed.
- Nuget restore
I’ve forgotten about this one too. But thanks for including it, Bitrise!
- Later we have “archive”.
This step will probably fail too. Go on & check why. See? In the “Specify project types to build” we are saying that we want to build each of the written one. As long as you don’t build apps for everything, modify it according to your requirements. In my case just Android and iOS.
- Deploy to Bitrise.io
For now, it is ok. Let’s not mess with it.
Having modified it, save it and go back to your project and click Start/Schedule Build. If you filled all the data correctly it should be a “Success”.
What is worth mentioning is that you can decide if you want a step to be started when a previous step failed. See? That tiny, orange toggle button in the image of the workflow above.
But hey! I wanted to run Unit tests, bump the versions and get notified on Slack. Also, I wanted it to run automatically! No problem, let’s proceed.
This is the first important step you should think of. When do you want to start a build? After a push? Pull request? Tag? Or maybe every night? In order to create one, you need to go to the triggers tab. 😇
Choose whatever suits you and “Add a trigger”. By default, your project should run after each push and pull request. It’s up to you if you want to change it. Also, what is worth mentioning is the fact that you can use different workflows for different actions. So for PRs or pushes you can run tests, for tags archive version etc. — this is how I am doing it 😉
If you want to run your CI on schedule:
- go to the page where you can start a build manually
- click Start/Schedule a build
- toggle “Schedule this build” & do what you want.
Choose days, hours, branch, workflow and you are ready to go.
Run the Unit tests
We want to run the tests before making a new version. If the tests fail we obviously don’t want to archive. So we need to add NUnit runner, click + button between Xamarin Archive and Nuget restore. In the pop-up search for NUnit runner.
Add it. In its configuration, there is not much to set. What is worth noticing is the field “Build before test”. If in the previous step you built the project there is no need to rebuild it. Voila, running unit tests is done! Build the project to see if the build succeeds.
Bump Android version
We need to add another step. You might need to add this between tests and archive. Thanks to James Montemagno there is one easily configurable step. Click + and search for “Set Android Manifest Version Code and Name”. What you need to configure in here is:
- AndroidManifest.xml file path
The obvious one. Probably something like this Droid/Properties/AndroidManifest.xml
- Version Code
The code you want to be built. I thought that if I am creating a CI it will be nice to have a build number.
- Version Name
This one is tricky. Firstly, it looks like it is not required. If you leave it empty it will take the original value from the original manifest. But in my scenario, I am tagging the commit and the tag starts the build. So let’s take a tag value.
In my case, it looks like this:
Now, let’s move on to Info.plist
Bump iOS version
Let’s add a step “Set iOS Info.plist Values (unified)”. Configure it. Fill in the data: “Info.plist file path”, “Bundle Version to set”, “Bundle Short Version to set”. Only the first one is needed, but it’s ok to fill the rest so you won’t have a chaos in your archives. In my case, similar to Android, I used “$BITRISE_BUILD_NUMBER” & “$BITRISE_GIT_TAG” for versioning.
Build the project again and see if it works!
What is left is the notification on a Slack. If you want one, add a step “Send a Slack message” and follow these instructions.
I might add that before sending a Slack message I create a QR code with the installation link, so I can scan it and download the app (in order to do it add the step called “Create install page QR code”.
You are done! Build it and see how it works!
As you can see I didn’t deploy the app to Fabric. The reason why this happened is that currently Fabric is only supported for iOS. Also, I am currently working on InApp payments, so I need to deploy the app to TestFlight and Alpha channel on Google Play store. As I don’t have time to do the research on how to do it, I am using Bitrise.io to deploy the app. Hopefully, in the near future, I will write another blog post on how to do it.
If you are interested in integrating it, read the articles from references & watch live coding from James!
At first, I was really afraid of integrating CI on Xamarin.Forms. Mostly because of my colleagues. Maybe a little bit because of shell scripts. Maybe. But Bitrise is the answer. I fell in love with it. It’s really easy to integrate it. It helps in the development. It’s awesome! Love you Bitrise! Love you Xamarin!