<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>The Carbon Emitter &#187; continuous integration</title>
	<atom:link href="http://blog.carbonfive.com/tag/continuous-integration/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.carbonfive.com</link>
	<description>The blog of Carbon Five</description>
	<lastBuildDate>Thu, 19 Apr 2012 16:48:46 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Automated ad hoc builds using Xcode 4</title>
		<link>http://blog.carbonfive.com/2011/05/04/automated-ad-hoc-builds-using-xcode-4/</link>
		<comments>http://blog.carbonfive.com/2011/05/04/automated-ad-hoc-builds-using-xcode-4/#comments</comments>
		<pubDate>Wed, 04 May 2011 23:24:19 +0000</pubDate>
		<dc:creator>Jonah Williams</dc:creator>
				<category><![CDATA[Mobile]]></category>
		<category><![CDATA[continuous integration]]></category>
		<category><![CDATA[Deployment]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[teamcity]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://blog.carbonfive.com/?p=3521</guid>
		<description><![CDATA[I&#8217;ve previously discussed Continuous Integration for iPhone Projects in TeamCity using Xcode 3 and Building Xcode 4 Projects from the Command Line. Now I&#8217;ll tie those together and use TeamCity to automatically create ad hoc builds I can install over &#8230; <a href="http://blog.carbonfive.com/2011/05/04/automated-ad-hoc-builds-using-xcode-4/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve previously discussed <a href="http://blog.carbonfive.com/2010/08/08/continuous-integration-for-iphone-projects-in-teamcity/">Continuous Integration for iPhone Projects in TeamCity</a> using Xcode 3 and <a href="http://blog.carbonfive.com/2011/04/06/building-xcode-4-projects-from-the-command-line/">Building Xcode 4 Projects from the Command Line</a>. Now I&#8217;ll tie those together and use TeamCity to automatically create ad hoc builds I can install over the air (directly onto a device without using iTunes) every time I check in code.</p>
<p><span id="more-3521"></span></p>
<p>I created a basic project configuration in TeamCity 6 to checkout my iOS project from git.</p>
<p>I set the artifact paths for this configuration to</p>
<blockquote><p>
project_name.acceptance.app*<br />
ad_hoc/*.png
</p></blockquote>
<p>This will eventually allow TeamCity to collect the icons, project_name.acceptance.app.ipa, and project_name.acceptance.app.plist files needed to perform an over the air install of the ad hoc build.</p>
<p>Finally I created the following custom script build step (available as <a href="https://gist.github.com/949831">https://gist.github.com/949831</a>).</p>
<pre class="brush: bash; title: ; notranslate">
#!/bin/bash

# https://gist.github.com/949831
# http://blog.carbonfive.com/2011/05/04/automated-ad-hoc-builds-using-xcode-4/

# command line OTA distribution references and examples
# http://nachbaur.com/blog/how-to-automate-your-iphone-app-builds-with-hudson
# http://nachbaur.com/blog/building-ios-apps-for-over-the-air-adhoc-distribution
# http://blog.octo.com/en/automating-over-the-air-deployment-for-iphone/
# http://www.neat.io/posts/2010/10/27/automated-ota-ios-app-distribution.html

project_dir=`pwd`

# Configuration
environment_name=&quot;staging&quot;
keychain=&quot;ci_keys&quot;
keychain_password=&quot;super secret&quot;
workspace=&quot;MyApp.xcworkspace&quot;
scheme=&quot;Ad Hoc&quot;
info_plist=&quot;$project_dir/MyApp-Info.plist&quot;
environment_plist=&quot;$environment_name.plist&quot;
environment_info_plist=&quot;$environment_name-Info.plist&quot;
product_name=&quot;My App $environment_name&quot;
mobileprovision=&quot;$project_dir/ad_hoc/MyAppStaging.mobileprovision&quot;
provisioning_profile=&quot;iPhone Distribution: My Company, LLC&quot;
build_number=&quot;%env.BUILD_NUMBER%&quot;
artifacts_url=&quot;http://my_ci_server.example/artifacts/$build_number&quot;
display_image_name=&quot;Icon-57.png&quot;
full_size_image_name=&quot;Icon-512.png&quot;

function failed()
{
    local error=${1:-Undefined error}
    echo &quot;Failed: $error&quot; &gt;&amp;2
    exit 1
}

function validate_keychain()
{
  # unlock the keychain containing the provisioning profile's private key and set it as the default keychain
  security unlock-keychain -p &quot;$keychain_password&quot; &quot;$HOME/Library/Keychains/$keychain.keychain&quot;
  security default-keychain -s &quot;$HOME/Library/Keychains/$keychain.keychain&quot;

  #describe the available provisioning profiles
  echo &quot;Available provisioning profiles&quot;
  security find-identity -p codesigning -v

  #verify that the requested provisioning profile can be found
  (security find-certificate -a -c &quot;$provisioning_profile&quot; -Z | grep ^SHA-1) || failed provisioning_profile
}

function describe_sdks()
{
  #list the installed sdks
  echo &quot;Available SDKs&quot;
  xcodebuild -showsdks
}

function describe_workspace()
{
  #describe the project workspace
  echo &quot;Available schemes&quot;
  xcodebuild -list -workspace $workspace
}

function increment_version()
{
  cd &quot;MyApp&quot;
  agvtool -noscm new-version -all $build_number
  cd ..
}

function set_environment()
{
  #copy the info plist for the selected environment into place
  cp -v &quot;MyApp/$environment_info_plist&quot; $info_plist || failed environment_plist
  #copy the environment settings plist into place
  cp -v &quot;MyApp/$environment_plist&quot; &quot;MyApp/environment.plist&quot; || failed environment

  #extract settings from the Info.plist file
  info_plist_domain=$(ls $info_plist | sed -e 's/\.plist//')
  short_version_string=$(defaults read &quot;$info_plist_domain&quot; CFBundleShortVersionString)
  bundle_identifier=$(defaults read &quot;$info_plist_domain&quot; CFBundleIdentifier)
  echo &quot;Environment set to $bundle_identifier at version $short_version_string&quot;
}

function build_app()
{
  local devired_data_path=&quot;$HOME/Library/Developer/Xcode/DerivedData&quot;

  #get the name of the workspace to be build, used as the prefix of the DerivedData directory for this build
  local workspace_name=$(echo &quot;$workspace&quot; | sed -n 's/\([^\.]\{1,\}\)\.xcworkspace/\1/p')
  #build the app
  echo &quot;Running xcodebuild &gt; xcodebuild_output ...&quot;

#  disabled overriding PRODUCT_NAME, setting applies to all built targets in Xcode 4 which renames static library target dependencies and breaks linking
#  xcodebuild -verbose -workspace &quot;$workspace&quot; -scheme &quot;$scheme&quot; -sdk iphoneos -configuration Release clean build PRODUCT_NAME=&quot;$product_name&quot; &gt;| xcodebuild_output
  xcodebuild -verbose -workspace &quot;$workspace&quot; -scheme &quot;$scheme&quot; -sdk iphoneos -configuration Release clean build &gt;| xcodebuild_output

  if [ $? -ne 0 ]
  then
    tail -n20 xcodebuild_output
    failed xcodebuild
  fi

  #locate this project's DerivedData directory
  local project_derived_data_directory=$(grep -oE &quot;$workspace_name-([a-zA-Z0-9]+)[/]&quot; xcodebuild_output | sed -n &quot;s/\($workspace_name-[a-z]\{1,\}\)\//\1/p&quot; | head -n1)
  local project_derived_data_path=&quot;$devired_data_path/$project_derived_data_directory&quot;
  #locate the .app file

#  infer app name since it cannot currently be set using the product name, see comment above
#  project_app=&quot;$product_name.app&quot;
  project_app=$(ls -1 &quot;$project_derived_data_path/Build/Products/Release-iphoneos/&quot; | grep &quot;.*\.app$&quot; | head -n1)

  # if [ $(ls -1 &quot;$project_derived_data_path/Build/Products/Release-iphoneos/$project_app&quot; | wc -l) -ne 1 ]
  if [ $(ls -1 &quot;$project_derived_data_path/Build/Products/Release-iphoneos/&quot; | grep &quot;.*\.app$&quot; | wc -l) -ne 1 ]
  then
    echo &quot;Failed to find a single .app build product.&quot;
    # echo &quot;Failed to locate $project_derived_data_path/Build/Products/Release-iphoneos/$project_app&quot;
    failed locate_built_product
  fi
  echo &quot;Built $project_app in $project_derived_data_path&quot;

  #copy app and dSYM files to the working directory
  cp -Rf &quot;$project_derived_data_path/Build/Products/Release-iphoneos/$project_app&quot; $project_dir
  cp -Rf &quot;$project_derived_data_path/Build/Products/Release-iphoneos/$project_app.dSYM&quot; $project_dir

  #rename app and dSYM so that multiple environments with the same product name are identifiable
  echo &quot;Retrieving build products...&quot;
  rm -rf $project_dir/$bundle_identifier.app
  rm -rf $project_dir/$bundle_identifier.app.dSYM
  mv -f &quot;$project_dir/$project_app&quot; &quot;$project_dir/$bundle_identifier.app&quot;
  echo &quot;$project_dir/$bundle_identifier.app&quot;
  mv -f &quot;$project_dir/$project_app.dSYM&quot; &quot;$project_dir/$bundle_identifier.app.dSYM&quot;
  echo &quot;$project_dir/$bundle_identifier.app.dSYM&quot;
  project_app=$bundle_identifier.app

  #relink CodeResources, xcodebuild does not reliably construct the appropriate symlink
  rm &quot;$project_app/CodeResources&quot;
  ln -s &quot;$project_app/_CodeSignature/CodeResources&quot; &quot;$project_app/CodeResources&quot;
}

function sign_app()
{
  echo &quot;Codesign as \&quot;$provisioning_profile\&quot;, embedding provisioning profile $mobileprovision&quot;
  #sign build for distribution and package as a .ipa
  xcrun -sdk iphoneos PackageApplication &quot;$project_dir/$project_app&quot; -o &quot;$project_dir/$project_app.ipa&quot; --sign &quot;$provisioning_profile&quot; --embed &quot;$mobileprovision&quot; || failed codesign
}

function verify_app()
{
  #verify the resulting app
  codesign -d -vvv --file-list - &quot;$project_dir/$project_app&quot; || failed verification
}

function build_ota_plist()
{
  echo &quot;Generating $project_app.plist&quot;
  cat &lt;&lt; EOF &gt; $project_app.plist
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;
&lt;plist version=&quot;1.0&quot;&gt;
&lt;dict&gt;
  &lt;key&gt;items&lt;/key&gt;
  &lt;array&gt;
    &lt;dict&gt;
      &lt;key&gt;assets&lt;/key&gt;
      &lt;array&gt;
        &lt;dict&gt;
          &lt;key&gt;kind&lt;/key&gt;
          &lt;string&gt;software-package&lt;/string&gt;
          &lt;key&gt;url&lt;/key&gt;
          &lt;string&gt;$artifacts_url/$project_app.ipa&lt;/string&gt;
        &lt;/dict&gt;
        &lt;dict&gt;
          &lt;key&gt;kind&lt;/key&gt;
          &lt;string&gt;full-size-image&lt;/string&gt;
          &lt;key&gt;needs-shine&lt;/key&gt;
          &lt;true/&gt;
          &lt;key&gt;url&lt;/key&gt;
          &lt;string&gt;$artifacts_url/$full_size_image_name&lt;/string&gt;
        &lt;/dict&gt;
        &lt;dict&gt;
          &lt;key&gt;kind&lt;/key&gt;
          &lt;string&gt;display-image&lt;/string&gt;
          &lt;key&gt;needs-shine&lt;/key&gt;
          &lt;true/&gt;
          &lt;key&gt;url&lt;/key&gt;
          &lt;string&gt;$artifacts_url/$display_image_name&lt;/string&gt;
        &lt;/dict&gt;
      &lt;/array&gt;
      &lt;key&gt;metadata&lt;/key&gt;
      &lt;dict&gt;
        &lt;key&gt;bundle-identifier&lt;/key&gt;
        &lt;string&gt;$bundle_identifier&lt;/string&gt;
        &lt;key&gt;bundle-version&lt;/key&gt;
        &lt;string&gt;$short_version_string $build_number&lt;/string&gt;
        &lt;key&gt;kind&lt;/key&gt;
        &lt;string&gt;software&lt;/string&gt;
        &lt;key&gt;subtitle&lt;/key&gt;
        &lt;string&gt;$environment_name&lt;/string&gt;
        &lt;key&gt;title&lt;/key&gt;
        &lt;string&gt;$project_app&lt;/string&gt;
      &lt;/dict&gt;
    &lt;/dict&gt;
  &lt;/array&gt;
&lt;/dict&gt;
&lt;/plist&gt;
EOF
}

echo &quot;**** Validate Keychain&quot;
validate_keychain
echo
echo &quot;**** Describe SDKs&quot;
describe_sdks
echo
echo &quot;**** Describe Workspace&quot;
describe_workspace
echo
echo &quot;**** Set Environment&quot;
set_environment
echo
echo &quot;**** Increment Bundle Version&quot;
increment_version
echo
echo &quot;**** Build&quot;
build_app
echo
echo &quot;**** Package Application&quot;
sign_app
echo
echo &quot;**** Verify&quot;
verify_app
echo
echo &quot;**** Prepare OTA Distribution&quot;
build_ota_plist
echo
echo &quot;**** Complete!&quot;
</pre>
<p>That is quite a few functions but the bottom of the script steps through them in what is hopefully an understandable sequence.</p>
<ol>
<li>Unlock the keychain containing the private key and provisioning profile used to sign the ad hoc build. Necessary since the TeamCity user&#8217;s login keychain may be locked when this build runs.</li>
<li>List the available sdks on the build machine (unnecessary but I found it helpful when debugging build settings).</li>
<li>List the schemes found in the workspace to be built (again purely for debugging).</li>
<li>Copy a plist containing application settings to &#8220;environment.plist&#8221; which will be copied into the app bundle when built and used to define application behavior, for example it contains the url of the server this build should communicate with.</li>
<li>Build the app using the specified workspace and scheme. Copy the resulting app and dSYM to the project directory so TeamCity can easily find them as build artifacts.</li>
<li>Sign the app using the specified mobile provisioning profile and create a &#8220;.ipa&#8221; package.</li>
<li>Verify that the app was successfully signed.</li>
<li>Create a plist to allow over the air installation of the app.</li>
</ol>
<p>Once run any device which has been added to the mobile provisioning profile used to sign this build can install the app just by visiting (using an appropriate %system.teamcity.buildType.id% for the TeamCity build configuration).</p>
<blockquote><p>
itms-services://?action=download-manifest&amp;url=http://teamcity.example.com:8111/guestAuth/repository/download/%system.teamcity.buildType.id%/.lastSuccessful/project_name.acceptance.app.plist
</p></blockquote>
<p>Possible issues:</p>
<ul>
<li>Access to the keychain will present a security dialog the first time this build runs so it was necessary for me to sign into the TeamCity user&#8217;s account using VNC and allow access to that keychain.</li>
<li>I found that builds occasionally failed to correctly create the CodeResources symlink so I recreate it manually. When this link was broken the ipa would fail verification.</li>
<li>An iOS device won&#8217;t be able to install the app if the artifacts require authenticating to the TeamCity server so I enabled guest access. Alternately I could have exposed those artifacts through some other service and created a nice installation guide page which links to them if I didn&#8217;t want to allow guest access to my TeamCity server.</li>
</ul>
<p>For additional resources for building over the air distribution builds take a look at:</p>
<p>Mike Nachbaur&#8217;s posts on &#8220;<a href="http://nachbaur.com/blog/how-to-automate-your-iphone-app-builds-with-hudson">How to Automate your iPhone App Builds with Hudson</a>&#8221; and &#8220;<a href="http://nachbaur.com/blog/building-ios-apps-for-over-the-air-adhoc-distribution">Building iOS Apps for Over the Air Ad Hoc Distribution</a>&#8220;.<br />
Vincent Daubry&#8217;s &#8220;<a href="http://blog.octo.com/en/automating-over-the-air-deployment-for-iphone/">Automating Over The Air Deployment for iPhone</a>&#8220;.<br />
Basil Shkara&#8217;s &#8220;<a href="http://www.neat.io/posts/2010/10/27/automated-ota-ios-app-distribution.html">Automated OTA iOS App Distribution</a>&#8220;.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.carbonfive.com/2011/05/04/automated-ad-hoc-builds-using-xcode-4/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Generating documentation from specs</title>
		<link>http://blog.carbonfive.com/2011/04/21/generating-documentation-from-specs/</link>
		<comments>http://blog.carbonfive.com/2011/04/21/generating-documentation-from-specs/#comments</comments>
		<pubDate>Thu, 21 Apr 2011 16:30:58 +0000</pubDate>
		<dc:creator>Jonah Williams</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[continuous integration]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[rspec]]></category>
		<category><![CDATA[Testing]]></category>

		<guid isPermaLink="false">http://blog.carbonfive.com/?p=3442</guid>
		<description><![CDATA[On one of our rails projects I am creating an api to allow mobile clients to access a web service. I need to provide documentation of this API to the developers of several different clients during its development. Normally I &#8230; <a href="http://blog.carbonfive.com/2011/04/21/generating-documentation-from-specs/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>On one of our rails projects I am creating an api to allow mobile clients to access a web service. I need to provide documentation of this API to the developers of several different clients during its development. Normally I would prefer to let my API tests act as documentation of the expected API behavior but in this case I cannot give all of the client developers access to the rails project&#8217;s git repository and even the cleanest rspec specs might not be legible to developers without ruby experience.</p>
<p>I also don&#8217;t want to spend time manually updating documentation every time I change the API and don&#8217;t want to risk wasting other developers&#8217; time by providing out of date or inaccurate documentation.</p>
<p>Instead I hacked together a rake task to covert my API controller specs into documentation using a custom rspec formatter. Now I can automatically update the documentation as part of our CI build process.<br />
<span id="more-3442"></span><br />
This example is available as <a href="https://gist.github.com/934902">https://gist.github.com/934902</a></p>
<p>First I wrote a rake task to generate my API documentation. This runs my API controller specs after adding some additional files to the ruby load path and requiring them to patch ActionController::TestCase::Behavior and load a custom rspec formatter.</p>
<pre class="brush: ruby; title: ; notranslate">
require 'rubygems'
require 'rspec/core/rake_task'

namespace :project_name do
  namespace :api do
    desc 'Generate API request documentation from API specs'
    RSpec::Core::RakeTask.new('generate_docs') do |t|
      t.pattern = 'spec/controllers/api/**/*_spec.rb'
      t.rspec_opts = [&quot;-Ilib/tasks/api_docs&quot;, &quot;-rinstrument_specs&quot;, &quot;-rapi_formatter&quot;, &quot;--format APIFormatter&quot;]
    end
  end
end
</pre>
<p>I patched ActionController::TestCase::Behavior to capture the requests and responses from process (called by get, put, post, and delete) and store them in rspec&#8217;s example metadata.</p>
<pre class="brush: ruby; title: ; notranslate">
require 'action_dispatch'
require 'action_controller'

module InstrumentSpecs
  module ::ActionController::TestCase::Behavior
    alias_method :process_without_logging, :process

    def process(action, parameters = nil, session = nil, flash = nil, http_method = 'GET')
      version, route = described_class.to_s.match(/::(Vd)::(S+)Controller/)[1..2].collect(&amp;:downcase)
      curl = &quot;curl &quot;
      parameters.each {|key, value| curl &lt;&lt; &quot;-d &quot;#{key}=#{CGI.escape(value)}&quot; &quot; } if parameters.present?
      curl &lt;&lt; &quot;-X #{http_method} &quot;
      curl &lt;&lt; &quot;https://api.host.example/#{version}/#{route} &quot;
      example.metadata[:curl] = curl

      response = process_without_logging(action, parameters, session, flash, http_method)
      example.metadata[:response] = &quot;#{response.status} #{response.body}&quot;

      response
    end
  end
end
</pre>
<p>Finally I added a custom rspec formatter to output the requests and responses as markdown.</p>
<pre class="brush: ruby; title: ; notranslate">
require 'rspec/core/formatters/base_formatter'

class APIFormatter &lt; RSpec::Core::Formatters::BaseFormatter
  def initialize(output)
    super(output)
  end

  def example_group_started(example_group)
    indented_message(&quot;#{example_group.description}n&quot;, example_group)
  end

  def example_group_finished(example_group)

  end

  def example_started(example)
    indented_message(&quot;#{example.description}n&quot;, example)
  end

  def example_passed(example)
    indented_message(&quot;#{example.metadata[:curl]}n&quot;)
    indented_message(&quot;#{example.metadata[:response]}nn&quot;)
  end

  def example_failed(example)

  end

  def example_pending(example)

  end

  private

  def indented_message(message, context = nil)
    if context.present?
      if context.respond_to?(:example_group)
        (context.example_group.ancestors.count + 1).times do
          output &lt;&lt; '#'
        end
      else
        context.ancestors.count.times do
          output &lt;&lt; '#'
        end
      end
    else
      output &lt;&lt; '    '
    end
    output &lt;&lt; message
  end
end
</pre>
<p><code>#Api::V1::AccountsController<br />
###index<br />
###without an API key<br />
####behaves like an unauthenticated user<br />
#####responds with success status<br />
curl -X GET https://api.host.example/v1/accounts<br />
200 {"error":{"type":"Unauthorized","message":"Authentication is required to access this resource"}}<br />
...<br />
</code></p>
<p>Now I can generate a description of my API based on my specs complete with examples of hitting the API using curl and the expected response status and body. As long as I name my rspec assertions and contexts well this should be legible and always up to date since I can regenerate the docs and push them to a github wiki page every time my specs pass on a continuous integration server.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.carbonfive.com/2011/04/21/generating-documentation-from-specs/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Running Xcode 4 unit tests from the command line</title>
		<link>http://blog.carbonfive.com/2011/04/06/running-xcode-4-unit-tests-from-the-command-line/</link>
		<comments>http://blog.carbonfive.com/2011/04/06/running-xcode-4-unit-tests-from-the-command-line/#comments</comments>
		<pubDate>Wed, 06 Apr 2011 12:00:02 +0000</pubDate>
		<dc:creator>Jonah Williams</dc:creator>
				<category><![CDATA[Mobile]]></category>
		<category><![CDATA[continuous integration]]></category>
		<category><![CDATA[Testing]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://blog.carbonfive.com/?p=3351</guid>
		<description><![CDATA[Command line builds for Xcode 4 projects are a good first step but I really want to get my project&#8217;s tests running on a continuous integration server again. Since &#8220;test&#8221; isn&#8217;t a valid build action to pass to xcodebuild I&#8217;ve &#8230; <a href="http://blog.carbonfive.com/2011/04/06/running-xcode-4-unit-tests-from-the-command-line/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://blog.carbonfive.com/2011/04/06/building-xcode-4-projects-from-the-command-line/">Command line builds for Xcode 4 projects</a> are a good first step but I really want to get my project&#8217;s tests running on a continuous integration server again. Since &#8220;test&#8221; isn&#8217;t a valid build action to pass to xcodebuild I&#8217;ve been looking for a configuration which would allow me to run tests in a headless environment.<br />
<span id="more-3351"></span><br />
I expect that GTM, GHUnit, and Cedar will all have reliable support for Xcode 4 projects eventually but I would like to start with just seeing some SenTestingKit tests pass.</p>
<p>I have been able to run test suites from the command line but only for &#8220;logic&#8221; tests. From the <a href="http://developer.apple.com/library/ios/#documentation/Xcode/Conceptual/iphone_development/135-Unit_Testing_Applications/unit_testing_applications.html">iOS Development Guide</a>:</p>
<blockquote><p>Xcode offers two types of unit tests: logic tests and application tests.</p>
<p>Logic tests.<br />
These tests check the correct functionality of your code in a clean-room environment; that is, your code is not run inside an application. Logic tests let you put together very specific test cases to exercise your code at a very granular level (a single method in class) or as part of a workflow (several methods in one or more classes). You can use logic tests to perform stress-testing of your code to ensure that it behaves correctly in extreme situations that are unlikely in a running application. These tests help you produce robust code that works correctly when used in ways that you did not anticipate. Logic tests are iOS Simulator SDK–based; however, the application is not run in iOS Simulator: The code being tested is run during the corresponding target’s build phase.</p>
<p>Application tests.<br />
These tests check the functionality of your code in a running application. You can use application tests to ensure that the connections of your user-interface controls (outlets and actions) remain in place, and that your controls and controller objects work correctly with your object model as you work on your application. Because application tests run only on a device, you can also use these tests to perform hardware testing, such as getting the location of the device.</p></blockquote>
<p>I am able to create a set of logic tests as a separate build target and scheme which will successfully run as part of an xcodebuild build.</p>
<ol>
<li>Create a new &#8220;LogicTests&#8221; unit test build target.</li>
<li>Leave the &#8220;Test Host&#8221; build setting blank.</li>
<li>Set the &#8220;Test After Build&#8221; build setting to &#8220;No&#8221;.</li>
<li>Do not write tests which require an application to be present (ie no window or application delegate available).</li>
<li>Create a new &#8220;LogicTests&#8221; scheme which includes the &#8220;LogicTests&#8221; build target in its run action.</li>
<li>Run the &#8220;LogicTests&#8221; scheme using xcodebuild.</li>
</ol>
<p><div id="attachment_3375" class="wp-caption alignnone" style="width: 310px"><a href="http://blog.carbonfive.com/wp-content/uploads/2011/04/screen-shot-2011-04-05-at-11-51-39-pm.png"><img src="http://blog.carbonfive.com/wp-content/uploads/2011/04/screen-shot-2011-04-05-at-11-51-39-pm.png?w=300" alt="Scheme for running logic tests" title="logic_test_scheme" width="300" height="205" class="size-medium wp-image-3375" /></a><p class="wp-caption-text">Scheme for running logic tests</p></div></p>
<blockquote><p>&gt; /Developer_Xcode4/usr/bin/xcodebuild -workspace WrappingScrollView.xcworkspace -scheme logictests -sdk iphonesimulator4.3 -configuration Debug clean build</p>
<p>&#8230;</p>
<p>Run test suite logictests<br />
Test Suite &#8216;logictests&#8217; started at 2011-04-06 07:44:57 +0000<br />
Run test case testExample<br />
Test Case &#8216;-[logictests testExample]&#8216; started.<br />
/Users/Jonah/Desktop/WrappingScrollView/WrappingScrollViewDemo/logictests/logictests.m:30: error: -[logictests testExample] : Unit tests are not implemented yet in logictests<br />
Test Case &#8216;-[logictests testExample]&#8216; failed (0.000 seconds).</p>
<p>Test Suite &#8216;logictests&#8217; finished at 2011-04-06 07:44:57 +0000.<br />
Executed 1 test, with 1 failure (0 unexpected) in 0.000 (0.000) seconds
</p></blockquote>
<p>That&#8217;s not a great solution but it at least allows me to run some tests on a continuous integration server. Hopefully I can find a way to run application tests through xcodebuild as well.</p>
<p>In case it is of any help to other developers struggling with the difference between command line and Xcode builds. The &#8220;Run Script&#8221; build phase of a unit test build target just runs &#8220;${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests&#8221;. The RunUnitTests script in turn invokes a platform specific script like &#8220;${SYSTEM_DEVELOPER_DIR}/Platforms/iPhoneSimulator.platform/Developer/Tools/RunPlatformUnitTests&#8221;  which ultimately calls RunTestsForBundle in &#8220;${SYSTEM_DEVELOPER_DIR}/Tools/RunPlatformUnitTests.include&#8221;. Hopefully it will prove possible to use these scripts to match the behavior seen when running tests from within Xcode to automatically run application tests.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.carbonfive.com/2011/04/06/running-xcode-4-unit-tests-from-the-command-line/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Building Xcode 4 projects from the command line</title>
		<link>http://blog.carbonfive.com/2011/04/06/building-xcode-4-projects-from-the-command-line/</link>
		<comments>http://blog.carbonfive.com/2011/04/06/building-xcode-4-projects-from-the-command-line/#comments</comments>
		<pubDate>Wed, 06 Apr 2011 10:00:59 +0000</pubDate>
		<dc:creator>Jonah Williams</dc:creator>
				<category><![CDATA[Mobile]]></category>
		<category><![CDATA[continuous integration]]></category>
		<category><![CDATA[Deployment]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://blog.carbonfive.com/?p=3336</guid>
		<description><![CDATA[The Xcode 4 developer tools introduced some changes to the xcodebuild command line tool. Instead of specifying a project and target developers can now provide a workspace and scheme to build. &#62; /Developer_Xcode4/usr/bin/xcodebuild -help Usage: xcodebuild [-project ] [[-target ]&#8230;&#124;-alltargets] &#8230; <a href="http://blog.carbonfive.com/2011/04/06/building-xcode-4-projects-from-the-command-line/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>The Xcode 4 developer tools introduced some changes to the xcodebuild command line tool. Instead of specifying a project and target developers can now provide a workspace and scheme to build.<br />
<span id="more-3336"></span></p>
<blockquote><p>&gt; /Developer_Xcode4/usr/bin/xcodebuild -help<br />
Usage: xcodebuild [-project ] [[-target ]&#8230;|-alltargets] [-configuration ] [-arch ]&#8230; [-sdk [|]] [=]&#8230; []&#8230;<br />
       xcodebuild -workspace  -scheme  [-configuration ] [-arch ]&#8230; [-sdk [|]] [=]&#8230; []&#8230;<br />
       xcodebuild -version [-sdk [|] [] ]<br />
       xcodebuild -list [[-project ]|[-workspace ]]<br />
       xcodebuild -showsdks
</p></blockquote>
<p>The workspace and scheme names should be known from the project. The default configuration options are &#8220;Debug&#8221; and &#8220;Release&#8221;. The &#8220;-showsdks&#8221; option lists available SDKs.</p>
<blockquote><p>&gt; /Developer_Xcode4/usr/bin/xcodebuild -showsdks<br />
Mac OS X SDKs:<br />
	Mac OS X 10.6                 	-sdk macosx10.6</p>
<p>iOS SDKs:<br />
	iOS 4.3                       	-sdk iphoneos4.3</p>
<p>iOS Simulator SDKs:<br />
	Simulator &#8211; iOS 3.2           	-sdk iphonesimulator3.2<br />
	Simulator &#8211; iOS 4.0           	-sdk iphonesimulator4.0<br />
	Simulator &#8211; iOS 4.1           	-sdk iphonesimulator4.1<br />
	Simulator &#8211; iOS 4.2           	-sdk iphonesimulator4.2<br />
	Simulator &#8211; iOS 4.3           	-sdk iphonesimulator4.3
</p></blockquote>
<p>Available build actions are listed in the xcodebuild man pages. Unfortunately these do not match the actions available in a scheme and the command line does not provide a mechanism for testing, running, profiling, or analyzing builds.</p>
<blockquote><p>&gt; man xcodebuild<br />
&#8230;</p>
<p>buildaction &#8230;<br />
           Specify a build action (or actions) to perform on the target. Available build actions are:</p>
<p>           build       Build the target in the build root (SYMROOT).  This is the default build action.</p>
<p>           archive     Archive a scheme from the build root (SYMROOT).  This requires specifying a workspace and scheme.</p>
<p>           installsrc  Copy the source of the project to the source root (SRCROOT).</p>
<p>           install     Build the target and install it into the target&#8217;s installation directory in the distribution root (DSTROOT).</p>
<p>           clean       Remove build products and intermediate files from the build root (SYMROOT).
</p></blockquote>
<p>Given all of these configuration options it is then possible to perform builds from the command line.</p>
<blockquote><p>&gt; /Developer_Xcode4/usr/bin/xcodebuild -workspace WrappingScrollView.xcworkspace -scheme WrappingScrollViewDemo -sdk iphonesimulator4.3 -configuration Debug clean build<br />
Build settings from command line:<br />
    SDKROOT = iphonesimulator4.3</p>
<p>=== CLEAN NATIVE TARGET JCFWrappingScrollView OF PROJECT JCFWrappingScrollView WITH CONFIGURATION Debug ===<br />
Check dependencies</p>
<p>&#8230;</p>
<p>** CLEAN SUCCEEDED **</p>
<p>=== BUILD NATIVE TARGET JCFWrappingScrollView OF PROJECT JCFWrappingScrollView WITH CONFIGURATION Debug ===<br />
Check dependencies</p>
<p>ProcessPCH /Users/Jonah/Library/Developer/Xcode/DerivedData/WrappingScrollView-fqscqfdtpoqunuanehtbgpseirdj/Build/PrecompiledHeaders/JCFWrappingScrollView-Prefix-dkkjrdaonxokgpbkgjfmpmcpadoz/JCFWrappingScrollView-Prefix.pch.gch JCFWrappingScrollView/JCFWrappingScrollView-Prefix.pch normal i386 objective-c com.apple.compilers.llvmgcc42<br />
    cd /Users/Jonah/Desktop/WrappingScrollView/JCFWrappingScrollView<br />
    setenv LANG en_US.US-ASCII</p>
<p>&#8230;</p>
<p>** BUILD SUCCEEDED **
</p></blockquote>
<p>Hopefully that is sufficient to automatically produce ad-hoc builds on a continuous integration server.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.carbonfive.com/2011/04/06/building-xcode-4-projects-from-the-command-line/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Continuous integration for iPhone projects in TeamCity</title>
		<link>http://blog.carbonfive.com/2010/08/08/continuous-integration-for-iphone-projects-in-teamcity/</link>
		<comments>http://blog.carbonfive.com/2010/08/08/continuous-integration-for-iphone-projects-in-teamcity/#comments</comments>
		<pubDate>Sun, 08 Aug 2010 22:58:32 +0000</pubDate>
		<dc:creator>Jonah Williams</dc:creator>
				<category><![CDATA[Mobile]]></category>
		<category><![CDATA[continuous integration]]></category>
		<category><![CDATA[Testing]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://blog.carbonfive.com/?p=1101</guid>
		<description><![CDATA[Carbon Five has been using TeamCity as our continuous integration server for most of our recent projects, including our iPhone work. Out continuous integration environment monitors the git repository used by each project, runs the project&#8217;s tests each time a &#8230; <a href="http://blog.carbonfive.com/2010/08/08/continuous-integration-for-iphone-projects-in-teamcity/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Carbon Five has been using <a href="http://www.jetbrains.com/teamcity/">TeamCity</a> as our continuous integration server for most of our recent projects, including our iPhone work. Out continuous integration environment monitors the git repository used by each project, runs the project&#8217;s tests each time a change is pushed to the repository, and can automatically produce an ad-hoc build of an app each time the tests pass.<br />
<span id="more-1101"></span><br />
<strong>Configuring the TeamCity build agent</strong><br />
In order to build an iPhone project I need a build runner running on an OS X machine with Xcode installed so I added a remote build agent on a mac mini. Each of the build configurations below then requires that compatible build agents be running on OS X.</p>
<p><strong>Running unit tests with GTM</strong><br />
I have been using <a href="http://code.google.com/p/google-toolbox-for-mac/">GTM</a> to run iPhone unit tests as part of the build process for a &#8220;Unit Tests&#8221; build target (see Alon&#8217;s post on our <a href="http://blog.carbonfive.com/2009/02/testing/iphone-unit-testing-toolkit">iPhone Unit Testing Toolkit)</a>. Running these tests with a TeamCity build agent just requires a command line build runner which calls the `xcodebuild` command and specifies the project, built target, and configuration to build.</p>
<table>
<tbody>
<tr>
<td>Command executable:</td>
<td>/Developer/usr/bin/xcodebuild</td>
</tr>
<tr>
<td>Command parameters:</td>
<td>-project example_project.xcodeproj -target &#8220;Unit Tests&#8221; -configuration &#8220;Debug&#8221; -sdk iphonesimulator4.0</td>
</tr>
</tbody>
<table>
<p><strong>Ad-hoc builds</strong><br />
Ad-hoc builds run with a similar command:</p>
<table>
<tbody>
<tr>
<td>Command executable:</td>
<td>/Developer/usr/bin/xcodebuild</td>
</tr>
<tr>
<td>Command parameters:</td>
<td>-project example_project.xcodeproj -target &#8220;ExampleProject&#8221; -configuration &#8220;Distribution&#8221; -sdk iphoneos4.0</td>
</tr>
</tbody>
<table>
Once the ad-hoc build has been created I want to save the resulting app and its debug symbols so I add these as build artifacts under the TeamCity build configuration&#8217;s General Settings:</p>
<table>
<thead>
<tr>
<th>Artifact paths:</th>
</tr>
</thead>
<tbody>
<tr>
<td>/Users/teamcity/xcode_builds/Distribution-iphoneos/ExampleProject.app =&gt; ExampleProject.zip</td>
</tr>
<tr>
<td>/Users/teamcity/xcode_builds/Distribution-iphoneos/ExampleProject.app.dSYM =&gt; ExampleProject.app.dSYM.zip</td>
</tr>
</tbody>
</table>
<p>Now my ad-hoc builds are produced automatically, always up to date with my working code changes, and available as an easy download from my TeamCity server. TeamCity will also save the artifacts for each build so I can easily retrieve the dSYM for a particular ad-hoc build to symbolicate a crashlog for that build on any developer&#8217;s machine.</p>
<p><strong>Future improvements</strong><br />
If necessary I can run tests on actual iPhone hardware by changing the sdk (`-sdk iphoneos4.0`) but I am not yet sure how I could specify which one of multiple devices would run the tests. It would be nice to eventually be able to choose between multiple devices so I can deliberately run some tests on a device with a specific OS version or feature set.<br />
With my current configuration TeamCity can only report a pass/fail status for iPhone tests. I need to consider modifying the GTM test runner script or switching to <a href="http://github.com/gabriel/gh-unit">GHUnit</a> or <a href="http://github.com/pivotal/cedar">Cedar</a> to get per-test results and then be able to build up a history of individual test failures.<br />
I also need to add a build configuration which uses agvtool to automatically increment the project&#8217;s build number as part of every ad-hoc build.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.carbonfive.com/2010/08/08/continuous-integration-for-iphone-projects-in-teamcity/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Deploying to Heroku from TeamCity</title>
		<link>http://blog.carbonfive.com/2010/08/06/deploying-to-heroku-from-teamcity/</link>
		<comments>http://blog.carbonfive.com/2010/08/06/deploying-to-heroku-from-teamcity/#comments</comments>
		<pubDate>Fri, 06 Aug 2010 07:09:32 +0000</pubDate>
		<dc:creator>Jonah Williams</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[continuous integration]]></category>
		<category><![CDATA[Deployment]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[rapid development]]></category>
		<category><![CDATA[Testing]]></category>

		<guid isPermaLink="false">http://blog.carbonfive.com/?p=1098</guid>
		<description><![CDATA[Previously I discussed our TeamCity configuration using RVM and mentioned that we often use git to deploy projects. Today I&#8217;ll share an example of how a TeamCity build agent can trigger deployments of a application hosted on Heroku and some &#8230; <a href="http://blog.carbonfive.com/2010/08/06/deploying-to-heroku-from-teamcity/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Previously I discussed our <a href="http://blog.carbonfive.com/wp-content/uploads/2010/12/tc_heroku_build_runner21.png2010/08/ruby-on-rails/using-rvm-on-teamcity-build-agents">TeamCity configuration</a> using RVM and mentioned that we often use git to deploy projects. Today I&#8217;ll share an example of how a TeamCity build agent can trigger deployments of a application hosted on <a href="http://heroku.com/">Heroku</a> and some of the challenges I found.<br />
<span id="more-1098"></span><br />
<strong>Add an ssh config entry for the project&#8217;s access to Heroku</strong></p>
<p>Much like shared github access I need to be able to specify which ssh key a particular project&#8217;s connections to heroku should use. Since I want to use client side checkouts I can&#8217;t specify a private key within TeamCity but I do know that all my compatible build agents are local so I can add a new entry to `~/.ssh/config` and define a host which will allow me to connect to Heroku with a particular key.</p>
<p><code># Heroku for #{new_project}<br />
Host heroku-#{new_project}<br />
  HostName heroku.com<br />
  User git<br />
  ForwardAgent yes<br />
  IdentityFile /home/teamcity/.ssh/teamcity_#{new_project}_rsa<br />
</code></p>
<p><strong>Add a ssh key to the Heroku account</strong><br />
Now I need to add this new key to the Heroku account for this project by installing the heroku gem in my project&#8217;s gemset and using the `heroku` command line to add the key. Heroku stores the account credentials used in `~/.heroku` and the user account running my build agents might need to connect to many different heroku accounts. I could switch my heroku credentials, upload a key, and have different projects deploy using different accounts. However since I find it useful to be able to run the heroku command line (see below) I found it preferable to have a single `teamcity` heroku account added to every project as a collaborator.<br />
<em>If you find it necessary to switch between Heroku accounts frequently this tool from Aeonscope might be useful:</em> <a href="http://www.aeonscope.net/2010/02/22/managing-multiple-heroku-accounts/">managing multiple heroku accounts</a></p>
<p>Now I can add a key to the current project&#8217;s Heroku account.<br />
<code>heroku keys:add ~/.ssh/teamcity_#{new_project}_rsa</code></p>
<p><strong>Deploying to Heroku</strong><br />
Now I can add a simple TeamCity build configuration which pushes code to Heroku once a particular revision passes the tests.</p>
<table>
<tbody>
<tr>
<td>Command executable</td>
<td>git</td>
</tr>
<tr>
<td>Command parameters</td>
<td>push git@heroku-#{new_project}:#{new heroku project&#8217;s name}.git master</td>
</tr>
</tbody>
</table>
<p><div id="attachment_1132" class="wp-caption alignnone" style="width: 585px"><a href="http://blog.carbonfive.com/wp-content/uploads/2010/12/tc_heroku_build_runner21.png"><img src="http://blog.carbonfive.com/wp-content/uploads/2010/12/tc_heroku_build_runner21.png" alt="" title="tc_heroku_build_runner" width="575" height="319" class="size-full wp-image-1132" /></a><p class="wp-caption-text">A project's deployment build configuration</p></div><br />
<strong>Deploying and running database migrations</strong><br />
I don&#8217;t want my app trying to respond to requests while waiting for a database migration to finish so now it becomes necessary to put the app in maintenance mode before deploying and migrating.</p>
<table>
<tbody>
<tr>
<td>Command executable</td>
<td>sh</td>
</tr>
<tr>
<td>Command parameters</td>
<td>-c heroku maintenance:on &#8211;app #{new_project} &amp;&amp; sleep 60 &amp;&amp; git push git@heroku.com:#{new_project}.git master &amp;&amp; heroku rake db:migrate &#8211;app #{new_project} &amp;&amp; heroku maintenance:off &#8211;app #{new_project}</td>
</tr>
</tbody>
</table>
<p>I found that I need to add a delay between turning on maintenance mode for the app and pushing to heroku. Attempting to push immediately fails with the error `Heroku push rejected, your slug is currently being compiled. Please try again later.` Even with a significant delay I still see this error occasionally and have to rerun the deploy build but at this point I don&#8217;t know of a way to make sure heroku can handle a new revision before attempting to push changes.</p>
<p>Now I can use TeamCity to automatically deploy changes to Heroku as soon as my project&#8217;s tests pass.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.carbonfive.com/2010/08/06/deploying-to-heroku-from-teamcity/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Using RVM on TeamCity build agents</title>
		<link>http://blog.carbonfive.com/2010/08/05/using-rvm-on-teamcity-build-agents/</link>
		<comments>http://blog.carbonfive.com/2010/08/05/using-rvm-on-teamcity-build-agents/#comments</comments>
		<pubDate>Fri, 06 Aug 2010 04:52:16 +0000</pubDate>
		<dc:creator>Jonah Williams</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[continuous integration]]></category>
		<category><![CDATA[Deployment]]></category>
		<category><![CDATA[rapid development]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[Testing]]></category>

		<guid isPermaLink="false">http://blog.carbonfive.com/?p=1106</guid>
		<description><![CDATA[We have been using TeamCity to manage the continuous integration, testing, and deployment of many of our recent projects. We have also been using RVM on all of our recent Rails projects to allow us to install multiple ruby versions &#8230; <a href="http://blog.carbonfive.com/2010/08/05/using-rvm-on-teamcity-build-agents/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>We have been using <a href="http://www.jetbrains.com/teamcity/">TeamCity</a> to manage the continuous integration, testing, and deployment of many of our recent projects. We have also been using <a href="http://rvm.beginrescueend.com">RVM</a> on all of our recent Rails projects to allow us to install multiple ruby versions and create isolated gemsets for each project. RVM proved to be particularly useful on our TeamCity build agents where it allows a single agent to build many projects without the fear that we will see gem or ruby version conflicts between projects or introduce dependencies on gems installed on the build server but not enumerated in the project. Here&#8217;s the configuration I have used to get our build agents to use each project&#8217;s RVM settings.<br />
<span id="more-1106"></span><br />
As much as I would like to see each project able to configure all of it&#8217;s dependencies on its environment we still have some dependencies which are not captured in the project configuration. For example we have projects which need access to a database servers or need private keys to use when deploying. As a result I have favored running as many build agents as possible as local build agents so that they share this configuration. The configuration below is therefore usually only applied once but in an environment using remote build agents it would need to be repeated or shared between every compatible remote agent&#8217;s system. Perhaps one day we&#8217;ll see each project include chef recipes to configure it&#8217;s own build environment and I would be interested to hear from anyone who has automated their CI configuration to that extent.</p>
<p><strong>1. Create a key for github access</strong><br />
   <code>&gt; ssh-keygen -t rsa -C "#{project_name}"</code><br />
   Upload the public key to github as a deploy key for the project so that the build agent can pull from the github repository.</p>
<p><strong>2. Setup rvm and a gemset for the project</strong><br />
<code>&gt; rvm install ruby-#{version}-r#{patch level}<br />
&gt; rvm use ruby-#{version}-r#{patch level}<br />
&gt; rvm gemset create #{project name}<br />
&gt; rvm gemset use #{project name}<br />
&gt; gem install bundler</code></p>
<p><em>This could probably all be automated as part of the project&#8217;s .rvmrc file.</em></p>
<p><strong>3. Setup a ssh config for the project</strong><br />
The keys used by many of the services we interact with are unique and tied to an account so we need to have TeamCity use different ssh keys when connecting to projects under different accounts. Add a new entry to ~/.ssh/config to alias a host to use a specific ssh key</p>
<p><code># GitHub for #{new_project}<br />
Host github-#{new_project}<br />
    HostName github.com<br />
    User git<br />
    ForwardAgent yes<br />
    IdentityFile /home/teamcity/.ssh/teamcity_#{new_project}_rsa<br />
</code></p>
<p>Connections to `github-#{new_project}` will now default to use `teamcity_#{new_project}_rsa` rather than the default `id_rsa`. By specifying the key in the ssh config file we&#8217;re able to use client side checkouts which will be useful when deploying using git. For projects able to use server side checkouts we can specify a private key to use in TeamCity&#8217;s VCS settings.</p>
<p><strong>4. Create a new TeamCity project</strong><br />
On projects with multiple build steps using the same build runner we could create a template to avoid repeating these settings in each build phase. Unfortunately TeamCity 5.1 templates do not support running multiple types of build runners so projects with both command line (`bundle install`) and rake runners (`rake spec`) require some repetition.</p>
<table>
<thead>
<tr>
<th>Setting the VCS root:</th>
</tr>
</thead>
<tbody>
<tr>
<td>Type of VCS</td>
<td>Git(JetBrains)</td>
</tr>
<tr>
<td>Fetch URL</td>
<td>git@github-#{project name}:#{account name}/#{project name}.git</td>
</tr>
<tr>
<td>Authentication method</td>
<td>default private key</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th>Version Control Settings:</th>
</thead>
<tbody>
<tr>
<td>VCS Checkout Mode</td>
<td>Automatically on client</td>
</tr>
</tbody>
</table>
<p>Client checkouts have a full git repository while a server side checkout performs a git pull and then copies the resulting files but not the full git work-tree to the build agents leaving the agents unable to easily run git commands. A client side checkout is therefore preferable when using `git push` to deploy a project.</p>
<table>
<thead>
<tr>
<th>Command line tasks (bundle install):</th>
</tr>
</thead>
<tbody>
<tr>
<td>Runner</td>
<td>command line</td>
</tr>
<tr>
<td>Executable</td>
<td>/home/teamcity/.rvm/gems/%rvm.ruby%@%rvm.gemset%/bin/bundle</td>
</tr>
<tr>
<td>Arguments</td>
<td>install</td>
</tr>
</tbody>
</table>
<p><a href="http://blog.carbonfive.com/wp-content/uploads/2010/12/tc_rvm_cl_build_runner11.png"><img src="http://blog.carbonfive.com/wp-content/uploads/2010/12/tc_rvm_cl_build_runner11.png" alt="Command line build runner settings" title="tc_rvm_cl_build_runner" width="861" height="393" class="alignnone size-full wp-image-1114" /></a></p>
<table>
<thead>
<tr>
<th>Rake tasks (test):</th>
</tr>
</thead>
<tbody>
<tr>
<td>Runner</td>
<td>rake</td>
</tr>
<tr>
<td>Rake task</td>
<td>%rake.tasks%</td>
</tr>
<tr>
<td>Additional rake command line parameters</td>
<td>%rake.opts%</td>
</tr>
<tr>
<td>Ruby interpreter path</td>
<td>/home/teamcity/.rvm/rubies/%rvm.ruby%/bin/ruby</td>
</tr>
<tr>
<td>RVM Gemset Name</td>
<td>#{project name}</td>
</tr>
</tbody>
</table>
<p><a href="http://blog.carbonfive.com/wp-content/uploads/2010/12/tc_rvm_rake_build_runner21.png"><img src="http://blog.carbonfive.com/wp-content/uploads/2010/12/tc_rvm_rake_build_runner21.png" alt="Rake task build runner settings" title="tc_rvm_rake_build_runner" width="852" height="548" class="alignnone size-full wp-image-1117" /></a></p>
<table>
<thead>
<tr>
<th>Configuration parameters</th>
</tr>
</thead>
<tbody>
<tr>
<td>rvm.ruby</td>
<td>ruby-#{version}-r#{patch level}</td>
</tr>
<tr>
<td>rvm.gemset</td>
<td>#{new_project}</td>
</tr>
</tbody>
</table>
<p><a href="http://blog.carbonfive.com/wp-content/uploads/2010/12/tc_rvm_config_params21.png"><img src="http://blog.carbonfive.com/wp-content/uploads/2010/12/tc_rvm_config_params21.png" alt="Configuration parameters" title="tc_rvm_config_params" width="852" height="220" class="alignnone size-full wp-image-1115" /></a></p>
<p>If using a template set the `rake.tasks`, `rake.opts`, and any other configuration parameters the template uses. Each build configuration based on the template can specify its own configuration parameters but cannot override the rake task and command line parameters directly.</p>
<p>To use the project&#8217;s RVM ruby and gemset add the following environment variables with appropriate paths:</p>
<table>
<tbody>
<tr>
<td>BUNDLE_PATH 	/home/teamcity/.rvm/gems/%rvm.ruby%@%rvm.gemset%</td>
</tr>
<tr>
<td>GEM_HOME 	/home/teamcity/.rvm/gems/%rvm.ruby%@%rvm.gemset%</td>
</tr>
<tr>
<td>GEM_PATH 	/home/teamcity/.rvm/gems/%rvm.ruby%@%rvm.gemset%:/home/teamcity/.rvm/gems/%rvm.ruby%@global</td>
</tr>
<tr>
<td>PATH 	/home/teamcity/.rvm/bin:/home/teamcity/.rvm/rubies/%rvm.ruby%/bin:/home/teamcity/.rvm/gems/%rvm.ruby%@%rvm.gemset%/bin:/home/teamcity/.rvm/gems/%rvm.ruby%@global/bin:%env.PATH%</td>
</tr>
</tbody>
</table>
<p><a href="http://blog.carbonfive.com/wp-content/uploads/2010/12/tc_rvm_environment_variables21.png"><img src="http://blog.carbonfive.com/wp-content/uploads/2010/12/tc_rvm_environment_variables21.png" alt="Environment variables" title="tc_rvm_environment_variables" width="854" height="355" class="alignnone size-full wp-image-1116" /></a></p>
<p>Now I can finally build a set of build configurations for a project which will all use the project&#8217;s RVM settings to isolate it from other projects on the TeamCity server.</p>
<p><a href="http://blog.carbonfive.com/wp-content/uploads/2010/12/tc_example_project21.png"><img src="http://blog.carbonfive.com/wp-content/uploads/2010/12/tc_example_project21.png" alt="An example set of build configurations" title="tc_example_project" width="1207" height="549" class="alignnone size-full wp-image-1122" /></a></p>
<p> JetBrains appears committed to adding RVM support to TeamCity and added the `RVM Gemset` property to rake tasks in TeamCity 5.1.3 so hopefully we&#8217;ll see additional RVM support in future releases.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.carbonfive.com/2010/08/05/using-rvm-on-teamcity-build-agents/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Automatically deploying to Engine Yard Cloud</title>
		<link>http://blog.carbonfive.com/2010/01/07/automatically-deploying-to-engine-yard-cloud/</link>
		<comments>http://blog.carbonfive.com/2010/01/07/automatically-deploying-to-engine-yard-cloud/#comments</comments>
		<pubDate>Thu, 07 Jan 2010 12:04:14 +0000</pubDate>
		<dc:creator>Jonah Williams</dc:creator>
				<category><![CDATA[Process]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[continuous integration]]></category>
		<category><![CDATA[Deployment]]></category>
		<category><![CDATA[Engine Yard Cloud]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[rake]]></category>

		<guid isPermaLink="false">http://blog.carbonfive.com/?p=793</guid>
		<description><![CDATA[I&#8217;m working on a application which is deployed to Engine Yard&#8217;s Cloud infrastructure and I wanted to automatically redeploy the application whenever our tests passed on our continuous integration server. Engine Yard will eventually allow us to push a branch &#8230; <a href="http://blog.carbonfive.com/2010/01/07/automatically-deploying-to-engine-yard-cloud/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m working on a application which is deployed to Engine Yard&#8217;s Cloud infrastructure and I wanted to automatically redeploy the application whenever our tests passed on our continuous integration server.</p>
<p>Engine Yard will eventually allow us to push a branch to our cloud environment from git (ie &#8220;git push engineyard master&#8221;) but until that is available the best option seems to be to trigger a github post receive hook directly.</p>
<p>To that end I rewrote an existing script to trigger post receive hooks as a rake task; <a href="http://gist.github.com/271433">http://gist.github.com/271433</a><br />
<span id="more-793"></span></p>
<pre>
require 'rubygems'<br />
require 'json'<br />
begin<br />
  require 'restclient'<br />
rescue Exception<br />
end</p>
<p>namespace :ey do</p>
<p>  # Based on http://gist.github.com/114954<br />
  # Discussed at https://cloud-support.engineyard.com/discussions/questions/83-deploying-to-solo-instance-from-automated-build<br />
  desc 'Trigger a GitHub Post Receive Hook to deploy the app'<br />
  task :deploy do<br />
    post_receive_hook 'preview'<br />
  end</p>
<p>  desc 'Trigger a GitHub Post Receive Hook to deploy and migrate the app'<br />
  task :deploy_and_migrate do<br />
    post_receive_hook 'preview', true<br />
  end</p>
<p>  def post_receive_hook(envname, migrate=false)<br />
    token = `git config --get cloud.token`.chomp</p>
<p>    if token.empty?<br />
      token = ENV['cloud.token']<br />
      end</p>
<p>    if token.empty?<br />
      puts &lt; [{"id" =&gt; commit, "message"=&gt;"[deploy #{envname}#{migrate ? ' migrate' : ''}]"}],<br />
        "ref" =&gt; "refs/heads/master",<br />
        }</p>
<p>    puts "Triggering a deploy for #{commit} on #{envname}"<br />
    begin<br />
      response = RestClient.post("https://cloud.engineyard.com/github/#{token}",<br />
                                 :payload =&gt; payload.to_json)<br />
      puts "Successfully triggered the deploy"<br />
    rescue RestClient::RequestFailed =&gt; e<br />
      puts "Could not deploy your changes"<br />
      puts e.response.code<br />
      puts e.response.body<br />
      exit 1<br />
    end<br />
  end<br />
end<br />
[/sourcecode]</p>
<p>In setting this up I discovered a couple of potential stumbling points:</p>
<ul>
<li>The environment must have been deployed via the EY dashboard before you will be able to trigger a deploy using the post receive hook API.</li>
<li>The branch specified in the API call (and therefore the git branch you should be working in if running that rake task) must match the branch deployed using the EY dashboard.</li>
<li>If you make an API call to deploy the 'master' branch EY will attempt to deploy branch 'HEAD'.</li>
<li>If the branch specified in the API call does not match the branch specified on the dashboard the API will report success but not redeploy the environment.</li>
</ul>
<p>The folks at Engine Yard are working to correct some of those issues and now I've got a project which automatically pushes changes to the cloud every time our tests cycle.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.carbonfive.com/2010/01/07/automatically-deploying-to-engine-yard-cloud/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Continuous Integration and Build Promotion</title>
		<link>http://blog.carbonfive.com/2009/03/04/continuous-integration-and-build-promotion/</link>
		<comments>http://blog.carbonfive.com/2009/03/04/continuous-integration-and-build-promotion/#comments</comments>
		<pubDate>Wed, 04 Mar 2009 17:24:33 +0000</pubDate>
		<dc:creator>Christian Nelson</dc:creator>
				<category><![CDATA[Process]]></category>
		<category><![CDATA[continuous integration]]></category>

		<guid isPermaLink="false">http://blog.carbonfive.com/?p=340</guid>
		<description><![CDATA[We have a build server and we practice continuous integration on all of our projects. In fact, it&#8217;s pretty much the first thing we set up after version control. We&#8217;re feedback junkies. It became especially apparent while working on a &#8230; <a href="http://blog.carbonfive.com/2009/03/04/continuous-integration-and-build-promotion/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>We have a build server and we practice continuous integration on all of our projects.  In fact, it&#8217;s pretty much the first thing we set up after version control.  We&#8217;re feedback junkies.  It became especially apparent while working on a client project last year where we used their development infrastructure.  They had a build server running, but the problem was that it took too long to get feedback.  I was lost and jonesing.  They had a monolithic build that took about 45 minutes to run its course and give me the affirmation I was seeking.</p>
<p>While setting up my current project, I decided to take a different approach when configuring our build server and continuous integration.  I had a few goals in mind:</p>
<ul>
<li>Super fast feedback</li>
<li>&#8220;Promoted&#8221; builds get pushed to the acceptance server</li>
<li>Minimize issues with the build infrastructure</li>
</ul>
<p>I split our build into three plans:</p>
<p><a href="http://blog.carbonfive.com/wp-content/uploads/2010/12/build21.png"><img src="http://blog.carbonfive.com/wp-content/uploads/2010/12/build21.png" alt="" title="Build Progression" width="613" height="217" class="aligncenter size-medium wp-image-396" /></a></p>
<h3>Continuous Integration Build Plan</h3>
<p>This resets the unit test database (using <a href="http://code.google.com/p/c5-db-migration/">c5-db-migrations</a>), compiles the project, runs all of the unit tests, and if there are no errors or failures, produces a war.  The war is installed locally using Maven so that it&#8217;s accessible to other processes in a known location.  This build is very fast and is triggered on every subversion commit.  The command used for this build plan is:</p>
<p>mvn db-migration:reset clean install</p>
<h3>Functional Tests Build Plan</h3>
<p>This resets the functional test database, deploys the war built during the continuous integration build to tomcat using <a href="http://cargo.codehaus.org/">Cargo</a>, runs all of the functional tests, and shuts down tomcat.  This build is triggered on every successful continuous integration build (i.e. as a dependent build).  A very short script performs the work of this build:</p>
<p>mvn -Pdev db-migration:reset<br />
cd functional-tests; mvn -Pdev clean test-compile cargo:start surefire:test cargo:stop</p>
<p>And here&#8217;s the cargo-maven-plugin configuration:</p>
<pre class="brush: xml; light: true; title: ; wrap-lines: false; notranslate">
&amp;lt;plugins&amp;gt;
...
    &amp;lt;plugin&amp;gt;
        &amp;lt;groupId&amp;gt;org.codehaus.cargo&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;cargo-maven2-plugin&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;1.0-beta-2&amp;lt;/version&amp;gt;
        &amp;lt;configuration&amp;gt;
            &amp;lt;wait&amp;gt;false&amp;lt;/wait&amp;gt;
            &amp;lt;configuration&amp;gt;
                &amp;lt;deployables&amp;gt;
                    &amp;lt;deployable&amp;gt;
                        &amp;lt;groupId&amp;gt;com.acme&amp;lt;/groupId&amp;gt;
                        &amp;lt;artifactId&amp;gt;acme-web&amp;lt;/artifactId&amp;gt;
                        &amp;lt;type&amp;gt;war&amp;lt;/type&amp;gt;
                        &amp;lt;properties&amp;gt;
                            &amp;lt;context&amp;gt;acme-web&amp;lt;/context&amp;gt;
                        &amp;lt;/properties&amp;gt;
                    &amp;lt;/deployable&amp;gt;
                &amp;lt;/deployables&amp;gt;
            &amp;lt;/configuration&amp;gt;
            &amp;lt;container&amp;gt;
                &amp;lt;containerId&amp;gt;tomcat6x&amp;lt;/containerId&amp;gt;
                &amp;lt;zipUrlInstaller&amp;gt;
                    &amp;lt;url&amp;gt;http://www.apache.org/dist/tomcat/tomcat-6/v6.0.18/bin/apache-tomcat-6.0.18.zip&amp;lt;/url&amp;gt;
                &amp;lt;/zipUrlInstaller&amp;gt;
            &amp;lt;/container&amp;gt;
        &amp;lt;/configuration&amp;gt;
    &amp;lt;/plugin&amp;gt;
&amp;lt;/plugins&amp;gt;
</pre>
<h3>Deploy to Acceptance Build Plan</h3>
<p>This step doesn&#8217;t build anything or run any tests, but is a little more complicated than the others because it&#8217;s interacting with a another machine: our dedicated project acceptance server.  We scp the war (built during the continuous integration phase) to our acceptance server.  Next, we shutdown tomcat and clean a few things up (logs, old webapp, and work).  Then we migrate the database (no reset because we care about the data).  Last, we bring tomcat back up with the new war.  This build is triggered on every successful functional test build.  Here&#8217;s the script that&#8217;s run by the build server:</p>
<pre class="brush: bash; light: true; title: ; wrap-lines: false; notranslate">
ARTIFACT_NAME=./ROOT.war

# SCP Application and Scripts
WAR=`find ~/.m2/repository/com/acme/acme-web -name &amp;quot;*-*.war&amp;quot; | sort | tail -1`
echo &amp;quot;Copying $WAR to acceptance server.&amp;quot;
scp $WAR acme@acme-acceptance:$ARTIFACT_NAME
scp ./bin/*_as.sh acme@acme-acceptance:.

# Shutdown and Clean Tomcat
ssh acme@acme-acceptance sh ./shutdown_as.sh

# DB Migration
mvn -Pdev db-migration:migrate -Djdbc.host=acme-acceptance

# Install Application
ssh acme@acme-acceptance mv $ARTIFACT_NAME ./apache-tomcat/webapps/

# Startup
ssh acme@acme-acceptance sh ./startup_as.sh
</pre>
<h3>Conclusion</h3>
<p>This has worked out really well for the project and we get feedback very quickly.</p>
<p>You may wonder why we broke functional tests into their own plan.  I find that functional tests can be a little less stable than unit tests (especially if selenium is involved), and they run much more slowly.  I&#8217;ve seen cases where flaky functional tests caused a team to start ignoring build results because it was usually a problem with the infrastructure, not with the code.  So, the decision was somewhat defensive and in retrospect, probably unnecessary.</p>
<p>We&#8217;ve spent less time maintaining our build plans than in the past as well.  At some point, our build server MySQL instance crapped out and even though all of the databases were deleted, our builds all ran successfully when the build server came back up because they start with a database reset, which creates the target database and migrates it to the latest schema.</p>
<p>A single war is promoted as it passes a greater level of testing, and is eventually deployed to the acceptance server if all of the tests pass.  While we&#8217;re saving a little time by not rebuilding the archive for each plan, that&#8217;s not the only thing I like about it.  It just feels a little more right and it completely eliminates the chance that something about the artifact changes as it makes its way through the pipelines.  The same war can make its way from the first CI build all the way to production.  This is possible because we include default configuration for the application which matches our development environments, and then provide <a href="http://blog.carbonfive.com/wp-content/uploads/2010/12/build21.png2008/04/java/configuring-applications-with-spring">a mechanism for externalizing application configuration</a> for the one-off environments.</p>
<p>I think most modern build server software provides everything you need to do something like this as it&#8217;s rather straight forward.  However, for those who are curious, we have been using <a href="http://www.atlassian.com/software/bamboo/">Bamboo</a> for the last year or two and recently installed <a href="http://www.jetbrains.com/teamcity/">TeamCity</a> so that we can give it a proper try.  Both are great products, and if you&#8217;re on a smallish team, TeamCity is completely free (and is superior to the open source alternatives, IMHO).</p>
<p>How are you using your build server?</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.carbonfive.com/2009/03/04/continuous-integration-and-build-promotion/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

