Showing posts with label DevOps. Show all posts
Showing posts with label DevOps. Show all posts

Wednesday, April 4, 2018

Even For Small Teams, AppCenter Helps Press the Easy Button



Opening up Xcode, Android Studio, Visual Studio, Atom or whatever integrated development environment we use and starting coding away is always easy enough. Sure, we can create an application, go through the process of manually signing it and get an app in the store. This is OK if we are working alone but at some point, many of us are going to be in a situation of working on a team or have a complex enough application where more formal testing and deployment is required. Then we start putting together disparate tools to do mobile DevOps, deploy test versions of the app, handle crash reporting, analytics, etc. Getting all this to work together can be difficult, particularly the build servers for automated builds which can be time consuming to setup and maintain for groups that don't have a lot of experience in that space.

This is the space where Microsoft's App Center really shines. For small teams, who may be new to mobile, they need to know very little about setting up these processes to use App Center. One of the strengths of this is that it falls under Microsoft's new philosophy of embracing technologies outside of their stack, so it isn't just for .Net folks. If you work in Xcode on Swift, no problem, Java in Android, no problem, React Native, no problem. App Center takes a variety of infrastructure needs common to most mobile apps and presents it as a all in one solution where all the parts are easy to use, work well together or can just be taken a-la-carte.

To see how many different capabilities Microsoft has provided on a variety of platforms consider the following:

Feature
Xamarin iOS and Android
Native Android
Native iOS
UWP
React Native
iOS and Android
Cordova
iOS and Android
MacOS
Build
 X
 X
 X
 X
 X

 X
Test
 X
 X
 X

 X
 X

Distribute
 X
 X
 X
 X
 X
 X
 X
Crash Reporting
 X
 X
 X
 X
 X
 X
 X
Analytics
 X
 X
 X
 X
 X
 X
 X
Push Notifications
 X
 X
 X
 X
 X
 X
 X
Code Push




 X
 X


Microsoft has gone to great lengths to make most of the features work with many different mobile development platforms. I don't have space to get into how these features work here, but if you want more information you can watch my AppCenter class on Lynda.com or Linked-In Leaning:



Here's how I think about the good, bad and ugly parts of App Center

The Good


  • We get continuous integration and continuous deployment setup quickly without needing to know a lot about how to do it
  • There is a lot of extendability and capability to tie in other process tools with API and REST interfaces
  • It has reasonable pricing for the features that are not outright free
  • If you are you blue about managing all the devices in your Ad-Hoc provisioning profiles, AppCenter can make this easy
  • Do you only have a few devices to test on? AppCenter has thousands
  • This even offers an entire framework for live code pushing React Native and Cordova Javascript code
  • Crash reporting and analytics can be set up easily on all supported development platforms
  • There just is a lot in this box to like. With AppCenter and a public git style repository of the right type there really is no reason not to have at least a basic CI process

The Bad


  • There are limitations around customization of build process (there are three places where custom scripts can be inserted)
  • No tie in for builds to kick off custom automated testing (must use scripts and API/REST interface)
  • Appium tests can only be written in Java
  • The testing feature does not allow for manual testing, there is no direct interaction with the devices for exploratory testing
  • There are some other limitations
    • Android React Native build only looks two directory levels deep in the repository for workspaces
    • Deployment feature still not as full featured as Hockey App
    • Features like iOS store deployment that require access to the Apple store account need two factor authentication to be turned off

The Ugly


  • To use the build services, it only has Git integration, if you use another source control tool, too bad. You also better be on VSTS, BitBucket or GitHub
  • On that note, repositories cannot be on-premise either
  • Builds cannot easily be tied into a gated check-in concept
  • The REST / API to create builds is fire and forget so it is hard to kick off an AppCenter build from another tool and know when the build is done to know if it failed.
That may seem like a lot of bad and ugly, but some of this is by design. The implication of making it super easy to set up builds that almost anyone can do, is that we may loose some flexibility. But that's kind of the point of AppCenters wide feature set. While organizations of any size and complexity may be tempted to use certain features of AppCenter, AppCenter also brings more complex things like the creation of build processes to even the smallest of teams. If your build needs are super complex then Microsoft has the much more flexible VSTS build services that can be used. But if your build needs are somewhat generic and simple, boy can you get that going with AppCenter quickly. The box of features is large, the breadth of toolsets supported is wide, there just is something for everyone to be found in there.

Tuesday, August 8, 2017

Visual Studio Mobile Center: Solving a Problem with Package Restore

Visual Studio Mobile Center is shaping up to be a great tool. Where before it had taken me a week to set up the builds in VSTS it now takes less than an hour. This speed and simplicity does come at a cost, mostly in terms of not having a lot of fine control over the build process. About a month ago this caused a problem for me.

I don't have full control of a repository I was trying to build using VSMC. That is to say the QA group added a directory with their test solutions. This was fine except that test solution required a Nuget package that was hosted on our company's internal Nuget server. Why was this a problem? Because VSMC will try and restore packages for any and all solutions it finds in the repository, even ones I'm not trying to build with VSMC and that meant the package restore step failed every time.

Luckily about the time this happened, VSMC implemented a feature I (and probably others) have been asking for. The ability to create custom build steps. There are three custom scripts that can be added, one right after the source code is retrieved (post-clone), one right before the solution is built (pre-build) and one right after the solution has been built (post-build). For Android and iOS apps the build happens on a Mac so bash scripts need to be made, for UWP apps the build happens on a Windows machine so Powershell scripts are needed. For more information you can check out their easy to read documentation:

VSMC Build Scripts

How does this help me and my error? Well as it turns out I can create a post-clone script that deletes the test project folder out of the cloned repository *BEFORE* the Nuget package restore happens. I don't need anything in there so no problem removing it. For my particular case I am doing Xamarin iOS and Android builds. That means I need to create a Bash script.

The script must be a specific name, mobile-center-post-clone.sh for a post clone shell script. It also has to be in the same directory as the solution or project to build. Because the solution that built my iOS project and the project for the Android application were in different locations, I needed two copies of this same script.

Here is the script I created:

 #!/usr/bin/env bash  
 echo “removing test automation directory”  
 set -e  
 rm -rf $MOBILECENTER_SOURCE_DIRECTORY/testAutomation  

The most important line in the script is the last one. It removes the entire directory from the build server where the QA project resides that is causing the problem. Notice that I am also using one of the built in build variables, $MOBILECENTER_SOURCE_DIRECTORY. This inserts the location of the root directory where the source code was copied to. It allows my script to work anywhere so I can use the same one for the iOS build and the Android build. It works like a charm.


Note: You may have to re-save your build configuration before it picks up that the scripts are there. The above picture shows that the build definition has detected my post-clone script.

That's it. If you are having issues with the Nuget restore step on a project you are not trying to build, you can just remove it using such a script. You could also do things with scrips like running UI tests after the build or changing the app Ids before the build. This is a great addition to Visual Studio Mobile Center.

Tuesday, May 31, 2016

Setting Up Builds With Xamarin Using MacInCloud and VSTS

For many of us doing mobile work the ability to create great continuous integration and continuous delivery solutions has been hampered by the lack of enterprise support for Macs and generally the lack of available build agents that work with iOS and even Android projects. Recently MacInCloud released a Visual Studio Team Services (VSTS) build agent that can work with native, Xamarin and Cordova development for iOS and Android. For Magenic this is exactly what we need so I have been working through creating a repeatable process that we can use project after project to stand up this sort of build service.

To start with I want to talk about the kinds of build services we can set up:

Continuous Integration (CI) - A build designed for when developers check in code. Usually ensures that the code being checked in compiles and that all unit tests pass.

Continuous Delivery (CD) - Happens when code is promoted to an environment, such as QA, built and deployed out to the app deployment service to be used for testing. Code promotion usually happens as code is merged into a branch for that purpose, such as a QA branch.

There is also a concept of Continuous Deployment, that is in many ways similar to Continuous Delivery expect the build is pushed to the production environment. For this blog post I will focus on continuous delivery for Xamarin when code is moved to a QA branch from a Development branch. I hope to follow it up by posts for CI and also for Native technologies and Cordova using VSTS and MacInCloud.

The technologies covered by this post:
Visual Studio Team Services (VSTS)
Xamarin Android
Xamarin iOS
MacInCloud VSTS Agent
HockeyApp

What do I want to accomplish when doing my CD Build:
Kick off when moving code into the QA branch
Register my Xamarin Account
Get all required dependencies
Change version number of Android and iOS code
Build iOS and Android code
Sign Android and iOS code
Generate required documentation (will cover in a later post)
Deploy out to HockeyApp

I won't go into how to connect the VSTS MacInCloud agent to VSTS. A good post that explains this can be found here: Getting Started with the MacinCloud VSTS Build Agent Plan. I also won't go into branching strategies, I assuming multiple branches with at least Development, QA and Release branches. I use git style repositories but the TFS style repositories will work as well.

What I assume is already done:
VSTS repository created
Branching implemented
MacInCloud VSTS agent purchased
MacInCloud agent created and connected to VSTS
iOS certificates and provisioning profiles uploaded to MacInCloud agent
Note: If you ever want to change the pool name that the agent is connected to, it will submit a request in the MacInCloud portal but it doesn't seem that the request is processed immediately. It may take a few hours for it to occur during which time you cannot build with the agent. Be cognizant of this when changing the pool name after the initial agent setup (which seems to happen nearly immediately).
Note: It may happen that the agent gets locked up or otherwise seems to stop responding. Unfortunately, at this time there is no way to manually reset the agent. You will need to create a support ticket with MacInCloud. Luckily they are very responsive and always got back to me later in the day.
Note: For Xamarin, a MacInCloud VSTS build agent can pretty much do all the build types you can do in Xamarin Studio on a Mac. However, that is not all types of .Net applications. For example, if you want to compile a UWP project as part of a Xamarin Forms solution, that part of the build would have to occur on a Windows build agent.

Setting up the build steps

Kick off when moving code into the QA branch

A last note on build steps. I called my branch to cause the CD build to run QA. Also I used the Ad-Hoc build definition to setup all the project settings for QA builds. In my VSTS project I created a new build configuration called "QA Build". I named my MacInCloud VSTS agent queue: Xamarin. My VSTS configuration for Repository, Triggers and General tabs to kick off the build looks like this:



Register my Xamarin Account

On the Build Tab we can start adding steps. There is one task that we care about to start, Activate Xamarin License. We need to add it to the build process four times. Twice at the beginning to activate the licenses for iOS and Android and twice at the end to deactivate them.


Note: Xamarin is now free and for many builds these steps may not be necessary. For some build options, such as embedding assemblies in native code for Android, an Enterprise Xamarin subscription or MSDN Enterprise license are still required. As the formal licensing switches from the Xamarin licensing scheme to the MSDN subscription scheme, these steps will likely slightly change.

Get all required dependencies

There are two tasks that can help here, Nuget Installer and Xamarin Component Restore. Put in tasks for one or both of these depending on where your packages come from. Currently, I'm using just Nuget packages and left the default to restore for all solutions in the branch.

Change version number of Android and iOS code 

Each and every build put into HockeyApp needs a unique build number that is ever increasing for it to understand what is the latest build. It does not use the upload or compile date as the primary mechanism for this, instead it uses the build number. A newer build will be thought to be older by HockeyApp if it has a lower build number than another in HockeyApp even if the version name looks higher.

Both Android and iOS has two build identifiers, one a human readable version name such as 1.3.2 or 1.3.3 and one an ever increasing sequence of numbers that is used to tell which is newer. In Android in the AndroidManifest the VersionName is the human readable name and the VersionCode is the ever increasing number to tell what is newer. For iOS the equivalent settings can be found in the info.plist under CFBundleVersion is the ever increasing number and CFBundleShortVersionString is the human readable name.

To handle this in VSTS I use a task called Version Assemblies that is part of Colin's ALM Corner Build and Release Tools. This is not a standard VSTS task so you will have to go out to the Marketplace (click Add Build Step then select "Don't see what you need? Check out our Marketplace." The Version Assemblies task allows you to search a file in search control for a RegEx match and replace it with part of the VSTS project's Build number.

Setup VSTS variables

To specify the build name I created a VSTS variable. This is done on the Variables Tab of VSTS setup. In this case I want the version name to be 1.3.0. When I change the version name, I will go here and change it. There are other ways to do this, but this is based on the use of the Version Assemblies Task. 


Then I setup the build number format on the general tab. This will use the current date, the value in the VersionNumber variable and the BuildID. 

$(date:yyyyMMdd)_$(VersionNumber).$(BuildID)


Note: Some samples I have seen, including the one for the task, show using the TFS revision number for this and using that for the build number. I highly recommend against this. The revision number resets on a daily basis or when anything else changes in the build number. This won't lead to an ever increasing number we can use for Android and iOS to tell what the latest is.

Setup iOS placeholder versions

Due to the structure of the iOS info.plist file it won't be easy for our task to find the right keys to replace. So we are going to use some numbers that will work fine for development, but ones that our build service will be able to find and replace. In the info.plist file I set the values as follows:

<key>CFBundleShortVersionString</key>
<string>1.0.0.0</string>
<key>CFBundleVersion</key>
<string>1.0.0.0.0</string>

Add Version Number tasks for iOS

Add two Version Assemblies tasks, one for the CFBundleShortVersionString, and one for the CFBundleVersion. Since a regex that finds and replaces 1.0.0.0 for the CFBundleShortVersionString will also find the first part of the CFBundleVersion, I recommend replacing the CFBundle version first in the build order. Here is how I set those up. With the the CFBundleShortVersionString will end up with the value in our VersionNumber variable (like 1.3.1) and the CFBundleVersion will end up with the unique and ever increasing BuildID.

(You will need to open the advanced area)
Build Regex Pattern:  (?:\d\d\d\d\d\d\d\d_)(\d+.\d+.\d+.)(\d+)
Build Regex Group Index: 2
Regex Replace Pattern: (\d+.\d+.\d+.\d+.\d+)



Build Regex Pattern:  (?:\d\d\d\d\d\d\d\d_)(\d+.\d+.\d+)(.\d+)
Build Regex Group Index: 1
Regex Replace Pattern: (\d+.\d+.\d+.\d+)


Setup Android placeholder versions

In the Android Application.Manifest ensure the versionName is two numbers separated by a period such as 1.2 and that the versionNumber is a number without a period like 4.

Add Version Number Tasks for Android

Build Regex Pattern:  (?:\d\d\d\d\d\d\d\d_)(\d+.\d+.\d+)(.\d+)
Build Regex Group Index: 1
Regex Replace Pattern: versionName="\d+.\d
Prefix for Replacements: versionName="


Build Regex Pattern:  (?:\d\d\d\d\d\d\d\d_)(\d+.\d+.\d+.)(\d+)
Build Regex Group Index: 2
Regex Replace Pattern: versionCode="\d+
Prefix for Replacements: versionCode="

Build iOS and Android code

Build iOS Code

I build the iOS code first by using the Xamarin.iOS build step. I add it in and point to a solution that contains all the iOS projects and any shared PCLs. The configuration I use the $(BuildConfiguration) variable which I set to Ad-Hoc. This will build the targeted solution in the Ad-Hoc build configuration with all appropriate build settings.


Note: I leave the Signing and Provisioning profile section blank. Instead I have defined the proper certificate and profile in the Ad-Hoc configuration project properties for the iOS projects. These correspond to the signing and provisioning profiles that I have already uploaded to my VSTS build agent in MacInCloud.
Note: I encountered an error "user interaction is not allowed" which had to do with the keychain for the certificates I uploaded being locked. I'm not sure how this happened and there is likely nothing you can do to fix it yourself. I submitted a ticket and the MacInCloud support team was able to quickly change something on their end to resolve the issue.
Note: I could have also included the Android projects in the solution and they would have built. However, I wanted direct control over their building and signing so I created a solution used only for the builds that only contains the shared PCLs and iOS projects so I wouldn't build the Android projects twice. It also gives me higher level quick visibility if it was the iOS and Android part of the build that failed. 

Build Android Code

Here I used the Xamarin.Android task. Instead of pointing to a solution, it points to a particular project. I also added and additional argument, /t:SignAndroidPackage that forces it to build an .APK. 


Note: I didn't include anything in the project file about sighing the APK because that would require me to keep my signing information in the project file itself. Instead I used a separate Android Signing build task and kept the certificate's authentication information in variables in the VSTS build definition.
Note: At first I received an error, "The Android SDK Directory could not be found. Please set via /p:AndroidSdkDirectory." This had to do with the ANDROID_HOME environment variable not being set correctly in the agent. If you put in a ticket, the MacInCloud support team can fix this for you.

Sign Android and iOS code

There is nothing to do here for iOS, as the code signing occurred as part of the iOS build process. For Android I added an Android Signing task to the build steps. I also added the appropriate keystore file into source control so I could reference it as part of the build.

Setup Keystore Variables

Granted, these are not very good passwords, but they will do for this test. Create these three variables in your build definition with the proper credentials for your keystore.


Add Android Signing Task

Use the following configuration for the Android Signing. The keystore should be located within your source code checked into the branch that is building.



Note: The first time I tried this I received an error, "Path must be a string…”. After searching and finding it wasn't a setting on the task, I found this was caused by the JAVA_HOME environment variable not being setup on the VSTS build agent. I submitted a ticket and they got the JDK properly setup with this variable defined and everything started working.

Deploy out to HockeyApp

Luckily there is already a task for deploying to HockeyApp in VSTS.  We need to add two of these tasks to our build definition, one for Android and one for iOS. On the first one you add you will need to setup the connection between HockeyApp and VSTS. To do this press the manage link on the HockeyApp connection section of the task. This will bring up an area where you can create a new connection. It will ask for an API Token.


The API Token can be found in HockeyApp under Account Settings \ API Tokens. I created one with Full Access though only Upload and Release is probably sufficient. Copy the created API token back into the VSTS HockeyApp connection.

Setup Apps in HockeyApp

You will need to setup two apps in HockeyApp, one for Android and one for iOS. I manually created them and set the Bundle Identifier (iOS) and package name (Android). Each one of these HockeyApp applications gave me an App Id that I could then copy back into the HockeyApp deployment task in the VSTS build.

Finalize Deployment Settings

For both the Android and iOS HockeyApp deployment tasks I added information on what binaries to deploy. I could also set release notes (later post), debug symbols and restrictions on who can download.

Android


iOS


Final Thoughts

This took a fair amount of trial and error to get it right. I'm hoping that this can be used by others as it is moving toward codification as part of Magenic's new recommended CD process. I'm sure there is some cleanup to be done and I wanted to get this down while it was fresh in my mind. Let me know if you have any issues with it. Here is a view of the full list of build steps:



What the builds look like in HockeyApp for Android:


For my simple solution the entire continuous delivery process takes less than 3.5 minutes.