Tuesday, November 27, 2012

Building PhoneGap / Apache Cordova iOS Apps with Jenkins

While there are several posts related to Jenkins and PhoneGap, I couldn't find a complete, up-to-date, 'step by step' guides that show how to setup continuous integration builds for your team.

I wanted to share my experience with both tools, but first let's start with some assumptions and requirements:
  1. As of today the most updated development environment version is XCode 4.5 w/ iOS 6.0. It is highly recommended to update to the latest and greatest version so things work properly.
  2. I used the latest Jenkins which is downloadable from its download site
  3. After installing Jenkins, I used this cool xcode-plugin that really helps to get things done. You can install it by going to Manage Jenkins | Manage Plugins | Available | Search for xcode and install it.
  4. As an optional step you should also install the Amazon S3 plugin to push the "Enterprise Site" artifacts (the IPA and PLIST files) so it can be available to others in your team.
  5. You must have Apple's iOS Developer Program account. Make sure you create a Certificate and Distribution (Adhoc) provisioning profile using the portal. Start by creating a certificate for Distribution (remember to do this through the "Distribution" tab) and continue with adding the devices you want to test with. Finally create a provisioning profile (remember to do this in the "Distribution" tab). If you have done things correctly you should have a certificate in your default keychain. Here is what I see: 
    (1) Apple's Certificate (2) Your Certificate (3) Your private key
    Make sure you have something like this in your user's Keychain
  6. Another assumption is that you use the latest version of Phonegap (currently v2.2) which provides handy command line tools to create iOS application shell.  I used:
./path/to/cordova-ios/bin/create /path/to/my_project com.example.my_project
Now before we start the real fun, let's explain a couple of caveats for working with Jenkins in this context:
  1. Jenkins jobs run as the jenkins user (created by the Jenkins installer), your jenkins user doesn't really know about the Keychain that you have created. We will create a different Keychain accessible by your jenkins user.
  2. Same goes to provisioning profiles, we will need to install the distribution provisioning profile for the jenkins user. 
  3. Code Signing for development and distribution is done with different provisioning profiles, from time to time, developers override the project settings so the profile (the Xcode UI really sucks!)  is configured wrongly. For this end we will add a script that makes sure we use the right profile.
Now let's start the real fun:
  1. Export the user's Keychain (usually under /Users//Library/Keychains) and import it into new Jenkins' Keychain (usually under /Users/Shared/Jenkins/Library/Keychains):
    user$ security default-keychain # retrieve the user's default keychain 
    user$ security export -k <user-keychain> -f pkcs12 -o <output-file-name>
    user$ sudo su jenkins # switch to jenkins account
    jenkins$ security create-keychain -P  <jenkins-keychain> 
    jenkins$ security import <exported-file-name> -k <jenkins-keychain> -f pkcs12 -A 
    jenkins$ security default-keychain -s <jenkins-keychain>  
  2. Copy your distribution provisioning profile to jenkins' user profiles directory /Users/Shared/Jenkins/Library/MobileDevice/Provisioning Profiles/
  3. Create a Jenkins job using the xcode plugin
    Fetch your code from git then add a build step which executes the xcode plugin build

    Remember that you should fill in these parameters
    • Target
    • Configuration
    • Project directory
    • output directory
    • Build IPA
    • Provisioning profile - direct to your profile
    • Unlock the keychain and provide the Keychain and its password

  4. In your job you will need to make sure that the right profile is used during the execution, I had to use some search and replace tricks. For this end I first find the provisioning profile's hash (a 28 hex-decimal hash):
    cp </path/to/.xcodeproj>/project.pbxproj  </path/to/.xcodeproj>/project.pbxproj.bak

    sed 's/PROVISIONING_PROFILE\ =\ "[^\"]*"/PROVISIONING_PROFILE\ =\ "<Profile Hash>"/g' </path/to/.xcodeproj>/project.pbxproj > </path/to/.xcodeproj>/project.pbxproj.pro1

    sed 's/\"PROVISIONING_PROFILE\[sdk=iphoneos\*]\"\ =\ "[^\"]*"/\"PROVISIONING_PROFILE\[sdk=iphoneos\*]\"\ =\ "<Profile Hash>"/g' </path/to/.xcodeproj>/project.pbxproj.pro1 > </path/to/.xcodeproj>/project.pbxproj.pro2

    mv </path/to/.xcodeproj>/project.pbxproj.pro2 </path/to/.xcodeproj>/project.pbxproj
  5. Distribute to external enterprise site - this one worth a separate post

Monday, November 19, 2012

REST Sniffer and Client - Working Together

A month ago I posted about REST Sniffer, a Chrome extension that helps with tracking REST calls. This time, I'll present a cool new feature that can help developers to detect and analyze bugs as well as support common Web apps development process integrated with Advanced REST Client.

The use case is very common, you are a Web (or Mobile-Web) developer given with a bug or scenario that requires several steps to reproduce. You probably start with opening a browser and trying out these steps. After simulating it, open the network panel and investigate that it's an API issue originated from this specific scenario (data, flow, state, etc). Now starts the beautiful twist, you pinpoint this API call and detach it to an external client that can reproduce this call in a similar environment. Let's see how it works in real life:

First you sniff your Web App's APIs, and click the "Load in REST Client" button



This operation automatically detaches this specific API call (including its method, URL, path, parameters and headers) to the Advanced REST Client where you can review and exercise this call again and again. Ultimately, step by step debugging it in your favorite IDE.


Finally Review the results in your client after resolving the issue


Many thanks to Paweł Psztyć the "Advanced REST Client" Google Chrome App creator who worked together with me on the integration and made it possible.

If you want to read more visit this short page prepared to help with understanding the workflow in details.