NSBoganNSBogan - Maksym Grebenets
https://mgrebenets.github.io
https://mgrebenets.github.io
2019-08-11T07:26:16+00:002019-08-11T07:26:16+00:001800TeamCity Kotlin REST Client
<p>Whichever CI server you use for development, being able to access it programmatically via REST API is an essential capability for implementing all kinds of automation. In this article you will learn how to utilize <a href="https://www.jetbrains.com/teamcity/">TeamCity</a> REST API using <a href="https://github.com/JetBrains/teamcity-rest-client">TeamCity Kotlin REST Client</a>.</p>
<!--more-->
<p>Let’s start by setting up some goals.</p>
<blockquote>
<p>I want to be able to access my TeamCity server using Kotlin programming language.</p>
</blockquote>
<p>The goal is set and to help me with the task JetBrains provides a <a href="https://github.com/JetBrains/teamcity-rest-client">REST client</a> which I’ve mentioned earlier. So all I have to do is write a simple Kotlin script that uses REST client and implement whichever automation I want, right? Well, except that I’m not a Java or Android developer and building Kotlin source code is totally new to me, so this article will cover some basics.</p>
<h2 id="️-setup">⚙️ Setup</h2>
<p>I’m working on a Mac OS X machine, so I’ll start by getting <a href="https://gradle.org/">Gradle Build Tool</a> installed.</p>
<script src="https://gist.github.com/afc3423f7ac576c0db4a4734910eab73.js"> </script>
<p>Next, I’ll create a new directory for my project as well as the main Kotlin file and a Gradle wrapper.</p>
<script src="https://gist.github.com/3d886e057f6d44e42cc87f7b4005eaf9.js"> </script>
<p>From now on I should be running all Gradle commands using the wrapper, e.g. <code class="highlighter-rouge">./gradlew build</code>. Wrapper will be saved in <code class="highlighter-rouge">gradle/wrapper</code> folder. This folder can be committed to source control which removes the dependency on global Gradle installation and makes the project self-contained.</p>
<p>I want to use Kotlin to write build scripts, so I create <code class="highlighter-rouge">build.gradle.kts</code> file in the project root with the following contents:</p>
<script src="https://gist.github.com/4048ef3bf2748c9cd884d1a807444424.js"> </script>
<p>This is to make sure I’m using exact version of Gradle and it doesn’t autoupdate.</p>
<h2 id="-implement">🔨 Implement</h2>
<p>This may sound unusual, but in this case I choose to write the Kotlin code first and then make it compile and run. Based on the example on REST client project page, I came up with the following:</p>
<script src="https://gist.github.com/974b030ecde04a1a78305d85c1f14bf3.js"> </script>
<p>In a nutshell this code connects to TeamCity using username and password provided as input arguments, then fetches latest build information for a specified build configuration and prints it out to console. Check inline comments for more details.</p>
<h2 id="️-build">👷♂️ Build</h2>
<p>After a lot of trial an error I came up with the the following build file:</p>
<script src="https://gist.github.com/a0669ddc663c66a9263d0d88efebeb9f.js"> </script>
<p>Check the inline comments for detailed information.
This build script builds Kotlin application targeted for running on top of <a href="https://en.wikipedia.org/wiki/Java_virtual_machine">JVM</a>. The application depends on TeamCity REST client.</p>
<p>Note that you have to install Java version 1.8 to build and run the application.</p>
<p>It’s time to build it:</p>
<script src="https://gist.github.com/1eb88bf6694b5401b073e72ebfcf4ced.js"> </script>
<h2 id="️-run">🏃♀️ Run</h2>
<p>I can now run the Kotlin application:</p>
<script src="https://gist.github.com/c6c8d2495b1bfd2905e2c87d1657358f.js"> </script>
<p>After customizing input arguments I am able to see something like this in the logs:</p>
<script src="https://gist.github.com/a12160cf3d21bd9936e9fb5c066d1b52.js"> </script>
<p>That’s just the beginning!
I can now use nice modern programming language to automate various CI/CD tasks on TeamCity.</p>
<p>For a full example project see <a href="https://github.com/mgrebenets/teamcity-rest-client-example">this repository</a>.</p>
https://mgrebenets.github.io/mobile%20ci/2019/06/24/kotlin-teamcity-rest-client
https://mgrebenets.github.io/mobile%20ci/2019/06/24/kotlin-teamcity-rest-client2019-06-24T00:00:00+00:00Xcode Build Settings in Depth
<p>Getting to the rock bottom of Xcode build settings.</p>
<!--more-->
<p>If you have ever done any Mac OS or iOS development, you eventually had to deal with Xcode build settings.</p>
<p><img src="https://mgrebenets.github.io/assets/images/build-settings/i-used-build-settings.png" alt="Build Settings" /></p>
<p>So what are those are what do we know about them?</p>
<p>For a standard iOS project there’s roughly 500 build settings grouped into around 50 categories. These build settings control virtually every single aspect of how you app is built and packaged. At the very least, build settings is what makes Debug build so different from Release build.</p>
<p>In this article I’ll mostly focus on build settings that control the behavior of Apple Clang and Swift compilers and the linker.</p>
<h2 id="-background-check">🗄 Background Check</h2>
<p>Build settings are not as simple as they may seem.</p>
<p>For starters, there are project and target level build settings as well as default OS settings.
The default OS build settings are inherited on a project level and project level build settings are inherited on a target level.</p>
<p>Then there are <code class="highlighter-rouge">.xcconfig</code> files, which can be used to represent build settings in plain text format.
The xcconfigs can be set on target and project level and add two more levels to inheritance flow.</p>
<p><img src="https://mgrebenets.github.io/assets/images/build-settings/xcconfigs-inheritance.png" alt="Inheritance" /></p>
<p>To make things even more complicated, you can include other xcconfigs using C-like <code class="highlighter-rouge">#include</code> statements.</p>
<script src="https://gist.github.com/b56aa994dd67699f040003674d3a4b24.js"> </script>
<p>And then there’s much more to build settings and xcconfigs.</p>
<p>To get familiar with all of the above, I’d highly recommend to start with <a href="https://pewpewthespells.com/blog/xcconfig_guide.html">The Unofficial Guide to xcconfig files</a>. Check out the rest of <a href="https://pewpewthespells.com/ramble.html">this amazing blog</a> for even more hands-on information about understanding and managing build settings.</p>
<h2 id="️-level-down">⬇️ Level Down</h2>
<p>Now let’s get one more level down. When it comes to compiling and linking the source code, Xcode build system manages 3 main tools under the hood:</p>
<ul>
<li>Clang Cxx compiler for compiling C/C++ and Objective-C/C++ code</li>
<li>Swift compiler</li>
<li>Linker to link all object files together</li>
</ul>
<p><img src="https://mgrebenets.github.io/assets/images/build-settings/xcode-tools.png" alt="Xcode Tools" /></p>
<p>Each of those tools has its own set of command line flags.
Clang compiler and linker flags are documented <a href="https://clang.llvm.org/docs/ClangCommandLineReference.html">here</a>.
<code class="highlighter-rouge">swiftc --help</code> command provides list of Swift command line flags. Surprisingly, I failed to find online documentation similar to Clang.</p>
<p>When a build setting is set in Xcode UI, Xcode then translates it to appropriate flags for underlying tools.
For example, setting <code class="highlighter-rouge">GCC_TREAT_WARNINGS_AS_ERRORS</code> to <code class="highlighter-rouge">YES</code> will add <code class="highlighter-rouge">-Werror</code> flag for Clang Cxx compiler.</p>
<p><img src="https://mgrebenets.github.io/assets/images/build-settings/gcc-treat-warnings-as-errors.png" alt="Cxx Treat Warnings as Errors" /></p>
<p>Similarly, setting <code class="highlighter-rouge">SWIFT_TREAT_WARNINGS_AS_ERRORS</code> to <code class="highlighter-rouge">YES</code> will add <code class="highlighter-rouge">-warnings-as-errors</code> flag to all invocations of Swift compiler.</p>
<p><img src="https://mgrebenets.github.io/assets/images/build-settings/swift-treat-warnings-as-errors.png" alt="Swift Treat Warnings as Errors" /></p>
<p>Finally, some build settings are translated into flags for all three tools, for example, enabling code coverage using <code class="highlighter-rouge">CLANG_ENABLE_CODE_COVERAGE = YES</code> build setting, will translate into the following<sup>*</sup>:</p>
<ul>
<li><code class="highlighter-rouge">-fprofile-instr-generate</code> and <code class="highlighter-rouge">-fcoverage-mapping</code> for Clang compiler</li>
<li><code class="highlighter-rouge">-profile-coverage-mapping</code> and <code class="highlighter-rouge">-profile-generate</code> for Swift compiler</li>
<li><code class="highlighter-rouge">-fprofile-instr-generate</code> for linker</li>
</ul>
<p><img src="https://mgrebenets.github.io/assets/images/build-settings/xcode-coverage-flags.png" alt="Code Coverage Flags" /></p>
<hr />
<p><sup>*</sup> Technically, it takes more than just setting <code class="highlighter-rouge">CLANG_ENABLE_CODE_COVERAGE</code> to enable code coverage, more details to come.</p>
<hr />
<p>So, how does Xcode know which flags to map build settings to?
Where is this mapping information stored and can it be extracted?</p>
<h2 id="️-xcode-specs">⚙️ Xcode Specs</h2>
<p>The answer to the question in previous section is Xcode Specs or <em>xcspecs</em>.</p>
<p>Xcspecs are ASCII plist files with <code class="highlighter-rouge">.xcspec</code> file extension stored deep inside Xcode.app bundle.
Xcode uses these specs to render build settings UI and to translate build settings to command line flags.</p>
<p>There are xcspecs for Clang compiler (<code class="highlighter-rouge">Clang LLVM 1.0.xcspec</code>), Swift compiler (<code class="highlighter-rouge">Swift.xcspec</code>) and linker (<code class="highlighter-rouge">Ld.xcspec</code>) as well as a number of xcspecs for core build system and other tools.
These xcspecs reference each other and work together as a system.</p>
<p>Each xcspec contains specification for one or more <em>tools</em>, for example, Swift xcspec contains specification for Swift compiler tool, while Clang LLVM xcspec contais specifications for Clang compiler, analyzer, couple of migrators and an <a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree">AST</a> builder tool.</p>
<p>A tool specification includes such details as name, description, identifier, executable path, supported file types and more.</p>
<script src="https://gist.github.com/a5eebad8258096401743edce9f594488.js"> </script>
<h3 id="-options">🔘 Options</h3>
<p>In context of this article we are most interested in <code class="highlighter-rouge">Options</code> array entry of the tool’s specification, which is where information about build settings is stored.
For example, the value of <code class="highlighter-rouge">SWIFT_EXEC</code> is stored as an option and is used by Xcode to resolve <code class="highlighter-rouge">ExecPath = "$(SWIFT_EXEC)";</code> statement:</p>
<script src="https://gist.github.com/03a91b4093bc4fb35e49b7e0c5eb32b7.js"> </script>
<p>All build settings (options) have <code class="highlighter-rouge">Name</code> and <code class="highlighter-rouge">Type</code> properties.
<code class="highlighter-rouge">Name</code> defines the build setting name, e.g. <code class="highlighter-rouge">SWIFT_OPTIMIZATION_LEVEL</code>.</p>
<p>Build settings may also have a <code class="highlighter-rouge">Category</code>, <code class="highlighter-rouge">Description</code> and <code class="highlighter-rouge">DisplayName</code> properties. For example, display name for <code class="highlighter-rouge">SWIFT_OPTIMIZATION_LEVEL</code> is <code class="highlighter-rouge">Optimization Level</code>.</p>
<p>A few build settings are hidden and never appear in Xcode UI. Some of them have corresponding comment in the code like <code class="highlighter-rouge">// Hidden.</code>, but not all.</p>
<h4 id="types">Types</h4>
<p>There are 6 different types of build settings:</p>
<ul>
<li><code class="highlighter-rouge">String</code></li>
<li><code class="highlighter-rouge">StringList</code></li>
<li><code class="highlighter-rouge">Path</code></li>
<li><code class="highlighter-rouge">PathList</code></li>
<li><code class="highlighter-rouge">Enumeration</code></li>
<li><code class="highlighter-rouge">Boolean</code></li>
</ul>
<h5 id="ℹ️-string-and-path">ℹ️ String and Path</h5>
<p>A build setting of <code class="highlighter-rouge">String</code> type has, well, a string value.</p>
<p>Note that string value doesn’t have to be quoted using double quotes.
As a matter of fact, some build setting that have integer values are represented using <code class="highlighter-rouge">String</code> type with default value set to <code class="highlighter-rouge">0</code>, but not to <code class="highlighter-rouge">"0"</code>.</p>
<p><code class="highlighter-rouge">Path</code> type is identical to <code class="highlighter-rouge">String</code> when used in xcspecs.</p>
<p>My guess is that <code class="highlighter-rouge">Path</code> type build settings are handled differently with regards to escaping whitespaces and other special characters.
They also get special treatment when resolving wildcard characters like <code class="highlighter-rouge">*</code></p>
<h5 id="ℹ️-stringlist-and-pathlist">ℹ️ StringList and PathList</h5>
<p><code class="highlighter-rouge">StringList</code> and <code class="highlighter-rouge">PathList</code> are used to represent list of string and path values correspondingly.</p>
<p>If not provided, default value is an empty list.</p>
<p>You can tell a list type in Xcode UI because it allows multiple values input:</p>
<p><img src="https://mgrebenets.github.io/assets/images/build-settings/list-type.png" alt="List" /></p>
<h5 id="ℹ️-enumeration">ℹ️ Enumeration</h5>
<p>Values of <code class="highlighter-rouge">Enumeration</code> type have a fixed list of values (cases), defined using <code class="highlighter-rouge">Values</code> key, for example:</p>
<script src="https://gist.github.com/5c4b859776ed778201a8f6fafc8e8acf.js"> </script>
<p>Another good example is build settings that have <code class="highlighter-rouge">YES_AGGRESSIVE</code> or <code class="highlighter-rouge">YES_ERROR</code> value on top of <code class="highlighter-rouge">YES</code> and <code class="highlighter-rouge">NO</code>. These build settings are declared as enumerations too:</p>
<script src="https://gist.github.com/56700040c6ceb970de8278d5ed79c655.js"> </script>
<p><img src="https://mgrebenets.github.io/assets/images/build-settings/yes-no-yes-error.png" alt="Enumeration" /></p>
<h5 id="ℹ️-boolean">ℹ️ Boolean</h5>
<p>Finally, values of <code class="highlighter-rouge">Boolean</code> type have either <code class="highlighter-rouge">YES</code> or <code class="highlighter-rouge">NO</code> value.</p>
<p>Note that only <code class="highlighter-rouge">YES</code> and <code class="highlighter-rouge">NO</code> are correct values for <code class="highlighter-rouge">Boolean</code> type, but not <code class="highlighter-rouge">"YES"</code> or <code class="highlighter-rouge">"NO"</code>.</p>
<p><img src="https://mgrebenets.github.io/assets/images/build-settings/boolean.png" alt="Boolean" /></p>
<h4 id="-command-line-flags-mapping">🗺 Command Line Flags Mapping</h4>
<p>As we already know, a lot of build setting values map to different command line flags.
The mapping information is defined in xcspecs using one of the following keys:</p>
<ul>
<li><code class="highlighter-rouge">CommandLineArgs</code></li>
<li><code class="highlighter-rouge">CommandLineFlag</code></li>
<li><code class="highlighter-rouge">CommandLinePrefixFlag</code></li>
<li><code class="highlighter-rouge">AdditionalLinkerArgs</code></li>
</ul>
<h5 id="ℹ️-command-line-arguments">ℹ️ Command Line Arguments</h5>
<p><code class="highlighter-rouge">CommandLineArgs</code> key-value entry is used to map build setting value to a <em>list</em> of command line arguments.</p>
<h6 id="scalar-types">Scalar Types</h6>
<p>A good example is <code class="highlighter-rouge">SWIFT_MODULE_NAME</code> build setting of <code class="highlighter-rouge">String</code> type:</p>
<script src="https://gist.github.com/56b78db453027d4c11f53f3f01a8d616.js"> </script>
<p>The <code class="highlighter-rouge">$(value)</code> is resolved to current build setting value, e.g. <code class="highlighter-rouge">MyModule</code> value is mapped to <code class="highlighter-rouge">-module-name "MyModule"</code> Swift compiler flag.</p>
<h6 id="list-types">List Types</h6>
<p>For list types each build setting value in the list is mapped to one or more command line flags, for example:</p>
<script src="https://gist.github.com/da35fa8bd00e6a5f0febb7814492855d.js"> </script>
<p>If the value of <code class="highlighter-rouge">CLANG_ANALYZER_OTHER_CHECKERS</code> is <code class="highlighter-rouge">"checker1" "checker2"</code>, it will be mapped to the following:</p>
<script src="https://gist.github.com/c0f40ed7c7d8e00bc41f5473f83dcbdc.js"> </script>
<h6 id="enumeration-type">Enumeration Type</h6>
<p>For enumerations types, mapping is defined for each enumeration case, for example:</p>
<script src="https://gist.github.com/d2225ee9a4f99ef9d81b8a914df2af23.js"> </script>
<ul>
<li><code class="highlighter-rouge">ansi</code> value is mapped to <code class="highlighter-rouge">-ansi</code> compiler flag.</li>
<li><code class="highlighter-rouge">compiler-default</code> maps to no flags.</li>
<li>All other enumeration values map to <code class="highlighter-rouge">-std=$(value)</code> compiler flag. Note the use of <code class="highlighter-rouge">"<<otherwise>>"</code>, this is similar to <code class="highlighter-rouge">default:</code> enum switch in C-like languages.</li>
</ul>
<h6 id="boolean-type">Boolean Type</h6>
<p>Boolean types are mapped just like enumerations with 2 <code class="highlighter-rouge">YES</code> and <code class="highlighter-rouge">NO</code> cases.</p>
<h5 id="ℹ️-command-line-flag">ℹ️ Command Line Flag</h5>
<p><code class="highlighter-rouge">CommandLineFlag</code> is used to prepend command line flag to the value of build setting.</p>
<p>For example, <code class="highlighter-rouge">SDKROOT</code> is defined like so:</p>
<script src="https://gist.github.com/efcc09c99a3eb4aa6b7a11e4c9120c63.js"> </script>
<p>So if the value of <code class="highlighter-rouge">SDKROOT</code> is <code class="highlighter-rouge">iphoneos</code>, the corresponding Clang compiler flag will be <code class="highlighter-rouge">-isysroot iphoneos</code>.</p>
<p>In a way <code class="highlighter-rouge">CommandLineFlag</code> is a shorthand for using <code class="highlighter-rouge">CommandLineArgs</code>. I.e. in <code class="highlighter-rouge">SDKROOT</code> example, <code class="highlighter-rouge">CommandLineFlag = "-isysroot";</code> could be replaced with <code class="highlighter-rouge">CommandLineArgs = ("-isysroot", "$(value)");</code>.</p>
<p>Handling of list, enumeration and Boolean types is similar to handling <code class="highlighter-rouge">CommandLineArgs</code> too.
For example, given the definition:</p>
<script src="https://gist.github.com/96617fd879004489cf5309c5a635cca8.js"> </script>
<p>The value like <code class="highlighter-rouge">SYSTEM_FRAMEWORK_SEARCH_PATHS = "A" "B" "C"</code> will be mapped to:</p>
<script src="https://gist.github.com/d9e1118c1489ec8106e3316326336e50.js"> </script>
<p>Enumerations deserve a special mention, because build flag mapping can be defined next to the value. A good example is <code class="highlighter-rouge">MACH_O_TYPE</code>:</p>
<script src="https://gist.github.com/8e1ed48ff817831fe42e36cd251a582e.js"> </script>
<h5 id="ℹ️-command-line-prefix-flag">ℹ️ Command Line Prefix Flag</h5>
<p><code class="highlighter-rouge">CommandLinePrefixFlag</code> maps build setting value to itself <em>prefixed</em> with a build flag.</p>
<p>It works just like <code class="highlighter-rouge">CommandLineFlag</code>, the only difference is that there’s no space between the build flag and the build settings value.</p>
<p>A good examples are <code class="highlighter-rouge">LIBRARY_SEARCH_PATHS</code> and <code class="highlighter-rouge">FRAMEWORK_SEARCH_PATHS</code> build settings of list type, where each list entry is mapped to <code class="highlighter-rouge">-L"$(value)"</code> or <code class="highlighter-rouge">-F"$(value)"</code> correspondingly.</p>
<script src="https://gist.github.com/4af7bc52338e4d894c14c304eb50c9e4.js"> </script>
<p>Another similar build setting often used by developers is <code class="highlighter-rouge">OTHER_LDFLAGS</code>.</p>
<p>Finally, whenever you see a flag like <code class="highlighter-rouge">-fmessage-length=0</code> it’s most likely mapped using prefix flag rule.</p>
<script src="https://gist.github.com/828f232353ebd21e7a74df84e8d5df30.js"> </script>
<h5 id="ℹ️-additional-linker-flags">ℹ️ Additional Linker Flags</h5>
<p>Certain Swift or Clang compiler build settings map not only to compiler flags, but to linker flags as well.
Those build settings have an additional <code class="highlighter-rouge">AdditionalLinkerArgs</code> key-value pair, for example:</p>
<script src="https://gist.github.com/82d846f5c45a591ceaef38d80b59cf76.js"> </script>
<p>In this example, the <code class="highlighter-rouge">-fobjc-arc</code> flag will be added both to Clang compiler and linker invocations.</p>
<p>The way mapping works for different build setting types is identical to handling of <code class="highlighter-rouge">CommandLineArgs</code>.</p>
<h4 id="references">References</h4>
<p>As I’ve mentioned earlier, build settings from different xcspecs can reference each other.</p>
<p>Some build settings have a <code class="highlighter-rouge">DefaultValue</code> property.
It can reference other build settings, e.g. <code class="highlighter-rouge">DefaultValue = "$(BITCODE_GENERATION_MODE)";</code>.
Default value of some build settings is defined by referencing other build setting:</p>
<script src="https://gist.github.com/67911f2e9771db903f22264aad0588a7.js"> </script>
<p><img src="https://mgrebenets.github.io/assets/images/build-settings/swift-module-name.png" alt="Default Value Reference" /></p>
<p>The references can be nested as well, for example:</p>
<script src="https://gist.github.com/c0cc9d693b7c08cd61ae0ab2616ab3c2.js"> </script>
<p>Here <code class="highlighter-rouge">$(DEPLOYMENT_TARGET_SETTING_NAME)</code> will be first resolved into a value like <code class="highlighter-rouge">SOME_SETTING</code> and then <code class="highlighter-rouge">$(SOME_SETTING)</code> is resolved once again to a final value. Similar to how build settings are resolved in xcconfigs.</p>
<p>Build settings reference can be used inside <code class="highlighter-rouge">CommandLineArgs</code> and all other mapping key-value entries.</p>
<h4 id="conditions">Conditions</h4>
<p>Conditions are defined using <code class="highlighter-rouge">Condition</code> key-value pair and are used to control when certain build setting is enabled or not.</p>
<p>For example, <code class="highlighter-rouge">SWIFT_BITCODE_GENERATION_MODE</code> build setting only makes sense when <code class="highlighter-rouge">ENABLE_BITCODE</code> is set to <code class="highlighter-rouge">YES</code>:</p>
<script src="https://gist.github.com/90f7e1d17d4802557ae9cf0b0d229eb8.js"> </script>
<p>Conditions have a C-like syntax, although string values do not have to be quoted. Such boolean operators as <code class="highlighter-rouge">!</code>, <code class="highlighter-rouge">&&</code>, <code class="highlighter-rouge">||</code>, <code class="highlighter-rouge">==</code> and <code class="highlighter-rouge">!=</code> can be used:</p>
<script src="https://gist.github.com/60a9ad0440a2eb705e90590b13dbc235.js"> </script>
<h4 id="other-properties">Other Properties</h4>
<p>There are other properties, such as</p>
<ul>
<li><code class="highlighter-rouge">Architectures</code> - defines which target architectures the build setting is applicable for.</li>
<li><code class="highlighter-rouge">AppearsAfter</code> - controls the order in which 2 specific build settings appear in Xcode UI.</li>
<li><code class="highlighter-rouge">FileTypes</code> - list of applicable file types.</li>
<li><code class="highlighter-rouge">ConditionFlavors</code> - must have something to do with the way conditions are checked.</li>
<li>Some other flags I didn’t have time to fully investigate yet.</li>
</ul>
<h2 id="-example">👩🏫 Example</h2>
<p>Let’s have a look at one build setting example and see how we can apply all the knowledge from this article to figure out which flags it will map to.</p>
<p>The build setting is <code class="highlighter-rouge">CLANG_ENABLE_CODE_COVERAGE</code> and it enables one very important feature - code coverage.</p>
<p><code class="highlighter-rouge">CLANG_ENABLE_CODE_COVERAGE</code> is defined in <code class="highlighter-rouge">Clang LLVM 1.0.xcspec</code> but strangely maps to no flags at all…</p>
<script src="https://gist.github.com/a49b86699e6e27d31e2a77331adfd1e1.js"> </script>
<p>However, <code class="highlighter-rouge">CLANG_ENABLE_CODE_COVERAGE</code> is referenced by <code class="highlighter-rouge">CLANG_COVERAGE_MAPPING</code>.</p>
<script src="https://gist.github.com/46abc931ad16ccbdcdb9956edcb29a9f.js"> </script>
<p>So now we know the Clang compiler flags added to compiler invocation when code coverage is enabled.</p>
<p>Additionally, there’s another build setting that controls the linker flag:</p>
<script src="https://gist.github.com/0cd24fccb0bdb8a2208d7672759f2c35.js"> </script>
<p>It also comes with a very detailed comment.</p>
<p>Finally, <code class="highlighter-rouge">CLANG_COVERAGE_MAPPING</code> is also defined in <code class="highlighter-rouge">Swift.xcspec</code>:</p>
<script src="https://gist.github.com/522294a2e07fbcda045deaa07da8c9a4.js"> </script>
<p>Now all the pieces of the puzzle come together and it’s clear how Xcode does the mapping.</p>
<p><img src="https://mgrebenets.github.io/assets/images/build-settings/xcode-coverage-flags.png" alt="Code Coverage Flags" /></p>
<p>The only problem is that both <code class="highlighter-rouge">CLANG_COVERAGE_MAPPING</code> and <code class="highlighter-rouge">CLANG_COVERAGE_MAPPING_LINKER_ARGS</code> are hidden and don’t show up in Xcode UI. So how do those get set if they don’t reference <code class="highlighter-rouge">CLANG_ENABLE_CODE_COVERAGE</code> in their default value?</p>
<p>The code coverage can be enabled by editing the scheme in Xcode UI or by passing <code class="highlighter-rouge">-enableCodeCoverage YES</code> to <code class="highlighter-rouge">xcodebuild</code> invocation</p>
<p><img src="https://mgrebenets.github.io/assets/images/build-settings/enable-coverage.png" alt="Default Value Reference" /></p>
<script src="https://gist.github.com/753c5ea0ca550b857f3376bcef67ed96.js"> </script>
<p>Xcode will then set both <code class="highlighter-rouge">CLANG_COVERAGE_MAPPING</code> and <code class="highlighter-rouge">CLANG_COVERAGE_MAPPING_LINKER_ARGS</code> to <code class="highlighter-rouge">YES</code> under the hood.</p>
<h2 id="-application">👷 Application</h2>
<p>OK then, so it’s more or less clear how build settings are resolved, but what’s the practical application?</p>
<p>Well, there’s the purely academic application where you get to know how things work, which occasionally will come handy when you have hard time figuring out some build settings mess.</p>
<p>While the official <a href="https://help.apple.com/xcode/mac/10.2/#/itcaec37c2a6">Xcode Build Settings</a> reference page is a good resource to use, the <a href="https://github.com/mgrebenets/fastlane-plugin-xcconfig_actions/blob/master/lib/fastlane/plugin/xcconfig_actions/helper/xcspecs/10.2/README.md">Extended Xcode Build Settings reference like this one</a> includes information about compiler and linker flags, build settings cross-reference and more.</p>
<p>There are other ways to use this knowledge.</p>
<p>Let’s say you want to try out alternative build system like <a href="https://buckbuild.com">Buck</a> or <a href="https://bazel.build/">Bazel</a>. Those build systems are gaining popularity these days. Buck was created by Facebook while Bazel came from Google. Other companies such as Uber, Airbnb and Dropbox use Buck; while Lyft is using Bazel to build their mobile apps.</p>
<p>Let’s further assume that over the years you have created and maintained a number of amazing xcconfig files. Those xcconfigs have all the compiler and linker build settings fine-tuned for your use. While moving to tools like Buck, you can’t just bring xcconfigs over, instead you’d want to translate xcconfigs to compiler and linker flags and then use those with Buck.</p>
<p>Well, now you have all the knowledge to do so.
You’d need to start with reading and resolving xcconfigs and then map resolved build settings to build flags.
It’s not a straightforward task and may take a while to implement.
Luckily for you, there’s a <a href="https://github.com/mgrebenets/fastlane-plugin-xcconfig_actions">Fastlane plugin</a> that does just that.</p>
<p>Like many unofficial tools, this plugin is reverse engineering the ways Xcode works, so use it at your own risk.</p>
https://mgrebenets.github.io/xcode/2019/05/12/xcode-build-settings-in-depth
https://mgrebenets.github.io/xcode/2019/05/12/xcode-build-settings-in-depth2019-05-12T00:00:00+00:00Fastlane for Enterprise
<p>Learn how to use <a href="https://github.com/fastlane/fastlane">Fastlane</a> in enterprise environment.</p>
<!--more-->
<p>In case you were wondering, no - <a href="https://github.com/fastlane/fastlane">Fastlane</a> doesn’t have an Enterprise offering. It always was and I hope will be an open-source product.</p>
<p>What the article really is about is how to use Fastlane in enterprise environment. Specifically those Fastlane actions that need connection to external URLs.</p>
<h2 id="enterprise-environment">Enterprise Environment</h2>
<p>If you are one of the lucky devs, who just “connect to Internet directly”™️, you may as well just skip this article and get back to enjoying Getting Things Done.</p>
<p>If, my unlucky friend, the words like <em>company proxy</em> and <em>company firewall</em> sound familiar, then you may find the rest of the article useful.</p>
<p>So, in very simple terms for non-DevOps engineers like me, working in a big enterprise company usually means that there’s at least one <a href="https://en.wikipedia.org/wiki/Proxy_server">proxy server</a> sitting between you, the developer, and outside world, aka The Internet. Proxy will make sure to authenticate you securely, just to know who you are; and it will do other important things, like peeking inside every single zip archive you download. Why? Because it can…</p>
<p>To make sure you don’t visit harmful websites like <a href="https://gist.github.com/">GitHub Gists</a> (🤯), there’s also a <a href="https://en.wikipedia.org/wiki/Firewall_(computing)">network firewall</a> thrown into the mix. The firewall will only allow connections to the whitelisted endpoints.</p>
<p><img src="https://mgrebenets.github.io/assets/images/fastlane-for-enterprise/network.png" alt="Network" /></p>
<h2 id="whitelist">Whitelist</h2>
<p>If you are the one tasked with a job of “Uploading ipa file to TestFlight from CI server”, the first thing to do is to request access to Apple endpoints via your company proxy and firewall. Mind you, the journey you are about to embark on will make Homer’s Odyssey look like a pleasant weekend trip. Depending on the complexity of your company’s IT infrastructure and level of support, you’d better collect all the information on your side first and check it twice, before submitting any requests.</p>
<p><img src="https://mgrebenets.github.io/assets/images/fastlane-for-enterprise/sisyphus.gif" alt="Sisyphus" /></p>
<p>Now, <a href="https://github.com/fastlane/fastlane/tree/master/spaceship">Spaceship</a> is the core part of Fastlane that enables access both to Apple Developer Center and to App Store Connect. The <a href="https://github.com/fastlane/fastlane/tree/master/spaceship#api-endpoints">list of API endpoints</a> used by Spaceship is a good starting point for the request you are about to submit.</p>
<p>I’d even recommend to go one step further and request to whitelist access to all URLs on <code class="highlighter-rouge">apple.com</code> domain. It will make your setup more future proof, in case Apple adds new APIs or changes existing private APIs, which they do quite often.</p>
<p>The final list of domains to whitelist should be like this:</p>
<ul>
<li><code class="highlighter-rouge">*.apple.com/*</code> - for all kind of Apple stuff.</li>
<li><code class="highlighter-rouge">*.devimages.apple.com.edgekey.net</code>/* - this is not strictly required for communicating to dev portal or App Store Connect, but this is where Fastlane can download iOS Simulator images.</li>
<li><code class="highlighter-rouge">*.mzstatic.com/*</code> - so that Fastlane can download screenshots of your app from App Store Connect.</li>
</ul>
<p>The port to request access for is <code class="highlighter-rouge">443</code> - for all HTTPS traffic.</p>
<h2 id="-service-account">🤖 Service Account</h2>
<p>Before you go ahead with submitting new request for your IT infrastructure change, make sure you have a <em>service account</em> as well.</p>
<p>Unlike normal user accounts, service accounts are not tied to a particular employee. This is very important. When a person leaves a company, their account gets eventually wiped and CI pipelines get broken, so the lesson is: <strong>never</strong> use personal accounts for CI setup. Service accounts don’t ask for a pay rise, don’t chuck a sickie, and they just <strong>don’t quit</strong>.</p>
<p>Another good thing about service accounts, they normally don’t have the password expiry policy set. You don’t have to update your CI configuration with a new password every 90 days or so.</p>
<p>If you don’t have a service account, request one then. Yes, it may mean you have to open yet another request to some other DevOps team, but who said enterprise was easy?</p>
<h2 id="using-fastlane-behind-the-proxy">Using Fastlane behind the Proxy</h2>
<p>Fast-forward <code class="highlighter-rouge">N</code> weeks, where <code class="highlighter-rouge">N</code> is a random large non-negative number, and you have the following at your disposal:</p>
<ul>
<li>A service account username and password, and maybe even an email, if you are super lucky.</li>
<li>Let’s assume the username is part of <a href="https://en.wikipedia.org/wiki/Active_Directory#Domain_Services">Active Directory Domain</a> and comes in a <code class="highlighter-rouge">au\username</code> form, where <code class="highlighter-rouge">au</code> is the domain.</li>
<li>
<p>Let’s also assume the password is just <code class="highlighter-rouge">password</code>.</p>
</li>
<li>All requested domains are whitelisted on all levels of intranet.</li>
<li>You service account can authenticate to the company proxy using username and password and access whitelisted domains.</li>
<li>Let’s assume the proxy host name is <code class="highlighter-rouge">company-proxy</code> and it listens on port <code class="highlighter-rouge">8080</code> for all incoming connections.</li>
</ul>
<h3 id="curl-test">Curl Test</h3>
<p>First off, run a simple <code class="highlighter-rouge">curl</code> test to make sure everything works:</p>
<script src="https://gist.github.com/c9807f0c69ccf2d12b94717238473e3c.js"> </script>
<p>The <code class="highlighter-rouge">--proxy-user</code> and <code class="highlighter-rouge">--proxy</code> options are self-explanatory, though note the backslash escaping as <code class="highlighter-rouge">\\</code>.</p>
<p>By saying <code class="highlighter-rouge">--proxy-anyauth</code> we tell curl to work with any authentication scheme that the proxy supports.</p>
<p>Most likely, all outgoing network traffic on your dev machine is signed with a company’s own self-signed Root Certificate Authority (CA) certificate, so we use <code class="highlighter-rouge">--insecure</code> option to convince <code class="highlighter-rouge">curl</code> to accept this self-signed certificate.</p>
<p>The self-signed root CA and authentication scheme will play very important role further on.</p>
<p>The output of the command should be something like this:</p>
<blockquote>
<p>Unauthenticated</p>
<p>Request ID: ABCABCBACBACXYZXYZXYZZ37.0.0</p>
</blockquote>
<p>Which is good. It means the request went all the way to appstoreconnect.apple.com.</p>
<h3 id="-root-ca-and-ssl-certificates">🔏 Root CA and SSL Certificates</h3>
<p>Just like with <code class="highlighter-rouge">curl</code>, self-signed root CA certificate will not be accepted by Fastlane either. While running Fastlane, you won’t have any option like the <code class="highlighter-rouge">curl</code>’s <code class="highlighter-rouge">--insecure</code> flag. Instead you need to add your internal root CA certificate to <a href="https://github.com/rubygems/rubygems">rubygems</a> path, because Fastlane is a Ruby gem:</p>
<script src="https://gist.github.com/015f115fdab9fdee73f2128f0ba8d837.js"> </script>
<p>You may have to use <code class="highlighter-rouge">sudo</code> if you are using system Ruby version, though I’d recommend to use <a href="http://rvm.io">RVM</a> or <a href="https://github.com/rbenv/rbenv">rbenv</a> to manage your rubies.</p>
<p>If you are using RVM you need to run the following as well:</p>
<script src="https://gist.github.com/24ad106dfe628076dbbb979e3df5bdf6.js"> </script>
<p>Now you can use <a href="https://gist.github.com/mgrebenets/ebab9213959319779807ce39bd0bed56">this Ruby script</a> to test SSL connection.</p>
<p>E.g. just run it directly like this:</p>
<script src="https://gist.github.com/a82a9a8989a279824e69b6bd55f88e7c.js"> </script>
<h3 id="-environment-variables">💲 Environment Variables</h3>
<p>Next thing you will notice is that Fastlane doesn’t have any option for passing proxy information.
Luckily, Fastlane is being a good citizen and respects all the <code class="highlighter-rouge">/http[s]_proxy/i</code> environment variables, namely:</p>
<ul>
<li><code class="highlighter-rouge">HTTP_PROXY</code></li>
<li><code class="highlighter-rouge">HTTPS_PROXY</code></li>
<li><code class="highlighter-rouge">http_proxy</code></li>
<li><code class="highlighter-rouge">https_proxy</code></li>
</ul>
<p>Remember this <em>“Gang of Four”</em>, nothing else will cause you as much pain as this bunch!</p>
<p>Somewhere in your <code class="highlighter-rouge">~/.bash_profile</code> or other appropriate shell profile, set these environment variables, for example:</p>
<script src="https://gist.github.com/f9e7d514cd8053d043ffa3a0c5b81c5c.js"> </script>
<p>Note that proxy URL is set in the following format:</p>
<blockquote>
<p>http://<code class="highlighter-rouge"><domain></code>\<code class="highlighter-rouge"><username></code>:<code class="highlighter-rouge"><password></code>@<code class="highlighter-rouge">host</code>:<code class="highlighter-rouge">port</code></p>
</blockquote>
<p>Without username and password, you wouldn’t be able to authenticate with your proxy.</p>
<p>Now give it a try, run the simple <code class="highlighter-rouge">download_screenshots</code><a href="https://docs.fastlane.tools/actions/deliver/">deliver</a> action:</p>
<script src="https://gist.github.com/5b8154f9c93e45544aca8090abf5a8e4.js"> </script>
<p>Answer all the prompts and see if it worked. I bet it did not!</p>
<p>Long story short, Fastlane is using <a href="https://github.com/lostisland/faraday">faraday</a> HTTP client Ruby library, which uses <a href="https://ruby-doc.org/stdlib-2.5.1/libdoc/uri/rdoc/Kernel.html">Kernel.URI</a> method, which can’t handle backslash <code class="highlighter-rouge">\</code> in username.</p>
<p>The solution is to use <a href="https://en.wikipedia.org/wiki/Percent-encoding">percent-encoding</a> for <code class="highlighter-rouge">\</code>, i.e. <code class="highlighter-rouge">%5c</code>:</p>
<script src="https://gist.github.com/7c222f043cc1a4007f6b8f984030ac57.js"> </script>
<p>You should be able to download screenshots now, though that’s just a first tiny step towards the final goal.
Well, actually, you can do a lot of things now, such as registering devices, managing App IDs and provisioning profiles, and more.
But I’d assume you also want to upload a new <code class="highlighter-rouge">ipa</code> to <a href="https://developer.apple.com/testflight/">TestFlight</a>, so meet The Transporter then…</p>
<h3 id="-transporter">🚎 Transporter</h3>
<p><a href="https://itunespartner.apple.com/en/movies/faq/Transporter_Getting%20Set%20Up">Transporter</a> aka <a href="https://help.apple.com/itc/transporteruserguide/#/apdAbeb95d60">iTMSTransporter</a> is a Java-based command-line tool used to “upload things to App Store”, including app metadata and new <code class="highlighter-rouge">ipa</code> builds.</p>
<h4 id="installing-transporter">Installing Transporter</h4>
<p>So how do you get a copy?</p>
<p>Well… <a href="https://help.apple.com/itc/transporteruserguide/#/apdA3ae5a8b0?sub=apdA687d545d">according to Apple</a>, you first login to your developer account and then click the download link <a href="https://itunesconnect.apple.com/WebObjects/iTunesConnect.woa/ra/resources/download/Transporter__OSX/bin/">like this one</a>.</p>
<p>But wait! You can’t download it unless you have <em>Admin</em> or <em>Technical</em> role.</p>
<p>I mean, “Why, Apple?! Why?!” 😱</p>
<p>Transporter is available as part of Xcode installation anyways, why make things so hard?</p>
<p>Why not make it available at <a href="https://developer.apple.com/download/more/">Apple Developers Downloads</a> at the very least?</p>
<p>Anyways, if you choose to use copy bundled with Xcode, then you can find it at</p>
<blockquote>
<p>/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/itms</p>
</blockquote>
<p>Just grab the whole directory.</p>
<p>If you installed it via Mac OS package, then get it at</p>
<blockquote>
<p>/usr/local/itms</p>
</blockquote>
<h4 id="patching-transporter">Patching Transporter</h4>
<p>If you wonder: “Why do I need a copy of Transporter? Can’t Fastlane just use it as is?”</p>
<p>Good question, you don’t need a copy of Transporter, you can use the one available inside Xcode or in your <code class="highlighter-rouge">/usr/local</code>, but you would have to patch it before using anyways.</p>
<p>Given that Transporter is a Java-based <em>command-line</em> app, it has the same issue as <code class="highlighter-rouge">curl</code> or any Ruby gem would have with your company’s internal <em>self-signed</em> root CA certificate - it won’t trust it. Apple didn’t bother to add a command line or configuration option of any kind to Transporter to trust self-signed certificates.</p>
<p>Thankfully, Transporter isn’t <em>just</em> a Java-based app, it comes with it’s own version of Java runtime bundled up inside <code class="highlighter-rouge">itms/java</code>. Try running <code class="highlighter-rouge">itms/java/bin/java -version</code> to see more info.</p>
<p>Now, the <code class="highlighter-rouge">itms/java</code> folder also contains <code class="highlighter-rouge">lib/security/cacerts</code> file, which is a <a href="https://www.ibm.com/support/knowledgecenter/en/SSYKE2_8.0.0/com.ibm.java.security.component.80.doc/security-component/keytoolDocs/cacertsfile.html">keystore with CA certificates</a>. So you need to add your company certificate to <code class="highlighter-rouge">cacerts</code> and <code class="highlighter-rouge">itms/java/bin/keytool</code> is just the right tool to do that.</p>
<script src="https://gist.github.com/ac573580346bafcded3c4c4063c77cb2.js"> </script>
<p>Here <code class="highlighter-rouge">${ROOT_CA_PATH}</code> is path to the certificate file, which you can locate directly or find it in OS X keychain</p>
<script src="https://gist.github.com/ec4231dffb1553a942b1befa4ea48706.js"> </script>
<p>Now you’ve convinced Transporter to trust your root CA, but you are not there yet, because you also need to teach Transporter some respect towards your new and shiny proxy, which is where the trouble awaits for you… again.</p>
<h4 id="transporter-and-proxy">Transporter and Proxy</h4>
<p>Well, now that we know that Transporter is a Java-based app, we look closer inside <code class="highlighter-rouge">itms</code> folder and find <code class="highlighter-rouge">itms/java/lib/net.properties</code> - a Java properties files used to configure <a href="https://en.wikipedia.org/wiki/Java_virtual_machine">JVM</a> that Transporter runs in.</p>
<p>The group of proxy variables is exactly what we need:</p>
<script src="https://gist.github.com/3e3db0cea028c2f32989d107273d380f.js"> </script>
<p>You don’t even have to modify the <code class="highlighter-rouge">net.properties</code> file, Fastlane reads the value of special <code class="highlighter-rouge">DELIVER_ITMSTRANSPORTER_ADDITIONAL_UPLOAD_PARAMETERS</code> environment variable and uses it to configure Transporter, for example in your <code class="highlighter-rouge">bash</code> script add the following <code class="highlighter-rouge">export</code> statement:</p>
<script src="https://gist.github.com/7fdc439c695408166d6c555413ceadad.js"> </script>
<p>But will it work? By now you’ve been there enough times to know the answer - <strong>“No”</strong>. 😜</p>
<p>Proxy configuration needs to include username and password for <a href="https://en.wikipedia.org/wiki/Basic_access_authentication">Basic authentication</a>.</p>
<p>You can try to add <code class="highlighter-rouge">au%5cusername:password@company-proxy</code> as the host value, but it will <strong>not</strong> work.</p>
<p>Removing <code class="highlighter-rouge">jdk.http.auth.tunneling.disabledSchemes=Basic</code> limitation from <code class="highlighter-rouge">net.properties</code> won’t help either.</p>
<p>While trying to google you may find mention of these properties:</p>
<script src="https://gist.github.com/50cc6828a877eb475cf0d306dd834624.js"> </script>
<p>Those are part of <a href="https://hc.apache.org/">Apache HTTP Client</a> JVM options though and are not part of <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/net/proxies.html">default Oracle’s network properties</a>, also Transporter doesn’t respect them.</p>
<p>🚧 Feels like another roadblock.</p>
<h4 id="another-proxy">Another Proxy</h4>
<p>The solution this time is to create yet another proxy (as if there wasn’t enough problems with them already!).</p>
<p>This “man in the middle” <em>local</em> proxy will take care of passing authentication information to your company proxy. The credentials no longer have to be hard-coded in proxy URL. This way the command line tools like Transporter can use <em>local</em> proxy for network connections and local proxy doesn’t require any type of authentication.</p>
<p>There is a number of proxy tools available for Mac OS. In this example I’ll be using <a href="http://cntlm.sourceforge.net/">CNTLM</a>.</p>
<p>I’ll briefly mention that I also tried <a href="https://tinyproxy.github.io/">TinyProxy</a> and <a href="https://github.com/rofl0r/proxychains-ng">ProxyChains-NG</a>. TinyProxy just wouldn’t let me use <code class="highlighter-rouge">\</code> or <code class="highlighter-rouge">%5c</code> in configuration file, while with ProxyChains-NG I just eventually gave up after a number of failed attempts to make it work.</p>
<p>So, <em>CNTLM</em>, a fast proxy for <a href="https://en.wikipedia.org/wiki/NT_LAN_Manager">NTLM</a> authentication implemented in C.</p>
<p>Easy to install.</p>
<script src="https://gist.github.com/58deb6e533fe11cd70413fc97e645c93.js"> </script>
<p>Easy to configure, just put the following in <code class="highlighter-rouge">cntlm.conf</code>:</p>
<script src="https://gist.github.com/8ee6a6c6f7e9cc33719c72ba94ecba26.js"> </script>
<p>Now run this command to generate password hashes:</p>
<script src="https://gist.github.com/24d24054dfc3b248374be8508e71c1ce.js"> </script>
<p>Type in your account password, copy hashes and append them to <code class="highlighter-rouge">cntlm.conf</code>:</p>
<script src="https://gist.github.com/98c83b781ad0e3479009d695ab8fa5da.js"> </script>
<p>Then run it:</p>
<script src="https://gist.github.com/52b3d6684d021f79d52c5ba1e6d18c86.js"> </script>
<p>Finally, configure proxy environment variables:</p>
<script src="https://gist.github.com/be4317b56defcdb3923b8ab4c2ebc607.js"> </script>
<p>Give it a go!</p>
<script src="https://gist.github.com/acc808d18687b13164e2494d134fad6e.js"> </script>
<p>What do you mean by “It doesn’t work!”?.
Something about proxy returning invalid challenge?</p>
<p>Well, that just means you company proxy doesn’t support NTLM authentication and only supports Basic authentication.
That needs to be changed by requesting IT support again, I’m afraid.</p>
<p>Now the curl test should finally work and your configuration looks like this:</p>
<p><img src="https://mgrebenets.github.io/assets/images/fastlane-for-enterprise/cntlm.png" alt="CNTLM" /></p>
<h3 id="upload-ipa">Upload <code class="highlighter-rouge">ipa</code></h3>
<p>You are all set now to run one of the most common and recurring tasks in <em>Continuous Delivery</em> process for an iOS app - upload a new build to <a href="https://developer.apple.com/testflight/">TestFlight</a>.</p>
<p>Start by setting up the basic lane using <a href="https://docs.fastlane.tools/actions/pilot/">pilot</a> action.</p>
<script src="https://gist.github.com/233b2f7a60f5ea5e30cdd31e87a63201.js"> </script>
<p>To skip the password prompt, set <code class="highlighter-rouge">FASTLANE_PASSWORD</code> environment variable. It could be a secret parameter in your CI server configuration or you could save it in OS X keychain as <code class="highlighter-rouge">AppleID.Password</code> and read like so:</p>
<script src="https://gist.github.com/8d509d5caccc7a3350ee6bc9e1d0b3cd.js"> </script>
<p>It’s important not to confuse Apple ID used as <em>username</em> with Apple ID of the app. Latter is the unique identifier the app is assigned in App Store, that’s why it is often referred to as <em>Adam</em> or <em>Adam/Apple/App</em> ID. You can find out Adam ID of the app by navigating to it in App Store Connect and grabbing the last part of URL.</p>
<p>Then again, <code class="highlighter-rouge">app_identifier</code> parameter is actually the Bundle Identifier stored under <code class="highlighter-rouge">CFBundleIdentifier</code> in the application’s <code class="highlighter-rouge">Info.plist</code>.</p>
<p>In this example, we <strong>don’t</strong> want to submit new build for review yet and we don’t want to wait for processing either, thus both <code class="highlighter-rouge">skip_submission</code> and <code class="highlighter-rouge">skip_waiting_for_build_processing</code> are set to <code class="highlighter-rouge">true</code>.</p>
<p>Note, that with most of Fastlane actions, each action parameter is shadowed by an environment variable. For example, instead of setting <code class="highlighter-rouge">ipa</code> parameter you can set <code class="highlighter-rouge">PILOT_IPA</code> environment variable. To see full list of parameters for an action, run <code class="highlighter-rouge">bundle exec fastlane action <action_name></code>, for example:</p>
<script src="https://gist.github.com/823ce818a19a1e69d3f32c9279b5c170.js"> </script>
<p>Try to run the lane now, after setting up all the environment variables, of course:</p>
<script src="https://gist.github.com/5e6c8d23e088bd472ac530f402676654.js"> </script>
<h4 id="fastlane-session">Fastlane Session</h4>
<p>If you plan to use similar action on CI server, then <a href="https://en.wikipedia.org/wiki/Multi-factor_authentication">Two-factor authentication (2FA)</a> enforced by Apple will become an issue. To avoid 2FA on CI servers, you need to set the <code class="highlighter-rouge">FASTLANE_SESSION</code> environment variable as described <a href="https://github.com/fastlane/fastlane/tree/master/spaceship#support-for-ci-machines">here</a>.</p>
<script src="https://gist.github.com/94d85fd227ea0b9bf48bb0a23f931286.js"> </script>
<p>Whenever using 2FA the browser will prompt you if you want to trust this particular browser. Doing so will generate a long-living session token (30 days) which will then be picked by Fastlane’s <code class="highlighter-rouge">spaceauth</code> command. This way you will only have to update your CI server configuration once every 30 days. There may be <a href="https://github.com/fastlane/fastlane/issues/14305">some ways</a> to keep the session token up to date by running scheduled CI jobs that perform Spaceship login, though I haven’t tested that approach yet.</p>
<h2 id="summary">Summary</h2>
<p>By the end of this journey you are able to upload new iOS app builds to TestFlight from the enterprise network, e.g. from a CI build agent.</p>
<p>It’s amazing how such a basic task requires so much extra effort when dealing with all the overhead inherent to most large companies.</p>
<p>I hope it was worth the effort though.
Once it all set up and runs smoothly, there are so many other apsects of iOS development that can be automated using tools like Fastlane.</p>
https://mgrebenets.github.io/fastlane/2019/04/07/fastlane-for-enterprise
https://mgrebenets.github.io/fastlane/2019/04/07/fastlane-for-enterprise2019-04-07T00:00:00+00:00Xcode Build Phases and Environment
<p>How to teach Xcode to respect the Environment.</p>
<!--more-->
<p>If you’ve ever done iOS development you’ve surely used <a href="https://help.apple.com/xcode/mac/10.2/#/dev50bab713d">Xcode Build Phases</a>. One of the tasks that a build phase can perform is <a href="https://help.apple.com/xcode/mac/10.2/#/devc8c930575">running a shell script</a>, and that’s where you can face one peculiar problem…</p>
<h1 id="the-problem">The Problem</h1>
<p>The problem is that shell scripts ran in Xcode build phases <strong>do not</strong> source the user shell profile.</p>
<p>Try to put the following in your shell profiles<code class="highlighter-rouge">~/.profile</code>:</p>
<script src="https://gist.github.com/78700337a9fbe957553136ab72c7f5fb.js"> </script>
<p>Then run the build phase by building Xcode project.</p>
<p><img src="https://mgrebenets.github.io/assets/images/build-phases-env/build-phase.png" alt="Build Phase" /></p>
<p>None of the messages from shell profiles will show up.</p>
<p>The reason is that a shell ran from Xcode build phase is <a href="https://www.vanimpe.eu/2014/01/18/different-shell-types-interactive-non-interactive-login/">non-interactive shell</a>.</p>
<p>It is not actually not a bug, but an expected behavior, which may confuse you a bit though.</p>
<h2 id="the-example">The Example</h2>
<p>As an example, let’s say you’ve got a Ruby script which you want to run as part of Xcode build phase.</p>
<p>The script happens to be using some 2.5.x Ruby language features, which are not available in 2.3.x.</p>
<p>You are also using <a href="http://rvm.io/">RVM</a> to install and use version 2.5.x.</p>
<p>Now add <code class="highlighter-rouge">ruby --version</code> to the build phase, build the project and check the output.
On Mojave OS X the output will be <code class="highlighter-rouge">2.3.7</code>, which is the system Ruby version.</p>
<p>None of the RVM environment usually defined in shell profile got loaded into script.</p>
<h2 id="login-shell">Login Shell</h2>
<p>One solution to this problem is to use <a href="https://www.vanimpe.eu/2014/01/18/different-shell-types-interactive-non-interactive-login/">login shell</a>.</p>
<p>It’s as simple as adding <code class="highlighter-rouge">-l</code> to the “Shell” parameter of the build phase, for example <code class="highlighter-rouge">/bin/sh -l</code>.
However, it will <strong>not</strong> work for <a href="https://en.wikipedia.org/wiki/Bourne_shell">Bourne shell (sh)</a>.</p>
<p>But the it <strong>will</strong> work for the <a href="https://en.wikipedia.org/wiki/Bash_(Unix_shell)">Bourne-again shell (bash)</a>, so you could change “Shell” parameter to say <code class="highlighter-rouge">/bin/bash -l</code>.</p>
<p>You will see this in the logs now:</p>
<blockquote>
<p>Loading ~/.bash_profile</p>
</blockquote>
<p>That works, but is not ideal. If you have a lot of developers on the team, they may have all kinds of things happening in their <code class="highlighter-rouge">~/.bash_profile</code> which you don’t necessarily want to run in Xcode build phase. All you want is only load RVM environment, nothing else.</p>
<p>Other developers may as well use <a href="https://en.wikipedia.org/wiki/Z_shell">zsh</a> or some other kind of shell.</p>
<h2 id="build-phase-scripts">Build Phase Scripts</h2>
<p>Another way to tackle this problem is to source just the things that matter as part of each build phase script.</p>
<p>For example, to use RVM for loading Ruby version in non-interactive shell, you could use this code:</p>
<script src="https://gist.github.com/d4366ceaa3593310244d81800cf5160c.js"> </script>
<p>Here we first add <code class="highlighter-rouge">rvm</code> command to the <code class="highlighter-rouge">PATH</code>.
Then we read Ruby version used by the project from <code class="highlighter-rouge">.ruby-version</code> file, which is one of the common setups.
Finally we get a shell script containing all the environment variables using <code class="highlighter-rouge">rvm "${RUBY_VERSION}" do rvm env --path</code> and source (load) that script into current shell session.</p>
<p>Now you can put this code to a <a href="https://github.com/bkeepers/dotenv">dotenv</a> file called <code class="highlighter-rouge">.env.ruby</code>, for example.
Each build phase shell script that requires Ruby can now add <code class="highlighter-rouge">source .env.ruby</code> line.</p>
<p><img src="https://mgrebenets.github.io/assets/images/build-phases-env/source-env.png" alt="Load Ruby Environment" /></p>
<p>While this approach may look like it requires more work, it is still a better one for a couple of reasons:</p>
<ul>
<li>You only load the things you need to run your script, not all the things from user’s shell profile</li>
<li>The Ruby version is selected based on the project’s <code class="highlighter-rouge">.ruby-version</code> file, while with login shell approach the default Ruby version set for RVM globally is loaded and you’d have to run extra code to switch to correct version</li>
</ul>
<h1 id="tips">Tips</h1>
<p>A few tips to using shell script build phases.</p>
<h2 id="script-errors">Script Errors</h2>
<p>Add <code class="highlighter-rouge">-e</code> flag for build phase to fail if shell script returns error code other that <code class="highlighter-rouge">0</code>, e.g. <code class="highlighter-rouge">/bin/sh -e</code>.</p>
<h2 id="managing-build-phase-scripts">Managing Build Phase Scripts</h2>
<p>Use the following convention to manage you build phase scripts:</p>
<blockquote>
<p>There must be one shell script per build phase.</p>
</blockquote>
<p>For example, put all your build phase scripts in a directory named <code class="highlighter-rouge">build-phases</code>, e.g. <code class="highlighter-rouge">build-phases/codecheck.sh</code>, <code class="highlighter-rouge">build-phases/codegen.sh</code>, etc.</p>
<p>In Xcode build phase UI instead of having an inline script, you have this now:</p>
<p><img src="https://mgrebenets.github.io/assets/images/build-phases-env/build-phase-script.png" alt="Build Phase Script" /></p>
<p>You can even move the Ruby environment loading line inside the build phase script to keep it down to a one-liner.</p>
<p>It’s a much better approach for a number of reasons:</p>
<ul>
<li>If you modify the build phase script, it’s much easier to review it in pull request as a change of <code class="highlighter-rouge">.sh</code> file, compared to when you have to review it as part of <code class="highlighter-rouge">pbxproj</code> UTF-8 ASCII plist file changes with all the newline and other escape sequences added into the mix.</li>
<li>You can reuse build phase scripts outside of Xcode, e.g. if you try to use alternative build system like <a href="https://buckbuild.com">Buck</a>.</li>
</ul>
https://mgrebenets.github.io/xcode/2019/04/04/xcode-build-phases-and-environment
https://mgrebenets.github.io/xcode/2019/04/04/xcode-build-phases-and-environment2019-04-04T00:00:00+00:00Swift Refactoring - Summary
<p>A summary for the <a href="/swift/2019/02/01/swift-refactoring-intro">series of articles</a> about implementing <a href="https://swift.org/blog/swift-local-refactoring/">Swift Local Refactoring</a> action.</p>
<!--more-->
<p>If you came here after going through previous 6 articles, you may have a few questions to ask:</p>
<p><em>Was it worth it?</em></p>
<p>Sure it was.</p>
<p>I learned the basics of working with Swift code base.
How to <a href="/swift/2019/02/02/swift-refactoring-setup">build it</a>, how to <a href="/swift/2019/02/03/swift-refactoring-tests">write tests</a> and <a href="/swift/2019/02/05/swift-refactoring-debugging">debug</a> the code.</p>
<p>This whole exercise took me one tiny step closer to understanding the rest of the Swift project.</p>
<p><em>Would you do it again?</em></p>
<p>The answer is “Yes” and “No”.</p>
<p>No, I would probably not try to implement another refactoring action via <code class="highlighter-rouge">swift-refactor</code>.
Instead, I’d look into using <a href="https://github.com/apple/swift/tree/master/lib/Syntax">libSyntax</a> library.</p>
<p>Yes, if I had more time to spare I’d look at one of the many <a href="https://bugs.swift.org/browse/TF-130?jql=labels%20%3D%20StarterBug">Swift starter tasks</a>.</p>
https://mgrebenets.github.io/swift/2019/02/06/swift-refactoring-summary
https://mgrebenets.github.io/swift/2019/02/06/swift-refactoring---summary2019-02-06T00:00:00+00:00Swift Refactoring - Debugging
<p>Debugging implementation for <a href="https://swift.org/blog/swift-local-refactoring/">Swift Local Refactoring</a> action.</p>
<!--more-->
<p><a href="/swift/2019/02/04/swift-refactoring-implementation-p2">Previous - Implementation Part 2</a></p>
<h1 id="ninja">Ninja</h1>
<p>If you have built <code class="highlighter-rouge">swift-refactor</code> tool using <code class="highlighter-rouge">ninja</code>, then you’d have to use command line <code class="highlighter-rouge">lldb</code> debugger to debug the code.
So after building <code class="highlighter-rouge">swift-refactor</code>, just run <code class="highlighter-rouge">lldb</code> in the terminal:</p>
<script src="https://gist.github.com/e5096458777a46043e046293e0579364.js"> </script>
<p>Next, tell the debugger which executable to debug (<code class="highlighter-rouge">swift-refactor</code> in this case):</p>
<script src="https://gist.github.com/6fe00897a20c233b0124a9506ee54cdc.js"> </script>
<p>Then set the breakpoint, e.g. for <code class="highlighter-rouge">isApplicable</code> implementation of <code class="highlighter-rouge">RefactoringActionCollapseNestedIfStatement</code> class:</p>
<script src="https://gist.github.com/4ff653ecb873a61c4461b1d034bb070e.js"> </script>
<p>Now tell <code class="highlighter-rouge">lldb</code> to run the executable with <code class="highlighter-rouge">-source-filename</code> and <code class="highlighter-rouge">-pos</code> arguments</p>
<script src="https://gist.github.com/680846748441ee7b74baaf55592bbd7a.js"> </script>
<p>The debugger has now stopped on line <code class="highlighter-rouge">1714</code> and is ready for your further input:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">-></span> <span class="mi">1714</span>
</code></pre></div></div>
<p>Same debug commands you’d use in Xcode UI work in command line:</p>
<script src="https://gist.github.com/0c003ac22de699731108cde0a146cd49.js"> </script>
<p><img src="https://mgrebenets.github.io/assets/images/swift-refactoring/refactoring-lldb.gif" alt="LLDB" /></p>
<h1 id="xcode">Xcode</h1>
<p>If you choose to develop using Xcode, debugging is even easier.</p>
<p>Edit the <em>swift-refactor</em> scheme</p>
<p><img src="https://mgrebenets.github.io/assets/images/swift-refactoring/xcode-edit-scheme.png" alt="Edit Scheme" /></p>
<p>and add launch arguments:</p>
<p><img src="https://mgrebenets.github.io/assets/images/swift-refactoring/launch-args.png" alt="Launch Arguments" /></p>
<p>Set breakpoint and hit “Run”:</p>
<p><img src="https://mgrebenets.github.io/assets/images/swift-refactoring/breakpoint.png" alt="Breakpoint" /></p>
<hr />
<p><a href="/swift/2019/02/06/swift-refactoring-summary">Next - Summary</a></p>
https://mgrebenets.github.io/swift/2019/02/05/swift-refactoring-debugging
https://mgrebenets.github.io/swift/2019/02/05/swift-refactoring---debugging2019-02-05T00:00:00+00:00Swift Refactoring - Implementation - Part 2
<p>Implementing <a href="https://swift.org/blog/swift-local-refactoring/">Swift Local Refactoring</a> action.</p>
<p>Part 2 of 2.</p>
<!--more-->
<p>In the <a href="/swift/2019/02/04/swift-refactoring-implementation-p1">previous part</a> we’ve implemented <code class="highlighter-rouge">isApplicable</code> check.</p>
<p>The very same <code class="highlighter-rouge">findNestedIfStatements</code> can be reused to implement refactoring transformation.</p>
<script src="https://gist.github.com/aad6c1c141df7a1b428ad72e59241057.js"> </script>
<p><code class="highlighter-rouge">// 1</code>
The first thing to do is check if refactoring can be applicable.
Note that we return <code class="highlighter-rouge">true</code> to abort the refactoring transformation.</p>
<script src="https://gist.github.com/7be112d50dbd6c8a7fd3504bd32fd6f7.js"> </script>
<p><code class="highlighter-rouge">// 2</code>
Next we create a buffer to write transformed code into and then create an output stream for writing to the buffer.</p>
<script src="https://gist.github.com/82b56fbe2f6a6d3c192d5f57598fa93b.js"> </script>
<p><code class="highlighter-rouge">// 3</code>
A collapsed <em>if</em> statement will still be an <em>if</em> statement, so we write the <code class="highlighter-rouge">if</code> keyword to output stream using <code class="highlighter-rouge">kw_if</code> keyword token.</p>
<script src="https://gist.github.com/7b03325997c013a4ce541ecd85db8ba0.js"> </script>
<p><code class="highlighter-rouge">// 4</code>
Now we need to write the combined conditions list to output stream.
Conveniently, conditions in the <a href="https://docs.swift.org/swift-book/ReferenceManual/Statements.html#grammar_condition-list">condition-list</a> can be joined together using commas.</p>
<blockquote>
<p>Grammar of an if statement</p>
<p>if-statement → if condition-list code-block else-clause opt</p>
<table>
<tbody>
<tr>
<td>else-clause → else code-block</td>
<td>else if-statement</td>
</tr>
</tbody>
</table>
<table>
<tbody>
<tr>
<td>condition-list → condition</td>
<td>condition , condition-list</td>
</tr>
</tbody>
</table>
</blockquote>
<p>Loop through conditions collected while finding nested <em>if</em> statements:</p>
<script src="https://gist.github.com/2a3c0d5e52a49ea53e19dc83515a4263.js"> </script>
<p>Get the range of the condition statement <code class="highlighter-rouge">SC</code> in the original source code:</p>
<script src="https://gist.github.com/48be3adc523999879f687e3dcbb9c7ec.js"> </script>
<p>Get the string representation of the condition statement from the original source code:</p>
<script src="https://gist.github.com/3fc86c2abda111e898b84e525c0493e5.js"> </script>
<p><code class="highlighter-rouge">SM</code> here is an instance of <code class="highlighter-rouge">SourceManager</code> available to each refactoring action implementation.</p>
<p>Finally write the condition string into output stream joining it with the comma if needed.</p>
<script src="https://gist.github.com/74fc1d0b468c682574146214359d4d7f.js"> </script>
<p>On first iteration separator will be an empty string while 2nd and consequent statements are joined by <code class="highlighter-rouge">", "</code> string.</p>
<p><code class="highlighter-rouge">// 5</code>
Now is the time to write the <em>then</em> statement shared by all collapsed <em>if</em> statements.
This is the reason we saved <code class="highlighter-rouge">LastThenStatement</code> while finding nested if statements.
Again, we get the string representation of the <em>then</em> statement and write it to output stream.</p>
<script src="https://gist.github.com/cfb6a44c0e60853eb50848a0a02dac97.js"> </script>
<p><em>Then</em> statement already contains opening and closing braces (<code class="highlighter-rouge">{</code> and <code class="highlighter-rouge">}</code>), so no need to add those.</p>
<p><code class="highlighter-rouge">// 6</code>
By this time the new transformed code is saved to output stream <code class="highlighter-rouge">OS</code>.
Final step is to replace original code with the new code using <em>Source Manager</em> <code class="highlighter-rouge">SM</code>.</p>
<p>First step is to get the range of the untransformed source code.</p>
<script src="https://gist.github.com/ea9d9e909548ba4febac675f4f09789d.js"> </script>
<p>Here we take range from the <code class="highlighter-rouge">Start</code> of the <code class="highlighter-rouge">FirstIfStmt</code> to the <code class="highlighter-rouge">End</code> of the <em>then</em> statement.</p>
<p>That range is then transformed into <em>source</em> range, e.g. range in <em>Source Manager</em> <code class="highlighter-rouge">SM</code>’s coordinates:</p>
<script src="https://gist.github.com/891da3a2b44f88120477106a3d209456.js"> </script>
<p>Finally, the code in <code class="highlighter-rouge">SourceRange</code> is replaced with contents of <code class="highlighter-rouge">Buffer</code> and we return <code class="highlighter-rouge">false</code> to indicate successful transformation (🤷♂️)</p>
<script src="https://gist.github.com/44a6f27a91f24a4655ab1ed1cd1f0279.js"> </script>
<p><a href="https://github.com/mgrebenets/swift/blob/feature/collapse-nested-if-statements/lib/IDE/Refactoring.cpp">Full version of Refactoring.cpp</a>.</p>
<p>The implementation is ready to be tested.
If anything goes wrong, then it’s time to debug.</p>
<hr />
<p><a href="/swift/2019/02/05/swift-refactoring-debugging">Next - Debugging</a></p>
https://mgrebenets.github.io/swift/2019/02/04/swift-refactoring-implementation-p2
https://mgrebenets.github.io/swift/2019/02/04/swift-refactoring---implementation-p22019-02-04T00:00:00+00:00Swift Refactoring - Implementation - Part 1
<p>Implementing <a href="https://swift.org/blog/swift-local-refactoring/">Swift Local Refactoring</a> action.</p>
<p>Part 1 of 2.</p>
<!--more-->
<p><a href="/swift/2019/02/03/swift-refactoring-tests">Previous article - Tests</a></p>
<h1 id="add-refactoring-kind">Add Refactoring Kind</h1>
<p>The chosen “Collapse Nested If Statement” refactoring is a cursor-based refactoring, so the first thing to do is to add this code to <a href="https://github.com/apple/swift/blob/master/include/swift/IDE/RefactoringKinds.def">RefactoringKinds.def</a>:</p>
<script src="https://gist.github.com/ee4558e598803b3bef404323bdda3928.js"> </script>
<p>This macro will generate bare bones for new <code class="highlighter-rouge">RefactoringActionCollapseNestedIfStatement</code> class.</p>
<p>A new <code class="highlighter-rouge">-collapse-nested-if-statement</code> command line option needs to be added to <code class="highlighter-rouge">swift-refactor</code> tool in <a href="https://github.com/apple/swift/blob/master/tools/swift-refactor/swift-refactor.cpp">swift-refactor.cpp</a>:</p>
<script src="https://gist.github.com/3076b4459139b1e606b8463b820c0f9d.js"> </script>
<p>Now, to finish off the refactoring action implementation, the following two methods have to be implemented in <a href="https://github.com/apple/swift/blob/master/lib/IDE/Refactoring.cpp">Refactoring.cpp</a>.</p>
<script src="https://gist.github.com/3b76c4b1f52145ee19e988ddddb3f167.js"> </script>
<p>Both methods require current cursor info for implementation.
While <code class="highlighter-rouge">isApplication</code> takes it as a <code class="highlighter-rouge">CursorInfo</code> input argument, for <code class="highlighter-rouge">performChange</code> current cursor info is available as a member of auto-generated <code class="highlighter-rouge">RefactoringActionCollapseNestedIfStatement</code> class.</p>
<h1 id="is-applicable">Is Applicable</h1>
<p>The way I approached this implementation task is asking myself a question first.</p>
<p><em>When is “Collapse Nested If Statements” refactoring action applicable?</em></p>
<p>The obvious answer is:</p>
<p><em>When there are more then 1 nested if statements.</em></p>
<p>So the approach is to <em>find nested if statements</em> at current position and count them.</p>
<p>Let’s first define a simple structure that will hold information about nested if statements:</p>
<script src="https://gist.github.com/116b8da6ff4f19d2cc9bc0c6fad2009e.js"> </script>
<p>It’s very straightforward, we keep track of the first <em>if</em> statement (<code class="highlighter-rouge">FirstIfStmt</code>) and last <strong><em>then</em></strong> statement (<code class="highlighter-rouge">LastThenStmt</code>).</p>
<p>One important thing about collapsible nested <em>if</em> statements is that <strong>they all share a single <em>then</em> statement</strong>, they wouldn’t be collapsible otherwise.</p>
<p>We also save all the <em>if</em> statement conditions into <code class="highlighter-rouge">Conditions</code> list.</p>
<p>To decide whether a refactoring action is applicable, we need to have non-null first <em>if</em> and last <em>then</em> statements and more than 1 condition in the list:</p>
<script src="https://gist.github.com/37aeac21570edc7611f83e4bdb3d9f86.js"> </script>
<p>With this new structure in mind, we can define a new helper method that finds all nested <em>if</em> statements under the cursor and then use it to implement <code class="highlighter-rouge">isApplicable</code>:</p>
<script src="https://gist.github.com/033fbafd5b1d61fd0303640a5839a756.js"> </script>
<h2 id="find-nested-if-statements">Find Nested If Statements</h2>
<p>This is the part where we finally get down to using cursor info provided to us by refactoring engine.</p>
<p>It’s easier to reason about the code in terms of <em>declarations</em>, <em>statements</em> and <em>conditions</em>. For example, for a code like this:</p>
<script src="https://gist.github.com/665c96f2eb401593586268c930f89ff8.js"> </script>
<p>The high level view could be this:</p>
<p><img src="https://mgrebenets.github.io/assets/images/swift-refactoring/abstract-view.png" alt="High Level View" /></p>
<p>The (very rough) Abstract Syntax Tree sketch for this code:</p>
<p><img src="https://mgrebenets.github.io/assets/images/swift-refactoring/ast.png" alt="AST" /></p>
<p>If the cursor is pointing at the start of the first <em>if</em> statement, then the AST we need to analyze looks like this:</p>
<p><img src="https://mgrebenets.github.io/assets/images/swift-refactoring/if-stmt-ast.png" alt="If Statement AST" /></p>
<p>So the very first thing to check is to make sure cursor info is pointing at the <em>start of the statement</em> (<code class="highlighter-rouge">StmtStart</code>), the refactoring can’t be applied otherwise:</p>
<script src="https://gist.github.com/792157b920a56cc575cad032154ad0c9.js"> </script>
<p>The returned empty <code class="highlighter-rouge">NestedIfStatementsInfo()</code> indicates that refactoring cannot be applied because <code class="highlighter-rouge">NestedIfStatementsInfo().canProceed()</code> is <code class="highlighter-rouge">false</code>.</p>
<h3 id="walk-the-tree">Walk the Tree</h3>
<p>Next thing to do is to start walking Abstract Syntax Tree.</p>
<script src="https://gist.github.com/ebf53606957fb4cce81ef1d47ecf6d23.js"> </script>
<p><code class="highlighter-rouge">// 1</code>
For that we create a new type called <code class="highlighter-rouge">NestedIfStatementsFinder</code>, which inherits from <code class="highlighter-rouge">SourceEntityWalker</code> - the base class for walking the source code tree.</p>
<p><code class="highlighter-rouge">// 2</code>
We also initialize an instance of <code class="highlighter-rouge">NestedIfStatementsFinder</code> called <code class="highlighter-rouge">Walker</code>.</p>
<p><code class="highlighter-rouge">// 3</code>
Additionally, our walker should collect nested if statements info into the <code class="highlighter-rouge">Result</code> property.</p>
<p><code class="highlighter-rouge">// 4</code> and <code class="highlighter-rouge">// 5</code>
Finally tell walker to <code class="highlighter-rouge">walk</code> the AST starting from <code class="highlighter-rouge">CursorInfo.TrailingStmt</code> and return the result.</p>
<p>Next let’s have a look at some of the <code class="highlighter-rouge">SourceEntityWalker</code> interface.</p>
<p>It has a handful of methods to walk the AST, specifically it can walk the <em>statement</em>, <em>declaration</em> or <em>expression</em>.</p>
<script src="https://gist.github.com/23643ff1eb9fcc09c495b32478567338.js"> </script>
<p>For our implementation we have used <code class="highlighter-rouge">bool walk(Stmt *S)</code>.</p>
<p>The type also offers customization points:</p>
<script src="https://gist.github.com/e3a136f327eeb99fff8c8ac157978216.js"> </script>
<p>These methods can be overridden in types inheriting from <code class="highlighter-rouge">SourceEntityWalker</code>.
When <code class="highlighter-rouge">true</code> is returned, the walker will keep walking the tree, otherwise it will stop.</p>
<p>For out implementation, we choose to override <code class="highlighter-rouge">walkToStmtPre</code>, which is called when walker is <em>about to walk the statement</em>.</p>
<script src="https://gist.github.com/60b2415aece5d205baefa7ec70bcf127.js"> </script>
<p>Let’s <em>walk</em> this code step by step:</p>
<p><code class="highlighter-rouge">// 1</code>
We are only interested in nested <em>if</em> statements, so when statement kind (<code class="highlighter-rouge">S->getKind()</code>) is not <code class="highlighter-rouge">StmtKind::If</code> then there’s no point to continue (return <code class="highlighter-rouge">false</code>).</p>
<script src="https://gist.github.com/e03b84f3744a24b3ee032997c91e6d32.js"> </script>
<p><code class="highlighter-rouge">// 2</code>
Now that we checked the statement kind, we can safely typecast it to <code class="highlighter-rouge">IfStmt</code>.</p>
<script src="https://gist.github.com/964eb1be034b837de024a66ac065807c.js"> </script>
<p><code class="highlighter-rouge">// 3</code>
We want to keep track of the first <em>if</em> statement in the <code class="highlighter-rouge">Result</code> variable, so save it if this is the first <em>if</em> statement we encounter.</p>
<script src="https://gist.github.com/e5546ad7c6b5809ebc3c2d4e160f92fd.js"> </script>
<p><code class="highlighter-rouge">// 4</code>
If current <em>if</em> statement has an <em>else</em> statement, it cannot be collapsed, so there’s no point to keep going.</p>
<script src="https://gist.github.com/cd9c8a93f87bb5732f82f8daaa00bfd9.js"> </script>
<script src="https://gist.github.com/f34e876a1ab08859417c148c0b48dfed.js"> </script>
<p><code class="highlighter-rouge">// 5</code>
We also need to keep track of last <em>then</em> statement, which will be useful while applying refactoring transformation.</p>
<script src="https://gist.github.com/44a80720186eb7b70f21f9fcb390d53e.js"> </script>
<p><code class="highlighter-rouge">// 6</code>
If the <em>then</em> statement of current <em>if</em> statement has more than one elements, then the refactoring cannot be applied from this point on and need to stop.</p>
<script src="https://gist.github.com/040f9e6337f3364c04370ab6ba266729.js"> </script>
<p>Here’s an example of Swift code:</p>
<script src="https://gist.github.com/d737b9c8b3998ae6690312efd0389503.js"> </script>
<p>The <code class="highlighter-rouge">if a < 2</code> <em>if</em> statement has 2 elements in the <em>then</em> statement: <code class="highlighter-rouge">print(a)</code> and <code class="highlighter-rouge">if b > 1</code> statements.</p>
<p><code class="highlighter-rouge">// 7</code>
Keep track of the <em>if</em> statement conditions in <code class="highlighter-rouge">Conditions</code> list:</p>
<script src="https://gist.github.com/6e7635dff6ba01e29df83e69b1d91311.js"> </script>
<p><code class="highlighter-rouge">// 8</code>
Finally, recursively walk the first statement inside the <em>then</em>-block.</p>
<script src="https://gist.github.com/30d23e616474b37ef06bf63225835a7d.js"> </script>
<h1 id="test">Test</h1>
<p>Now it’s a good time to run the tests <a href="/swift/2019/02/03/swift-refactoring-tests">created in previous article</a> to make sure implementation of <code class="highlighter-rouge">isApplicable</code> works as expected.</p>
<hr />
<p><a href="/swift/2019/02/04/swift-refactoring-implementation-p2">Next - Implementation - Part 2</a></p>
https://mgrebenets.github.io/swift/2019/02/04/swift-refactoring-implementation-p1
https://mgrebenets.github.io/swift/2019/02/04/swift-refactoring---implementation-p12019-02-04T00:00:00+00:00Swift Refactoring - Tests
<p>Using TDD approach to implement <a href="https://swift.org/blog/swift-local-refactoring/">Swift Local Refactoring</a> action.</p>
<!--more-->
<p><a href="/swift/2019/02/02/swift-refactoring-setup">Previous article - Setup</a></p>
<p>TDD or <a href="https://en.wikipedia.org/wiki/Test-driven_development">Test-driven development</a> is a perfect approach when you face a new and unfamiliar code base.</p>
<p>It surely helped me, I was able to wind up a large number of tests and then iterate on actual implementation to make those tests pass.</p>
<p>However, learning how to write tests for Swift source code is a challenge by itself.
The project is using <code class="highlighter-rouge">lit</code> or <a href="https://llvm.org/docs/CommandGuide/lit.html">LLVM Integrated Tester</a> and you can find more details in Apple’s own <a href="https://github.com/apple/swift/blob/80ce2c3f25b47afb22119ba4510421d46b45dec3/docs/Testing.md#using-litpy">Testing Swift</a> documentation.</p>
<h1 id="test-refactoring-kind">Test Refactoring Kind</h1>
<p>I’ll be making changes to the <code class="highlighter-rouge">swift-refactor</code> tool in Swift toolchain.
For now I will treat that tool as a black box, i.e. I have no idea how the refactoring action is implemented.</p>
<p>What I do know though, is that if I give <code class="highlighter-rouge">swift-refactor</code> tool a file and specify a cursor position in that file, then it will print out a list of applicable refactoring actions at that cursor position.</p>
<p>So I’ll start by creating a new test file at <code class="highlighter-rouge">swift/test/refactoring/RefactoringKind/collapse_nested_if_statement.swift</code> with the following content:</p>
<script src="https://gist.github.com/665c96f2eb401593586268c930f89ff8.js"> </script>
<p>Now, if I point a cursor at row <code class="highlighter-rouge">4</code> and column <code class="highlighter-rouge">4</code> in this file, I expect my new refactoring action to be applicable.
If I name the refactoring action “Collapse Nested If Statement”, then this text should be the output of the following command:</p>
<script src="https://gist.github.com/05998b276334983a4af30895df706af1.js"> </script>
<p>So my test case is this:</p>
<p><em>Given that I run <code class="highlighter-rouge">swift-refactor</code> for <code class="highlighter-rouge">collapse_nested_if_statement.swift</code> file, row <code class="highlighter-rouge">4</code> and column <code class="highlighter-rouge">4</code>,
I expect the output to contain <code class="highlighter-rouge">"Collapse Nested If Statement"</code> string.</em></p>
<p>All I have to do now is write this test case using <code class="highlighter-rouge">lit</code> command.
This is how it looks:</p>
<script src="https://gist.github.com/70c92261ce1fbc1b6a907085c6d7ad19.js"> </script>
<p>This code is put directly into <code class="highlighter-rouge">collapse_nested_if_statement.swift</code> file and <code class="highlighter-rouge">lit</code> will pick it up from there.</p>
<p>Here’s the detailed breakdown of the test spec:</p>
<script src="https://gist.github.com/34e7c2b0da5c7ca93d8fa788d475b71f.js"> </script>
<p>The <code class="highlighter-rouge">CHECK-COLLAPSE-NESTED-IF-STATEMENT</code> is also defined in <code class="highlighter-rouge">collapse_nested_if_statement.swift</code> like so:</p>
<script src="https://gist.github.com/89708b5826af86a8475473456f3aae38.js"> </script>
<p>So the refactoring action first begins (<code class="highlighter-rouge">Action begins</code>), then the <code class="highlighter-rouge">Collapse Nested If Statement</code> output is written to standard output and then the action ends (<code class="highlighter-rouge">Action ends</code>).</p>
<p>The special <code class="highlighter-rouge">-NEXT</code> syntax is how you can define multi-line strings.</p>
<p><a href="https://github.com/mgrebenets/swift/blob/feature/collapse-nested-if-statements/test/refactoring/RefactoringKind/collapse_nested_if_statement.swift">More examples of refactoring kind tests</a>.</p>
<h1 id="cursor-position-reference">Cursor Position Reference</h1>
<p>You have probably spotted a small problem with <code class="highlighter-rouge">-pos=4:4</code> argument of the test command.</p>
<p>If the tests are modified, refactored or moved around, then the actual cursor position of the start of test code can change.
When there’s dozens of tests in the single file, fixing up all the impacted <code class="highlighter-rouge">-pos=</code> arguments can be quite a challenge.</p>
<p>That’s where using cursor position <em>reference</em> is really helpful.</p>
<p>All you have to do is add a block comment like so</p>
<script src="https://gist.github.com/3efa36c5d9d73a130895eb47912f1763.js"> </script>
<p>Now you can use <code class="highlighter-rouge">"2-statements"</code> string as a reference to the cursor position:</p>
<script src="https://gist.github.com/659a19a0114166b6ed93fab75f6daadb.js"> </script>
<p>If the <code class="highlighter-rouge">test2Statements</code> is relocated in file or some changes happen to formatting or indentation, the tests will still point to the correct cursor position and will require no changes.</p>
<h1 id="test-refactoring-transformation">Test Refactoring Transformation</h1>
<p>Next thing to test is the refactoring transformation itself.</p>
<p>The structure of these tests is like this:</p>
<ul>
<li>Take the test fixture Swift file that contains code to refactor.</li>
<li>Pass it to <code class="highlighter-rouge">swift-refactor</code> and capture the output.</li>
<li>Compare output to expected code using <code class="highlighter-rouge">diff</code> utility.</li>
</ul>
<p><img src="https://mgrebenets.github.io/assets/images/swift-refactoring/refactoring-transformation-test.png" alt="Test Refactoring Transformation" /></p>
<p>I have created a new <code class="highlighter-rouge">CollapseNestedIfStatement</code> folder under <code class="highlighter-rouge">swift/test/refactoring</code>, then created <code class="highlighter-rouge">basic.swift</code> file and <code class="highlighter-rouge">Outputs/basic</code> directory.</p>
<p><code class="highlighter-rouge">basic.swift</code> is where the <code class="highlighter-rouge">lit</code> tests will live and <code class="highlighter-rouge">Outputs/basic</code> is where expected outputs will be created.</p>
<p>Similar to refactoring kind test, I write the following Swift code in <code class="highlighter-rouge">basic.swift</code>:</p>
<script src="https://gist.github.com/3efa36c5d9d73a130895eb47912f1763.js"> </script>
<p>After the refactoring action has been applied, I expect the code to look like this:</p>
<script src="https://gist.github.com/4971be38d3f05a111d24e8ab77129f83.js"> </script>
<p>so this is what I put into <code class="highlighter-rouge">Outputs/basic/2-statements.swift.expected</code>.</p>
<p>Now I have to write <code class="highlighter-rouge">lit</code> test spec in <code class="highlighter-rouge">basic.swift</code>:</p>
<script src="https://gist.github.com/fa465f1a60f920ab7f09e5a1bc13f7c2.js"> </script>
<p>The test begins by cleaning up output directory with <code class="highlighter-rouge">rm -rf %t.result && mkdir -p %t.result</code> command. <code class="highlighter-rouge">%t</code> in this case is expanded to the test name.</p>
<p>Next the test runs <code class="highlighter-rouge">%refactor</code> command which expands to <code class="highlighter-rouge">swift-refactor</code>. The command is almost identical to the one in refactoring kind tests, except that this time I pass <code class="highlighter-rouge">-collapse-nested-if-statement</code> to tell <code class="highlighter-rouge">swift-refactor</code> to apply this particular refactoring action.</p>
<blockquote>
<p>The <code class="highlighter-rouge">-collapse-nested-if-statement</code> command line option hasn’t been implemented yet, but remember that this is TDD.</p>
</blockquote>
<p>The output of <code class="highlighter-rouge">swift-refactor</code> is saved to <code class="highlighter-rouge">%t.result/2-statements.swift</code>.</p>
<p>Finally, the output is compared to expected Swift code using <code class="highlighter-rouge">diff</code> utility.</p>
<script src="https://gist.github.com/a1c0b88865f68ecff2514ee1f15692c3.js"> </script>
<p><code class="highlighter-rouge">-u</code> is used to compare 3 lines of unified context, while <code class="highlighter-rouge">-B</code> is used to ignore blank lines.</p>
<p><code class="highlighter-rouge">%S</code> is expanded to the parent directory of the current (<code class="highlighter-rouge">basic.swift</code>) file.</p>
<p>That’s the basic approach, next step is to add more test code and expected outputs. <a href="https://github.com/mgrebenets/swift/tree/feature/collapse-nested-if-statements/test/refactoring/CollapseNestedIfStatement">Here’s an example</a>.</p>
<h1 id="running-tests">Running Tests</h1>
<p>Once you have enough tests and made your first changes to implement the new refactoring action, you can rebuild only the <code class="highlighter-rouge">swift-refactor</code> tool:</p>
<script src="https://gist.github.com/7cd513955f23a605c4908a56bf732bc9.js"> </script>
<p>where <code class="highlighter-rouge">SWIFT_BUILD_DIR</code> is set to location of Swift build folder, for example <code class="highlighter-rouge">build/Ninja-RelWithDebInfoAssert+swift-DebugAssert/swift-macosx-x86_64/</code>.</p>
<p>To speed up the development process even further, you can use <code class="highlighter-rouge">--filter</code> option of <code class="highlighter-rouge">lit.py</code> to run selected tests only.
For example, to run only refactoring kind tests from <code class="highlighter-rouge">collapse_nested_if_statement.swift</code>:</p>
<script src="https://gist.github.com/9c55f3e3d6804e8c6d5a32191763b9e8.js"> </script>
<p>Or to run refactoring transformation tests from <code class="highlighter-rouge">CollapseNestedIfStatement/basic.swift</code>:</p>
<script src="https://gist.github.com/9ca593d757b2759aed073b5d9a662d39.js"> </script>
<p>Now you are all set for the usual “Build, Test, Repeat” development cycle.</p>
<hr />
<p><a href="/swift/2019/02/04/swift-refactoring-implementation-p1">Next - Implementation - Part 1</a></p>
https://mgrebenets.github.io/swift/2019/02/03/swift-refactoring-tests
https://mgrebenets.github.io/swift/2019/02/03/swift-refactoring---tests2019-02-03T00:00:00+00:00Swift Refactoring - Setup
<p>Getting Swift sources and setting up build environment to implement <a href="https://swift.org/blog/swift-local-refactoring/">Swift Local Refactoring</a> action.</p>
<!--more-->
<p><a href="/swift/2019/02/01/swift-refactoring-intro">Previous article - Intro</a></p>
<p>When it comes to cloning source code and building it, there’s not that much that I can add to the <a href="https://github.com/apple/swift">Swift repository README</a>, but I’ll try to highlight some moments that I find to be important.</p>
<h1 id="latest-xcode">Latest Xcode</h1>
<p>I can’t stress enough how important this step is!</p>
<p>If you use wrong version of Xcode you will be banging your head against the wall trying to figure out why the build is OK, the tests pass, but you changes do not show up in the Xcode when you choose your new toolchain.</p>
<p>Don’t forget to use latest Xcode when building from command line, for example, if you installed latest Xcode 10.2 beta to <code class="highlighter-rouge">/Applications/Xcode-10.2.app</code>, then run this in terminal</p>
<script src="https://gist.github.com/bd58fc8b49ba6e257acdc085852d4aef.js"> </script>
<h1 id="stable-source">Stable Source</h1>
<p>If you want to use source code that has passed <a href="https://swift.org/continuous-integration/#configuration">Swift CI</a> then, after pulling in all the code, you can customize your <code class="highlighter-rouge">update-checkout</code> command like so</p>
<script src="https://gist.github.com/72f71393af95cf891072f63e17e64294.js"> </script>
<p>If the build was tagged, it means it passed all the tests and had a successful Xcode toolchain build. It may be a good idea to work on top of a stable code.</p>
<h1 id="building-xcode-toolchain">Building Xcode Toolchain</h1>
<p>Apple docs just tell you to run <code class="highlighter-rouge">./utils/build-toolchain $BUNDLE_PREFIX</code> command to build a new toolchain. It works, however, the command takes really long time and doesn’t seem to take advantage of incremental builds when you re-run it.</p>
<p>Instead, you can package a toolchain using build artifacts created with <code class="highlighter-rouge">build-script</code>.</p>
<p><a href="https://johnfairh.github.io/site/swift_source_basics.html">This</a> and <a href="https://samsymons.com/blog/exploring-swift-part-2-installing-custom-toolchains/">this</a> articles provide more details. Both recommend to use the following command to build Swift code:</p>
<script src="https://gist.github.com/7202fa9024061bdfec37990a53ff2807.js"> </script>
<p>Once the build is over, you can use <a href="https://gist.github.com/mgrebenets/1475448a3220e9559ae2ac9ed5955629">this script</a> to create a toolchain in just few seconds.</p>
<p>Set the <code class="highlighter-rouge">SWIFT_SOURCE_PATH</code> to root of your Swift sources location and run the script from that location. Optionally customize <code class="highlighter-rouge">CONFIGURATION</code> and <code class="highlighter-rouge">BUILD_DIR</code>.</p>
<script src="https://gist.github.com/afb417f8690660ba5543ebed24e46840.js"> </script>
<hr />
<p><a href="/swift/2019/02/03/swift-refactoring-tests">Next - Tests</a></p>
https://mgrebenets.github.io/swift/2019/02/02/swift-refactoring-setup
https://mgrebenets.github.io/swift/2019/02/02/swift-refactoring---setup2019-02-02T00:00:00+00:00Swift Refactoring - Intro
<p>Introduction to a series of articles detailing how to implement a new type of <a href="https://swift.org/blog/swift-local-refactoring/">Swift Local Refactoring</a>.</p>
<!--more-->
<p>So you thought about contributing to Swift code base but never knew where and how to start? Well then, <a href="https://swift.org/blog/swift-local-refactoring/">Swift Local Refactoring</a> is a very good place to start.</p>
<p>In a series of articles I’ll take you through my experience with implementing a single local Swift refactoring action.
The refactoring action I chose as an example is “Collapse Nested If Statements”.</p>
<p>In short, it changes code like this<script src="https://gist.github.com/befa9b767c9ac8ebe33d9b51b1b61ff9.js"> </script>into this<script src="https://gist.github.com/3e516cd309e63c24796ebf754f890d9b.js"> </script>The steps:</p>
<ul>
<li><a href="/swift/2019/02/02/swift-refactoring-setup">Setup</a> Swift build environment.</li>
<li>Follow TDD approach and Write <a href="/swift/2019/02/03/swift-refactoring-tests">tests</a> first.</li>
<li><a href="/swift/2019/02/04/swift-refactoring-implementation-p1">Implement Part 1</a> refactoring action.</li>
<li><a href="/swift/2019/02/04/swift-refactoring-implementation-p2">Implement Part 2</a> refactoring action.</li>
<li><a href="/swift/2019/02/05/swift-refactoring-debugging">Debug</a> the code.</li>
<li><a href="/swift/2019/02/06/swift-refactoring-summary">Summary</a> and my thoughts on Xcode’s refactoring feature.</li>
</ul>
<h1 id="ps">P.S.</h1>
<p>You may notice that <a href="https://bugs.swift.org/browse/SR-5739">Collapse Nested If Statements</a> refactoring action is already implemented and available in latest versions of Xcode.</p>
<p>A disclaimer though, I <strong>did not</strong> implement that action, but I surely took learnings from the current implementation.</p>
<p>The major difference between an action currently available in Xcode and the one described in these articles, is that current Xcode’s version collapses only 2 statements at a time, so if you have 3 or more nested statements, you have to repeat the action to collapse them all.</p>
<p>(<em>Reload to play gifs</em>)</p>
<p><img src="https://mgrebenets.github.io/assets/images/swift-refactoring/swift-refactoring-one-at-a-time.gif" alt="Example 1" /></p>
<p>While the action implemented in these articles collapses all nested if statements at once.</p>
<p><img src="https://mgrebenets.github.io/assets/images/swift-refactoring/swift-refactoring-all-at-once.gif" alt="Example 2" /></p>
<hr />
<p><a href="/swift/2019/02/02/swift-refactoring-setup">Next - Setup</a></p>
https://mgrebenets.github.io/swift/2019/02/01/swift-refactoring-intro
https://mgrebenets.github.io/swift/2019/02/01/swift-refactoring---intro2019-02-01T00:00:00+00:00Async Swift Scripting
<p>A trick to use asynchronous callbacks in Swift scripts.</p>
<!--more-->
<p>I was really inspired by <a href="https://realm.io/news/swift-scripting/">this talk by Ayaka Nonaka</a>. I personally believe that writing scripts in Swift will become A Thing very soon. It’s already happening for Mac OS X, the upcoming Linux compiler will bring it to a next level. There’s already plenty of useful frameworks available via <a href="http://cocoapods.org">CocoaPods</a> or <a href="https://github.com/Carthage/Carthage">Carthage</a>. The only thing that’s missing is a decent package manager for Swift frameworks, something like <a href="http://brew.sh">Homebrew</a>. Swift Package Manager (SPAM) sounds like a nice name :)</p>
<p>Anyway, I wanted to use <a href="https://github.com/Alamofire/Alamofire">Alamofire</a> in a simple Swift script. So I have copy-paste-edited sample code from their GitHub page and saved it as a <code class="highlighter-rouge">Example.swift</code> file.</p>
<script src="https://gist.github.com/fecc3cfe5e1fad74cb1ef5a0565312d0.js?file=Example.swift"> </script>
<h1 id="build-alamofire">Build Alamofire</h1>
<p>To run this script I need to build Alamofire framework first. There are two ways to do that: using CocoaPods or Carthage.</p>
<p>Before I go on, it’s important to specify versions of the tools I use.</p>
<ul>
<li>Xcode 9.2</li>
<li><a href="https://github.com/CocoaPods/CocoaPods">cocoapods</a> gem version 1.4.0</li>
<li><a href="https://github.com/neonichu/Rome">cocoapods-rome</a> gem version 0.8.0</li>
<li><a href="https://github.com/Carthage/Carthage">carthage</a> version 0.28.0</li>
</ul>
<h2 id="cocoapods">CocoaPods</h2>
<p>Start with a <code class="highlighter-rouge">Podfile</code> that looks like this:</p>
<script src="https://gist.github.com/07aff08e446119223d85db40f3410028.js"> </script>
<p>Note that a file named <code class="highlighter-rouge">.swift-version</code> must exist in your working directory.
The contents of the file are “4.0” indicating Swift language version to use.</p>
<p>Next run <code class="highlighter-rouge">pod install</code> to build the frameworks.</p>
<p>%{ gist 4654b77f53c1982ceee1de7e0f73b772 %}</p>
<p>You may want to use <code class="highlighter-rouge">bundle exe pod install</code> if you installed gems with <code class="highlighter-rouge">Gemfile</code> and bundler.
Now you have <code class="highlighter-rouge">Alamofire.framework</code> ready for use in <code class="highlighter-rouge">Rome</code> directory.</p>
<h2 id="carthage">Carthage</h2>
<p>Start with a <code class="highlighter-rouge">Cartfile</code>.</p>
<script src="https://gist.github.com/b3ea270bf558ce839e59fc6f574bb12a.js"> </script>
<p>Then build.</p>
<script src="https://gist.github.com/ae936eba2cc5d36a7c1217ae51e688cf.js"> </script>
<p>Note the <code class="highlighter-rouge">--platform mac</code> option. The option is not really well documented, but it’s extremely important in this case. It tells carthage to build only Mac OS X targets, and that’s exactly what you need for Swift scripting.</p>
<p>You should now have <code class="highlighter-rouge">Alamofire.framework</code> ready for use in <code class="highlighter-rouge">Carthage/Build/Mac</code> directory.</p>
<h1 id="run">Run</h1>
<p>Time to run the script. To point Swift compiler to location of 3rd party frameworks use <code class="highlighter-rouge">-F</code> option and make sure you put it <em>before</em> the name of the Swift file.</p>
<script src="https://gist.github.com/988716a627370d78d49befa865c0b132.js"> </script>
<p>And the output is…</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Done
</code></pre></div></div>
<p>Wait a sec. How come? Well, that’s because…</p>
<h1 id="its-async">It’s Async!</h1>
<p>Yes, the callback from Alamofire is asynchronous. So the script finishes execution before it gets the response callback from Alamofire.</p>
<p>That means we have to keep the script alive and kicking until we get all async callbacks. You have probably thought about semaphores or mutexes right now. Good guess, but that won’t work. Consider this pseudo-code.</p>
<script src="https://gist.github.com/b93c9fbacdd2e42afa830777640649fe.js"> </script>
<p>The problem is that callback block (closure) is dispatched to the same queue it was originally enqueued from. This is the case for Alamofire and I’m pretty sure for most of the libraries with async callbacks.</p>
<p><code class="highlighter-rouge">WAIT(MUTEX)</code> code will lock the main queue and <code class="highlighter-rouge">UNLOCK(MUTEX)</code> line will never be executed.</p>
<h1 id="run-loop">Run Loop</h1>
<p>The answer to this particular problem is <a href="https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html">Run Loop</a>.
Each OS X or iOS application has a main run loop that keeps the app alive and reacts to all kinds of input sources, such as timer events or selector calls.
As a matter of fact, our Swift script has a run loop too, all we have to do is to keep it running until all async callbacks are received. The draft solution looks like this:</p>
<p>%{ gist 0f51d4036a48ca31f1178f14aab66e65 %}</p>
<p>In this example we get current run loop (<code class="highlighter-rouge">runLoop</code>) and then keep it running with help of <code class="highlighter-rouge">runMode(_: beforeDate:)</code> method. <a href="https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSRunLoop_Class/#//apple_ref/occ/instm/NSRunLoop/runMode:beforeDate:">According to the documentation</a> this method will return <code class="highlighter-rouge">YES</code> if the run loop ran and processed an input source or if the specified timeout value was reached; otherwise, <code class="highlighter-rouge">NO</code> if the run loop could not be started.</p>
<p>That’s the main difference from using mutexes or semaphores. <code class="highlighter-rouge">runMode</code> doesn’t block main queue, it just puts run loop to <em>sleep</em> until specified time in the future (for <code class="highlighter-rouge">0.1</code>s in this example) and while <em>asleep</em> the run loop can be <em>woken up</em> by an input source. Asynchronous call to our JSON response closure is exactly the type of input source that can wake up a sleeping run loop, so each time <code class="highlighter-rouge">runMode</code> returns <code class="highlighter-rouge">YES</code> we also check for value of <code class="highlighter-rouge">keepAlive</code> and if it’s false, that means we have handled our async callback and the script can stop its execution.</p>
<h1 id="swift-script-runner">Swift Script Runner</h1>
<p>To make the task of writing scripts with async callbacks easier, I have created a <a href="https://github.com/mgrebenets/SwiftScriptRunner">SwiftScriptRunner</a> framework. Here’s how you’d use it:</p>
<script src="https://gist.github.com/06ec6cff5ec302f179020e5f2356a89b.js"> </script>
<p>Then in <code class="highlighter-rouge">Example.swift</code>:</p>
<script src="https://gist.github.com/c3930a814d7ea58e2e26fbde8ebac469.js"> </script>
<p>You can call <code class="highlighter-rouge">lock()</code> multiple times before <code class="highlighter-rouge">wait()</code>, just make sure you balance each <code class="highlighter-rouge">lock()</code> with <code class="highlighter-rouge">unlock()</code> to avoid <em>deadlocks</em>.</p>
https://mgrebenets.github.io/swift/2015/10/08/async-swift-scripting
https://mgrebenets.github.io/swift/2015/10/08/async-swift-scripting2015-10-08T00:00:00+00:00Code Coverage for iOS (Xcode 7)
<p>Create code coverage reports for iOS unit tests using new Xcode 7 code coverage feature.</p>
<!--more-->
<h1 id="the-old-way">The Old Way</h1>
<p>I’ll start with <a href="/mobile%20ci/2015/02/08/code-coverage-for-ios">back reference to another post I wrote earlier</a>, which describes the process of getting code coverage reports using good old <code class="highlighter-rouge">gcov</code>.</p>
<p>To try out the old approach checkout <a href="https://github.com/mgrebenets/MixAndMatchTests">this repository</a> and run the scripts.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Run tests with gcov instrumentation.</span>
./test-gcov.sh
<span class="c"># Generate Cobertura coverage report (output is gcov-report.xml).</span>
./gcovr.sh
<span class="c"># Generate HTML report (output is lcov-reports).</span>
./lcov.sh
</code></pre></div></div>
<p>There’s nothing new inside those scripts, same stuff as described in the previous blog post. Run these with Xcode 6 and make sure that everything works <em>almost</em> as expected.</p>
<p>Don’t worry if you already trashed Xcode 6 and switched to Xcode 7. You still can run all the same scripts. The only problem is that <code class="highlighter-rouge">lcov.sh</code> will fail, that’s not critical but is a first sign of trouble.</p>
<p>The real problem is that there’s <em>no coverage information available for Swift code</em>. That’s because there are no <code class="highlighter-rouge">gcda</code> and <code class="highlighter-rouge">gcno</code> files generated for Swift.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># For Model.swift</span>
Model.d
Model.dia
Model.o
Model.swiftdeps
<span class="c"># For XCTestCase+GCovFlush.m</span>
XCTestCase+GCovFlush.d
XCTestCase+GCovFlush.dia
XCTestCase+GCovFlush.gcda
XCTestCase+GCovFlush.gcno
XCTestCase+GCovFlush.o
</code></pre></div></div>
<p>So Apple is slowly deprecating <code class="highlighter-rouge">gcov</code> after all.</p>
<h1 id="profile-data">Profile Data</h1>
<p>What should we use to get test coverage reports for Swift code?</p>
<p>Apple is switching to a new <a href="http://llvm.org/docs/CoverageMappingFormat.html">Coverage Mapping Format</a> and <a href="http://llvm.org/docs/CommandGuide/llvm-profdata.html">Profile Data format</a>.</p>
<p>LLVM toolset comes with a number of tools to work with profile data format, specifically <a href="http://llvm.org/docs/CommandGuide/llvm-cov.html">llvm-cov</a>. This tool can analyze profile data and instrumented app binary and emit code coverage data in more human-friendly format. But first we need to get profile data generated and app binary instrumented.</p>
<h2 id="gather-profile-data">Gather Profile Data</h2>
<p>With Xcode 7 it’s a much easier task. Instead of specifying 3 build settings <code class="highlighter-rouge">xcodebuild</code> now has a single flag called <code class="highlighter-rouge">-enableCodeCoverage</code> and all you have to do is set it to <code class="highlighter-rouge">YES</code>.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>xcodebuild <span class="nb">test</span> <span class="se">\</span>
<span class="nt">-project</span> MixAndMatchTests.xcodeproj<span class="se">\</span>
<span class="nt">-scheme</span> MixAndMatchTests <span class="se">\</span>
<span class="nt">-sdk</span> iphonesimulator <span class="se">\</span>
<span class="nt">-configuration</span> Debug <span class="se">\</span>
<span class="nt">-enableCodeCoverage</span> YES
</code></pre></div></div>
<p>The <code class="highlighter-rouge">test-profdata.sh</code> from GitHub repository is more detailed version of the script below. Feel free to just run <code class="highlighter-rouge">./test-profdata.sh</code>.</p>
<p>Setting <code class="highlighter-rouge">-enableCodeCoverage</code> flag to <code class="highlighter-rouge">YES</code> is essentially the same as checking the “Gather coverage data” checkbox in Xcode scheme settings.</p>
<p><img src="https://mgrebenets.github.io/assets/images/xcode-code-coverage/gather-coverage-data.png" alt="Gather coverage data" /></p>
<h2 id="convert-profile-data">Convert Profile Data</h2>
<p>OK, so now profile data is generated and we have an instrumented binary available at out disposal.
The question is where do we find the binary and profile data?</p>
<p>Both instrumented binary and profile data are sitting inside derived data directory. We can get derived data path from build settings.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">BUILD_SETTINGS</span><span class="o">=</span>build-settings.txt
<span class="c"># Get build settings</span>
xcodebuild <span class="nt">-project</span> MixAndMatchTests.xcodeproj <span class="se">\</span>
<span class="nt">-scheme</span> MixAndMatchTests <span class="se">\</span>
<span class="nt">-sdk</span> iphonesimulator <span class="se">\</span>
<span class="nt">-configuration</span> Debug <span class="se">\</span>
<span class="nt">-showBuildSettings</span> <span class="o">></span> <span class="k">${</span><span class="nv">BUILD_SETTINGS</span><span class="k">}</span>
<span class="c"># Project Temp Root ends up with /Build/Intermediates/</span>
<span class="nv">PROJECT_TEMP_ROOT</span><span class="o">=</span><span class="k">$(</span><span class="nb">grep</span> <span class="nt">-m1</span> PROJECT_TEMP_ROOT <span class="k">${</span><span class="nv">BUILD_SETTINGS</span><span class="k">}</span> | cut <span class="nt">-d</span><span class="o">=</span> <span class="nt">-f2</span> | xargs<span class="k">)</span>
</code></pre></div></div>
<p>Let’s look for profile data first. From <a href="https://forums.developer.apple.com/thread/4097">Apple forums</a> we know that we are looking for <code class="highlighter-rouge">Coverage.profdata</code> file, so let’s just find it.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">PROFDATA</span><span class="o">=</span><span class="k">$(</span>find <span class="k">${</span><span class="nv">PROJECT_TEMP_ROOT</span><span class="k">}</span> <span class="nt">-name</span> <span class="s2">"Coverage.profdata"</span><span class="k">)</span>
</code></pre></div></div>
<p>Looking for binary is similar, we use the fact that it’s sitting inside app bundle, e.g. <code class="highlighter-rouge">MixAndMatchTests.app/MixAndMatchTests</code>.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">BINARY</span><span class="o">=</span><span class="k">$(</span>find <span class="k">${</span><span class="nv">PROJECT_TEMP_ROOT</span><span class="k">}</span> <span class="nt">-path</span> <span class="s2">"*MixAndMatchTests.app/MixAndMatchTests"</span><span class="k">)</span>
</code></pre></div></div>
<p><em>Note:</em> You shouldn’t use <code class="highlighter-rouge">-derivedDataPath</code> or CONFIGURATION_BUILD_DIR option when running <code class="highlighter-rouge">xcodebuild</code> for testing. Having build directory and derived data directory in custom locations will cause some problems for open source tools which I’ll talk later in this article.</p>
<p>OK, so we got both path to binary and path to profile data, let’s feed those to <code class="highlighter-rouge">llvm-cov</code> now.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>xcrun llvm-cov show <span class="se">\</span>
<span class="nt">-instr-profile</span> <span class="k">${</span><span class="nv">PROFDATA</span><span class="k">}</span> <span class="se">\</span>
<span class="k">${</span><span class="nv">BINARY</span><span class="k">}</span>
</code></pre></div></div>
<p>What you see now is a detailed coverage data. To get a short summary, let’s use <code class="highlighter-rouge">report</code> option instead of <code class="highlighter-rouge">show</code>.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>xcrun llvm-cov report <span class="se">\</span>
<span class="nt">-instr-profile</span> <span class="k">${</span><span class="nv">PROFDATA</span><span class="k">}</span> <span class="se">\</span>
<span class="k">${</span><span class="nv">BINARY</span><span class="k">}</span>
<span class="c"># Output</span>
Filename Regions Miss Cover Functions Executed
<span class="nt">-----------------------------------------------------------------------</span>
...usr/include/MacTypes.h 0 0 nan% 0 nan%
...sr/include/objc/objc.h 0 0 nan% 0 nan%
...r/include/sys/_types.h 0 0 nan% 0 nan%
...tchTests/AppDelegate.m 17 6 64.71% 7 42.86%
...DetailViewController.m 8 8 0.00% 4 0.00%
...MasterViewController.m 30 25 16.67% 10 40.00%
...MatchTests/Model.swift 1 0 100.00% 1 100.00%
...MatchTests/ObjCModel.m 1 0 100.00% 1 100.00%
...ixAndMatchTests/main.m 3 0 100.00% 1 100.00%
<span class="nt">-----------------------------------------------------------------------</span>
TOTAL 60 39 35.00% 24 41.67%
</code></pre></div></div>
<p>Yes! A nice colorized (at least for me) output! Check <code class="highlighter-rouge">llvm-cov-show.sh</code> script for a cleaner version of the shell script.</p>
<p>For now please ignore the fact that some system and test files are included in report, we will filter them out later. In the meantime we have achieved our first goal and converted profile data into some kind of test coverage report.</p>
<h1 id="gcov-report">GCov Report</h1>
<p>So we have a coverage report, but how useful is it? Well, it’s not much useful as it is.</p>
<p>The main reason for generating coverage report is to be able to feed it to your favorite CI server and enjoy a nicely formatted and browsable version of it. Ever more, configure your build jobs to be marked as stable, unstable or failed if test coverage is below a certain threshold.</p>
<p>As it happens, none of the popular CI servers seem to have plugins for parsing Profile Data yet. So we have to convert it to something that CI servers can digest, such as <a href="http://cobertura.github.io/cobertura/">Cobertura</a> coverage report.</p>
<p>LLVM toolset doesn’t support such conversion, but there is a <a href="http://blog.llvm.org/2014/11/llvm-weekly-44-nov-3rd-2014.html">glimpse</a> of <a href="http://reviews.llvm.org/rL220915">hope</a>.</p>
<p>A brief search lead me to <a href="http://stackoverflow.com/questions/31040594/how-to-generate-gcov-file-from-llvm-cov">this Stack Overflow page</a> with further reference to <a href="https://github.com/venmo/slather">Slather</a> ruby gem. Slather is designed to take care of all your testing tasks including generating coverage report. In this article I’ll only use it for converting profile data to Cobertura format.</p>
<p>There is a pull request <a href="https://github.com/venmo/slather/pull/92">#92</a> (still open at the moment of updating this post) with changes to support this new feature. Let’s build this gem from source and see if it’s up to job.</p>
<p>First we need to create a custom Gemfile.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Gemfile.</span>
<span class="n">source</span> <span class="s1">'https://rubygems.org'</span>
<span class="n">gem</span> <span class="s1">'slather'</span><span class="p">,</span> <span class="ss">:git</span> <span class="o">=></span> <span class="s2">"https://github.com/viteinfinite/slather.git"</span><span class="p">,</span> <span class="ss">:branch</span> <span class="o">=></span> <span class="s2">"feature-profdata"</span>
</code></pre></div></div>
<p>Then install Slather from this branch.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bundle install
</code></pre></div></div>
<p>And we are good to go.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bundle <span class="nb">exec </span>slather coverage <span class="se">\</span>
<span class="nt">--input-format</span> profdata <span class="se">\</span>
<span class="nt">--cobertura-xml</span> <span class="se">\</span>
<span class="nt">--ignore</span> <span class="s2">"../**/*/Xcode*"</span> <span class="se">\</span>
<span class="nt">--output-directory</span> slather-report <span class="se">\</span>
<span class="nt">--scheme</span> MixAndMatchTests <span class="se">\</span>
MixAndMatchTests.xcodeproj
</code></pre></div></div>
<p>Now check <code class="highlighter-rouge">slather-report</code> directory and you got your <code class="highlighter-rouge">cobertura.xml</code> file ready to be fed to CI server plugin! There are options other than <code class="highlighter-rouge">--cobertura-xml</code>, such as <code class="highlighter-rouge">--simple-output</code>, <code class="highlighter-rouge">--html</code> and others.</p>
<p>Let’s use simple output option and compare it to Xcode output.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>MixAndMatchTests/AppDelegate.m: 16 of 33 lines <span class="o">(</span>48.48%<span class="o">)</span>
MixAndMatchTests/DetailViewController.m: 0 of 23 lines <span class="o">(</span>0.00%<span class="o">)</span>
MixAndMatchTests/MasterViewController.m: 19 of 63 lines <span class="o">(</span>30.16%<span class="o">)</span>
MixAndMatchTests/Model.swift: 3 of 3 lines <span class="o">(</span>100.00%<span class="o">)</span>
MixAndMatchTests/ObjCModel.m: 3 of 3 lines <span class="o">(</span>100.00%<span class="o">)</span>
MixAndMatchTests/main.m: 5 of 5 lines <span class="o">(</span>100.00%<span class="o">)</span>
Test Coverage: 35.38%
</code></pre></div></div>
<p><img src="https://mgrebenets.github.io/assets/images/xcode-code-coverage/xcode-coverage.png" alt="Xcode Coverage Report" /></p>
<h1 id="fastlane">Fastlane</h1>
<p>If you are a fan of <a href="https://github.com/fastlane/fastlane">fastlane</a> (I am), then have a look at project <code class="highlighter-rouge">Fastfile</code>. It includes a basic example of how you can use <code class="highlighter-rouge">scan</code> and <code class="highlighter-rouge">slather</code> actions to get coverage reports.</p>
<h1 id="caveats">Caveats</h1>
<p>I’m adding this section as an update for this post.
There’s a number of things you have to do to have proper coverage for Swift code.</p>
<h2 id="enable-testability">Enable Testability</h2>
<p>First of all enable testability for the <em>main</em> target. This is controlled by <code class="highlighter-rouge">ENABLE_TESTABILITY</code> build setting that has to be set to <code class="highlighter-rouge">YES</code>. In fact, enabling this flag for unit tests target causes no trouble. This flag will allow you to import Swift code from main target in unit tests code in this way:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">@testable</span> <span class="kd">import</span> <span class="kt">MixAndMatchTests</span>
</code></pre></div></div>
<h2 id="dont-include-main-target-files-to-unit-tests-target">Don’t include main target files to Unit Tests target</h2>
<p>This is another mandatory step to get coverage for Swift code. Otherwise you will get a lot of warnings like this in the test log:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># For Swift files</span>
objc[7995]: Class _TtC14MixAndMatchTests4Model is implemented <span class="k">in </span>both
<derived-data-path>/MixAndMatchTests.app/MixAndMatchTests and
<derived-data-path>/MixAndMatchTests.xctest/MixAndMatchTests.
One of the two will be used. Which one is undefined.
<span class="c"># For Objective-C files</span>
objc[7995]: Class ObjCModel is implemented <span class="k">in </span>both
<derived-data-path>/MixAndMatchTests.app/MixAndMatchTests and
<derived-data-path>/MixAndMatchTests.xctest/MixAndMatchTests.
One of the two will be used. Which one is undefined.
</code></pre></div></div>
<p>This is not only annoying, but also will result in useless code coverage reports generated.</p>
<h2 id="dont-test-swift-code-using-objective-c-code">Don’t test Swift code using Objective-C code</h2>
<p>This is rather a consequence of first two changes. Since Swift files are not part of test target, there is no generated code for these Swift files in the Swift umbrella header, and that means you can’t use this Swift code from Objective-C.</p>
<p>So you have to <strong>test Swift with Swift</strong> to get coverage reports.</p>
<h2 id="avoid-using-legacy-and-new-coverage-formats-together">Avoid using legacy and new coverage formats together</h2>
<p>If you coverage results look totally off and you get tons of message in test log, that look like this:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ObjectiveC.gcda: cannot merge previous GCDA file: corrupt arc tag <span class="o">(</span><some hex address><span class="o">)</span>
</code></pre></div></div>
<p>Then you are most-likely mixing both test approaches together, which is not recommended.
Make sure you have disabled legacy flags <code class="highlighter-rouge">GCC_GENERATE_TEST_COVERAGE_FILES</code> and <code class="highlighter-rouge">GCC_INSTRUMENT_PROGRAM_FLOW_ARCS</code>, when you want to use Profile Data. Have a look at these discussions: <a href="http://stackoverflow.com/questions/33289254/xcode-7-0-and-7-1-code-coverage-turned-on-unit-test-crash-cannot-merge-previo">1</a>, <a href="http://stackoverflow.com/questions/22519530/dozens-of-profilinginvalid-arc-tag-when-running-code-coverage-in-xcode-5">2</a>, <a href="https://forums.developer.apple.com/thread/9765">3</a>.</p>
<p>Thanks to <a href="https://github.com/venmo/slather/pull/99#issuecomment-151502550">@GUL-</a> for help with this tricky stuff.</p>
https://mgrebenets.github.io/mobile%20ci/2015/09/21/code-coverage-for-ios-xcode-7
https://mgrebenets.github.io/mobile%20ci/2015/09/21/code-coverage-for-ios-xcode-72015-09-21T00:00:00+00:00Equatable NSObject With Swift 2
<p>[<font color="red">Swift 2.0</font>]</p>
<p>Subtle differences in implementing <code class="highlighter-rouge">Equatable</code> protocol for <code class="highlighter-rouge">NSObject</code> subclasses in Swift 1.2 and 2.0.</p>
<!--more-->
<blockquote>
<p>The best way to read this post is in Xcode playground, so go ahead and <a href="https://mgrebenets.github.io/assets/playgrounds/NSObjectEquatable.playground.zip">Download Playground</a></p>
</blockquote>
<h1 id="equatable">Equatable</h1>
<p>Instances of the type that conform to <code class="highlighter-rouge">Equatable</code> protocol can be compared for value equality using operators <code class="highlighter-rouge">==</code> and <code class="highlighter-rouge">!=</code>.</p>
<p>When adopting <code class="highlighter-rouge">Equatable</code>, only the <code class="highlighter-rouge">==</code> operator is required to be
implemented. The standard library provides an implementation for <code class="highlighter-rouge">!=</code>.</p>
<p>This was pretty much a copy-paste from documentation. Let’s try it in practice.</p>
<h2 id="swift-structs">Swift Structs</h2>
<p>If you just have a simple struct, you will not be able to compare two instances of it.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">struct</span> <span class="kt">CardStruct</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">rank</span><span class="p">:</span> <span class="kt">Int</span>
<span class="nf">init</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="kt">Int</span><span class="p">)</span> <span class="p">{</span>
<span class="k">self</span><span class="o">.</span><span class="n">rank</span> <span class="o">=</span> <span class="n">rank</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Uncomment next line to see the following error:</p>
<blockquote>
<p>Error: Binary operator <code class="highlighter-rouge">==</code> cannot be applied to two CardStruct operands</p>
</blockquote>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//print(CardStruct(rank: 4) == CardStruct(rank: 4))</span>
</code></pre></div></div>
<p>To fix it, make sure that your structure conforms to <code class="highlighter-rouge">Equatable</code> protocol first.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">struct</span> <span class="kt">EquatableCardStruct</span><span class="p">:</span> <span class="kt">Equatable</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">rank</span><span class="p">:</span> <span class="kt">Int</span>
<span class="nf">init</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="kt">Int</span><span class="p">)</span> <span class="p">{</span>
<span class="k">self</span><span class="o">.</span><span class="n">rank</span> <span class="o">=</span> <span class="n">rank</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Then implement <code class="highlighter-rouge">==</code> operator as prescribed by <code class="highlighter-rouge">Equatable</code>.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">func</span> <span class="o">==</span><span class="p">(</span><span class="nv">lhs</span><span class="p">:</span> <span class="kt">EquatableCardStruct</span><span class="p">,</span> <span class="nv">rhs</span><span class="p">:</span> <span class="kt">EquatableCardStruct</span><span class="p">)</span> <span class="o">-></span> <span class="kt">Bool</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">lhs</span><span class="o">.</span><span class="n">rank</span> <span class="o">==</span> <span class="n">rhs</span><span class="o">.</span><span class="n">rank</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Now two instances of <code class="highlighter-rouge">EquatableCardStruct</code> are equal if they have the same rank.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">print</span><span class="p">(</span><span class="kt">EquatableCardStruct</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">5</span><span class="p">)</span> <span class="o">==</span> <span class="kt">EquatableCardStruct</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">5</span><span class="p">))</span>
<span class="c1">// true</span>
<span class="nf">print</span><span class="p">(</span><span class="kt">EquatableCardStruct</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">5</span><span class="p">)</span> <span class="o">==</span> <span class="kt">EquatableCardStruct</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">3</span><span class="p">))</span>
<span class="c1">// false</span>
</code></pre></div></div>
<p>Since collection types are equatable by default, you can equate two arrays of <code class="highlighter-rouge">EquatableCardStruct</code>s as well with no additional effort.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">equatableCardStructs1</span> <span class="o">=</span> <span class="p">[</span><span class="kt">EquatableCardStruct</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">1</span><span class="p">),</span> <span class="kt">EquatableCardStruct</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">2</span><span class="p">),</span> <span class="kt">EquatableCardStruct</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">3</span><span class="p">)]</span>
<span class="k">let</span> <span class="nv">equatableCardStructs2</span> <span class="o">=</span> <span class="p">[</span><span class="kt">EquatableCardStruct</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">1</span><span class="p">),</span> <span class="kt">EquatableCardStruct</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">2</span><span class="p">),</span> <span class="kt">EquatableCardStruct</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">3</span><span class="p">)]</span>
<span class="nf">print</span><span class="p">(</span><span class="n">equatableCardStructs1</span> <span class="o">==</span> <span class="n">equatableCardStructs2</span><span class="p">)</span>
<span class="c1">// true</span>
<span class="nf">print</span><span class="p">([</span><span class="kt">EquatableCardStruct</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">2</span><span class="p">)]</span> <span class="o">==</span> <span class="p">[</span><span class="kt">EquatableCardStruct</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">5</span><span class="p">)])</span>
<span class="c1">// false</span>
</code></pre></div></div>
<h2 id="nsobject-subclass">NSObject Subclass</h2>
<p>So it all works well for structs, but what if you are dealing with <code class="highlighter-rouge">NSObject</code> subclass? Let’s declare one to start with.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="kt">CardObject</span><span class="p">:</span> <span class="kt">NSObject</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">rank</span><span class="p">:</span> <span class="kt">Int</span>
<span class="nf">init</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="kt">Int</span><span class="p">)</span> <span class="p">{</span>
<span class="k">self</span><span class="o">.</span><span class="n">rank</span> <span class="o">=</span> <span class="n">rank</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Now pay close attention to next line.</p>
<p>With Swift 1.2 (Xcode 6.3.2) it will work fine, uncomment and see for yourself.</p>
<p>With Swift 2.0 (Xcode 7) it will produce a compiler error.</p>
<blockquote>
<p>Error: Redundant conformance of ‘CardObject’ to protocol ‘Equatable’</p>
</blockquote>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// This is "line 93" for future reference</span>
<span class="c1">//extension CardObject: Equatable {}</span>
</code></pre></div></div>
<p>Usual implementation for <code class="highlighter-rouge">==</code>.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">func</span> <span class="o">==</span><span class="p">(</span><span class="nv">left</span><span class="p">:</span> <span class="kt">CardObject</span><span class="p">,</span> <span class="nv">right</span><span class="p">:</span> <span class="kt">CardObject</span><span class="p">)</span> <span class="o">-></span> <span class="kt">Bool</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">left</span><span class="o">.</span><span class="n">rank</span> <span class="o">==</span> <span class="n">right</span><span class="o">.</span><span class="n">rank</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Now let’s try to equate some objects.</p>
<p>Look at the next two lines while using Swift 1.2. Notice that commenting and uncommenting line <code class="highlighter-rouge">93</code> doesn’t change the behavior. Despite the fact that <code class="highlighter-rouge">CardObject</code> is not declared to conform to <code class="highlighter-rouge">Equatable</code>, the code still works. Most likely this is due to the fact that all code is in one playground, this <code class="highlighter-rouge">==</code> operator would most definitely fail if it were in another file.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">print</span><span class="p">(</span><span class="kt">CardObject</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">5</span><span class="p">)</span> <span class="o">==</span> <span class="kt">CardObject</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">5</span><span class="p">))</span>
<span class="c1">// true</span>
<span class="nf">print</span><span class="p">(</span><span class="kt">CardObject</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">5</span><span class="p">)</span> <span class="o">==</span> <span class="kt">CardObject</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">3</span><span class="p">))</span>
<span class="c1">// false</span>
</code></pre></div></div>
<p>This is where we can verify previous statement. Again, toggle comments on line <code class="highlighter-rouge">93</code> to see how result of the next <code class="highlighter-rouge">==</code> changes.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">cardObjects1</span> <span class="o">=</span> <span class="p">[</span><span class="kt">CardObject</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">1</span><span class="p">),</span> <span class="kt">CardObject</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">2</span><span class="p">),</span> <span class="kt">CardObject</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">3</span><span class="p">)]</span>
<span class="k">let</span> <span class="nv">cardObjects2</span> <span class="o">=</span> <span class="p">[</span><span class="kt">CardObject</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">1</span><span class="p">),</span> <span class="kt">CardObject</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">2</span><span class="p">),</span> <span class="kt">CardObject</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">3</span><span class="p">)]</span>
<span class="nf">print</span><span class="p">(</span><span class="n">cardObjects1</span> <span class="o">==</span> <span class="n">cardObjects2</span><span class="p">)</span>
<span class="c1">// false when line 93 commented</span>
<span class="c1">// true otherwise</span>
</code></pre></div></div>
<p>So when <code class="highlighter-rouge">CardObject</code> is conforming to <code class="highlighter-rouge">Equatable</code> explicitly equating collections works as expected, otherwise it doesn’t, most likely <code class="highlighter-rouge">isEqual:</code> method of <code class="highlighter-rouge">NSObject</code> is used, which compares object hashes.</p>
<p>But give it a try with Swift 2.0 now. First of all you will be told that <code class="highlighter-rouge">NSObject</code> already conforms to <code class="highlighter-rouge">Equatable</code>, so line <code class="highlighter-rouge">93</code> has redundand conformance. Once you comment that line <code class="highlighter-rouge">cardObjects1</code> and <code class="highlighter-rouge">cardObjects2</code> are not equal any more, because it’s all back to comparing hash values now.</p>
<p>In order to fix this problem, you will have to override <code class="highlighter-rouge">isEqual</code> method.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="kt">EquatableCardObject</span><span class="p">:</span> <span class="kt">NSObject</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">rank</span><span class="p">:</span> <span class="kt">Int</span>
<span class="nf">init</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="kt">Int</span><span class="p">)</span> <span class="p">{</span>
<span class="k">self</span><span class="o">.</span><span class="n">rank</span> <span class="o">=</span> <span class="n">rank</span>
<span class="p">}</span>
<span class="k">override</span> <span class="kd">func</span> <span class="nf">isEqual</span><span class="p">(</span><span class="nv">object</span><span class="p">:</span> <span class="kt">AnyObject</span><span class="p">?)</span> <span class="o">-></span> <span class="kt">Bool</span> <span class="p">{</span>
<span class="k">if</span> <span class="k">let</span> <span class="nv">rhs</span> <span class="o">=</span> <span class="n">object</span> <span class="k">as?</span> <span class="kt">EquatableCardObject</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">rank</span> <span class="o">==</span> <span class="n">rhs</span><span class="o">.</span><span class="n">rank</span>
<span class="p">}</span>
<span class="k">return</span> <span class="kc">false</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>This class is almost identical to <code class="highlighter-rouge">CardObject</code>, except for the <code class="highlighter-rouge">isEqual</code> method. Another difference is that there’s no global <code class="highlighter-rouge">==</code> implemented to compare 2 instances of <code class="highlighter-rouge">EquatableCardObject</code>.</p>
<p>Nevertheless the comparison works.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">print</span><span class="p">(</span><span class="kt">EquatableCardObject</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">5</span><span class="p">)</span> <span class="o">==</span> <span class="kt">EquatableCardObject</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">5</span><span class="p">))</span>
<span class="c1">// true</span>
<span class="nf">print</span><span class="p">(</span><span class="kt">EquatableCardObject</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">5</span><span class="p">)</span> <span class="o">==</span> <span class="kt">EquatableCardObject</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">3</span><span class="p">))</span>
<span class="c1">// false</span>
</code></pre></div></div>
<p>And not just for single values, but for arrays as well.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">equatableCardObjects1</span> <span class="o">=</span> <span class="p">[</span><span class="kt">EquatableCardObject</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">1</span><span class="p">),</span> <span class="kt">EquatableCardObject</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">2</span><span class="p">),</span> <span class="kt">EquatableCardObject</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">3</span><span class="p">)]</span>
<span class="k">let</span> <span class="nv">equatableCardObjects2</span> <span class="o">=</span> <span class="p">[</span><span class="kt">EquatableCardObject</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">1</span><span class="p">),</span> <span class="kt">EquatableCardObject</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">2</span><span class="p">),</span> <span class="kt">EquatableCardObject</span><span class="p">(</span><span class="nv">rank</span><span class="p">:</span> <span class="mi">3</span><span class="p">)]</span>
<span class="nf">print</span><span class="p">(</span><span class="n">equatableCardObjects1</span> <span class="o">==</span> <span class="n">equatableCardObjects2</span><span class="p">)</span>
<span class="c1">// true</span>
</code></pre></div></div>
<h1 id="summary">Summary</h1>
<p>This sure looks like a breaking change from 1.2 to 2.0. I wonder if that’s intentional or not. It does look strange that writing implementation of <code class="highlighter-rouge">==</code> operator doesn’t actually change anything, in fact, it is never even called for <code class="highlighter-rouge">NSObject</code> subclasses, but then the whole conformance to <code class="highlighter-rouge">Equatable</code> is broken.</p>
https://mgrebenets.github.io/swift/2015/06/21/equatable-nsobject-with-swift-2
https://mgrebenets.github.io/swift/2015/06/21/equatable-nsobject-with-swift-22015-06-21T00:00:00+00:00JIRA ID in Git Commit Messages
<p>A quick tip on how to automatically add <a href="http://en.wikipedia.org/wiki/JIRA">JIRA</a> ID in each git commit message.</p>
<!--more-->
<h1 id="what--why">What & Why</h1>
<p><a href="https://translate.google.com.au/?ie=UTF-8&hl=en&client=tw-ob#auto/en/JIRA">JIRA</a> or not, if you use some kind of issue tracker and want to get a certain level of integration with Git, it is a good idea to include ticket IDs into commit message.</p>
<p>A couple of assumptions then.</p>
<p>Ticket IDs are in the <code class="highlighter-rouge">PROJ-1234</code> format, where <code class="highlighter-rouge">PROJ</code> is the short reference to the project (usually uppercase) at least 1 character long, and <code class="highlighter-rouge">1234</code> represents a ticket number.</p>
<p>Let’s also assume that you are naming your branches in the following way: <code class="highlighter-rouge">prefix/JIRA-1234-optional-description</code>. Prefix is arbitrary and optional as well. Usual examples are <code class="highlighter-rouge">feature/</code> or <code class="highlighter-rouge">bugfix/</code>. So now you are working on the branch named like this and you want all your commits to have <code class="highlighter-rouge">[JIRA-123]</code> added at the start of commit message, for example</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span>JIRA-123] Fix the crash
</code></pre></div></div>
<h1 id="how">How</h1>
<p>You should use Git hooks to achieve the goal.</p>
<p>There are subtle differences when doing it for a main git repo and for submodules.</p>
<h2 id="main-repo">Main Repo</h2>
<p>Git hooks are located in <code class="highlighter-rouge">.git/hooks/</code>. The particular hook you are interested in is commit message hook. Copy a default sample <code class="highlighter-rouge">.git/hooks/commit-msg.sample</code> and name it <code class="highlighter-rouge">.git/hooks/commit-msg</code>.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cp .git/hooks/commit-msg.sample .git/hooks/commit-msg
</code></pre></div></div>
<p>Now edit <code class="highlighter-rouge">commit-msg</code> and remove the example code from it.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Remove this code.</span>
<span class="nb">test</span> <span class="s2">""</span> <span class="o">=</span> <span class="s2">"</span><span class="k">$(</span><span class="nb">grep</span> <span class="s1">'^Signed-off-by: '</span> <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span> |
sort | uniq <span class="nt">-c</span> | sed <span class="nt">-e</span> <span class="s1">'/^[ ]*1[ ]/d'</span><span class="k">)</span><span class="s2">"</span> <span class="o">||</span> <span class="o">{</span>
<span class="nb">echo</span> <span class="o">></span>&2 Duplicate Signed-off-by lines.
<span class="nb">exit </span>1
<span class="o">}</span>
</code></pre></div></div>
<p>Then add this code at the end of the file.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># If commit message is a fixup message, ignore it.</span>
<span class="o">[[</span> <span class="nt">-n</span> <span class="s2">"</span><span class="k">$(</span><span class="nb">cat</span> <span class="nv">$1</span> | <span class="nb">grep</span> <span class="s1">'fixup!'</span><span class="k">)</span><span class="s2">"</span> <span class="o">]]</span> <span class="o">&&</span> <span class="nv">FIXUP</span><span class="o">=</span><span class="s2">"YES"</span>
<span class="nv">TICKET</span><span class="o">=</span><span class="k">$(</span>git symbolic-ref HEAD | rev | cut <span class="nt">-d</span>/ <span class="nt">-f1</span> | rev | <span class="nb">grep</span> <span class="nt">-o</span> <span class="nt">-E</span> <span class="s2">"[A-Z]+-[0-9]+"</span><span class="k">)</span>
<span class="k">if</span> <span class="o">[[</span> <span class="nt">-n</span> <span class="s2">"</span><span class="k">${</span><span class="nv">TICKET</span><span class="k">}</span><span class="s2">"</span> <span class="o">&&</span> <span class="nt">-z</span> <span class="s2">"</span><span class="k">${</span><span class="nv">FIXUP</span><span class="k">}</span><span class="s2">"</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then
</span>sed <span class="nt">-i</span>.bak <span class="nt">-e</span> <span class="s2">"1s/^/[</span><span class="k">${</span><span class="nv">TICKET</span><span class="k">}</span><span class="s2">] /"</span> <span class="nv">$1</span>
<span class="k">fi</span>
</code></pre></div></div>
<p>Some explanation might be helpful. First the line that sets the <code class="highlighter-rouge">TICKET</code> variable.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">TICKET</span><span class="o">=</span><span class="k">$(</span>git symbolic-ref HEAD | rev | cut <span class="nt">-d</span>/ <span class="nt">-f1</span> | rev | <span class="nb">grep</span> <span class="nt">-o</span> <span class="nt">-E</span> <span class="s2">"[A-Z]+-[0-9]+"</span> | head <span class="nt">-n1</span><span class="k">)</span>
</code></pre></div></div>
<p>The <code class="highlighter-rouge">git symbolic-ref HEAD</code> commands gets the name of the current git branch, which may look like <code class="highlighter-rouge">refs/heads/feature/JIRA-1234-description</code>.</p>
<p>Then <code class="highlighter-rouge">rev</code> turns it into <code class="highlighter-rouge">noitpircsed-4321-ARIJ/erutaef/sdaeh/sfer</code>.</p>
<p>When the branch name is reversed, the last component is now first in the string, and that’s exactly the component we are after, so get it with <code class="highlighter-rouge">cut</code> command using <code class="highlighter-rouge">/</code> as a separator. <code class="highlighter-rouge">cut -d/ -f1</code> splits by <code class="highlighter-rouge">/</code> and takes <code class="highlighter-rouge">1</code>st component. The result is <code class="highlighter-rouge">noitpircsed-4321-ARIJ</code>.</p>
<p>Next reverse it back into <code class="highlighter-rouge">JIRA-1234-description</code> and at this moment we expect the string to start with JIRA ID. JIRA ID by itself is more than one capital letter, then dash <code class="highlighter-rouge">-</code> and then more than one digit, this is exactly what <code class="highlighter-rouge">[A-Z]+-[0-9]+</code> regex describes. If your project name is different, you can adjust regex. <code class="highlighter-rouge">grep</code> with the given regex and <code class="highlighter-rouge">-o</code> option will return the match <code class="highlighter-rouge">o</code>nly, which is <code class="highlighter-rouge">JIRA-1234</code>. Finally <code class="highlighter-rouge">head -n1</code> will take only the first match, that’s in case you have more than one JIRA ID in the branch name.</p>
<p>If the <code class="highlighter-rouge">TICKET</code> has a value, then modify current commit message by adding value of <code class="highlighter-rouge">TICKET</code> at the start of it. The commit message is actually a file and that file can be accessed via bash script <code class="highlighter-rouge">$1</code> variable. <code class="highlighter-rouge">sed</code> is used to find a beginning of the line <code class="highlighter-rouge">^</code> and add <code class="highlighter-rouge">[${TICKET}] </code>, but only once, which is controlled by <code class="highlighter-rouge">1</code> before before the <code class="highlighter-rouge">s/</code> path: <code class="highlighter-rouge">1s/^/[${TICKET}] /</code>.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="o">[[</span> <span class="nt">-n</span> <span class="s2">"</span><span class="k">${</span><span class="nv">TICKET</span><span class="k">}</span><span class="s2">"</span> <span class="o">&&</span> <span class="nt">-z</span> <span class="s2">"</span><span class="k">${</span><span class="nv">FIXUP</span><span class="k">}</span><span class="s2">"</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then
</span>sed <span class="nt">-i</span>.bak <span class="nt">-e</span> <span class="s2">"1s/^/[</span><span class="k">${</span><span class="nv">TICKET</span><span class="k">}</span><span class="s2">] /"</span> <span class="nv">$1</span>
<span class="k">fi</span>
</code></pre></div></div>
<p>And last thing to explain is <code class="highlighter-rouge">FIXUP</code> variable. If you are using commands like <code class="highlighter-rouge">git commit -a --fixup HEAD</code> then <code class="highlighter-rouge">fixup!</code> string is added to the start of commit message automatically. But the problem is that <code class="highlighter-rouge">fixup!</code> is added <em>before</em> commit hook is called, so you end up with commit messages like this.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span>JIRA-1234] fixup! <span class="o">[</span>JIRA-1234] Commit message
</code></pre></div></div>
<p>That’s not what you want if you want to take advantage of autosquasing feature. This is why there is this bit of code at the start of the script.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[[</span> <span class="nt">-n</span> <span class="s2">"</span><span class="k">$(</span><span class="nb">grep</span> <span class="s1">'fixup!'</span> <span class="nv">$1</span><span class="k">)</span><span class="s2">"</span> <span class="o">]]</span> <span class="o">&&</span> <span class="nv">FIXUP</span><span class="o">=</span><span class="s2">"YES"</span>
</code></pre></div></div>
<p>It searches for <code class="highlighter-rouge">fixup!</code> string in commit message file <code class="highlighter-rouge">$1</code> and if a match is found sets <code class="highlighter-rouge">FIXUP</code> variable to <code class="highlighter-rouge">"YES"</code>.</p>
<h2 id="submodules">Submodules</h2>
<p>OK, so now you have commit hook working for main repo, but what if you also have a number of in-house submodules and work with them in the same workspace? In that case you’d want to have the same hooks for submodules.</p>
<p>The problem is that hooks for submodules are located in different directories. Submodules git configuration and other files are located in <code class="highlighter-rouge">.git/modules</code>. The simplest way would be to find all <code class="highlighter-rouge">hooks</code> directories inside <code class="highlighter-rouge">.git/modules</code> and copy commit message hook file we created previously. This will works if you are OK to have same hooks for main repo and submodules, and none of the submodules paths contains <code class="highlighter-rouge">hooks</code> string. The script below does exactly what I described in English just now. <code class="highlighter-rouge">smh</code> here stands for <code class="highlighter-rouge">submodule hooks</code>.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for </span>smh <span class="k">in</span> <span class="k">$(</span>find .git/modules <span class="nt">-name</span> hooks<span class="k">)</span><span class="p">;</span> <span class="k">do</span> <span class="se">\</span>
cp <span class="nt">-f</span> .git/hooks/commit-msg <span class="k">${</span><span class="nv">smh</span><span class="k">}</span>/<span class="p">;</span> <span class="se">\</span>
<span class="k">done</span>
</code></pre></div></div>
<p>Don’t forget to update submodule hooks when you change the main repo hooks.</p>
https://mgrebenets.github.io/tools/2015/06/04/jira-id-in-git-commit-messages
https://mgrebenets.github.io/tools/2015/06/04/jira-id-in-git-commit-messages2015-06-04T00:00:00+00:00App Store Version Territory
<p>Homegrown research on iOS app short and bundle version strings and how to specify them properly in respect to iTunes Connect and TestFlight.</p>
<!--more-->
<h1 id="version-strings-intro">Version Strings Intro</h1>
<p>A typical iOS app needs 2 version strings to be defined. This is an example of Xcode 6.3.2 UI.</p>
<p><img src="https://mgrebenets.github.io/assets/images/app-version/xcode-version-build-ui.png" alt="Xcode Version Settings" /></p>
<p>The first version string is referred to as just “Version”. It is also know as Short Bundle Version String and is stored under <code class="highlighter-rouge">CFBundleShortVersionString</code> key in the app’s Info.plist.</p>
<p>This is what your users expect to see on the “About” screen in the app, if they care. The general rule is to use <a href="http://semver.org/">Semantic Versioning</a> scheme in the <code class="highlighter-rouge">Major.Minor.Patch</code> form, e.g. <code class="highlighter-rouge">1.0.0</code>. It is also possible to use more user-friendly lightweight option <code class="highlighter-rouge">Major.Minor</code>, for example <code class="highlighter-rouge">1.0</code>, or even use just <code class="highlighter-rouge">1</code>, the decision is up to you. Later in this post and in the Summary section, I will give you the exact guidelines for short version string.</p>
<p>Second is Bundle Version. In Xcode UI it is called just “Build” and is stored under <code class="highlighter-rouge">CFBundleVersion</code> key in Info.plist. Another common name for this version string is “Build Version” or even “Build Number”. Its purpose is to uniquely identify this particular bundle (aka build) among all the other builds for the current app version. Often bundle version can be unique across all versions of the app ever, though this is not mandatory any more.</p>
<p><img src="https://mgrebenets.github.io/assets/images/app-version/short-n-bundle-full-spelling-xcode-ui.png" alt="App Versions" /></p>
<p><img src="https://mgrebenets.github.io/assets/images/app-version/short-n-bundle-xcod-ui-raw-values.png" alt="App Versions Raw Values" /></p>
<p>You are free to put whatever you want as version strings, it will be compiled, linked and archived with no errors or warnings of any kind. Here’s the ultimate proof for my words.</p>
<p><img src="https://mgrebenets.github.io/assets/images/app-version/build-ok-with-poop.png" alt="Anything Goes" /></p>
<p><img src="https://mgrebenets.github.io/assets/images/app-version/poop-app-version.png" alt="Anything Goes Indeed" /></p>
<p>The real fun begins when you try to upload that app bundle to TestFlight. At this time it actually matters what you put as app version strings. Let’s dissect each version string separately and figure out what the rules are. But first let’s create a test app in iTunes Connect.</p>
<p><img src="https://mgrebenets.github.io/assets/images/app-version/test-app-in-itc-1.0.0.png" alt="App Versions Raw Values" /></p>
<h2 id="short-bundle-version-string">Short Bundle Version String</h2>
<p>So what happens if I try to upload an app bundle with short version string saying “poop”? Naturally it fails.</p>
<p><img src="https://mgrebenets.github.io/assets/images/app-version/invalid-value-poop.png" alt="Poop Upload Fails" /></p>
<p>I was totally expecting arbitrary strings to be a “no no” in iTunes Connect. But guess what? Big surprise!</p>
<p><img src="https://mgrebenets.github.io/assets/images/app-version/poop-version-in-itc.png" alt="Poop Version in iTunes Connect" /></p>
<p>Well, don’t do that anyway.</p>
<p>Let’s use a valid version string this time, e.g. <code class="highlighter-rouge">1.0.0</code> and for now set build version to <code class="highlighter-rouge">1</code>. I will use the <code class="highlighter-rouge">short-version (build-version)</code> format from this moment on to indicate both versions, so I’m trying to upload <code class="highlighter-rouge">1.0.0 (5)</code>. Why <code class="highlighter-rouge">5</code>? Well, I just want it to be <code class="highlighter-rouge">5</code>, it doesn’t really matter.</p>
<p><img src="https://mgrebenets.github.io/assets/images/app-version/itc-upload-success.png" alt="Upload Success" /></p>
<p>Great, so it worked. Note that the app short version string exactly matches the version string in iTunes Connect. Back in a while, before Apple integrated TestFlight into iTunes Connect, it used to be a mandatory requirement, but not any more. I’m sure you want a proof, so I’ll just upload <code class="highlighter-rouge">1.0 (1)</code> this time.</p>
<p><img src="https://mgrebenets.github.io/assets/images/app-version/success.png" alt="Upload Success" /></p>
<p>It worked! But that’s not convincing enough. What if there’s some advanced matching happening and <code class="highlighter-rouge">1.0</code> is kind of the same as <code class="highlighter-rouge">1.0.0</code>? OK then, I will upload <code class="highlighter-rouge">2.0 (1)</code>.</p>
<p><img src="https://mgrebenets.github.io/assets/images/app-version/success.png" alt="Upload Success" /></p>
<p>Worked again! Just to make sure I’m not uploading to a black hole, I’ll try <code class="highlighter-rouge">1.0.0 (0)</code> again. Note the <code class="highlighter-rouge">0</code> build version, that’s on purpose.</p>
<p><img src="https://mgrebenets.github.io/assets/images/app-version/upload-0-less-than-5.png" alt="0 is less than 5" /></p>
<p>Aha! A very interesting error message! I personally like the <code class="highlighter-rouge">train version</code> term. Apparently each distinct version in TestFlight has its own <em>train</em>, whatever that means, I like to imagine an actual Illawarra line train with carriages. Every time you upload a new prerelease version, a new train is created. The order in which you upload the builds does not matter, you can upload <code class="highlighter-rouge">1.0</code> after <code class="highlighter-rouge">2.0</code>.</p>
<p>However, if your app already has a live version in App Store, then your new uploads must have a greater version that the live app. <em>Greater</em> in this case means <em>semantically</em> greater, that means components of the version string are compared left to right. For example, <code class="highlighter-rouge">1.0.1</code> is less than <code class="highlighter-rouge">1.1</code>, because <code class="highlighter-rouge">1 == 1</code> and <code class="highlighter-rouge">0 < 1</code>. Here’s the proof.</p>
<p><img src="https://mgrebenets.github.io/assets/images/app-version/1.0.1-less-than-1.1.png" alt="1.0.1 is less than 1.1" /></p>
<p>Finally, to dot all the <code class="highlighter-rouge">i</code>s, or should I say to dot all the short version string components, I will try to upload <code class="highlighter-rouge">2.1.1.1 (1)</code> to see what happens.</p>
<p><img src="https://mgrebenets.github.io/assets/images/app-version/at-most-3-non-negative-ints.png" alt="At Most 3 Non-negative Ints" /></p>
<p>And here’s the rule for creating a short version string.</p>
<blockquote>
<p>A period-separated list of at most three non-negative integers.</p>
</blockquote>
<p>Very clear and simple to remember.</p>
<p>One more thing, before I move on to bundle version. You can upload new prerelease builds to iTunes Connect <em>even if you don’t have a new version created there yet</em>. That’s right, just upload the builds and they will show up in Prerelease tab anyway. That also explains why the version string of uploaded bundle doesn’t have to match the version with Prepare for Submission status. As usual, I can prove it.</p>
<p><img src="https://mgrebenets.github.io/assets/images/app-version/prepare-for-submission-and-prerelease.png" alt="Prepare for Submission and Prerelease" /></p>
<p><img src="https://mgrebenets.github.io/assets/images/app-version/ready-for-sale-and-prerelease.png" alt="Ready for Sale and Prerelease" /></p>
<p>OK, enough of short version string. Don’t worry if facts look a bit scattered around the text, I’ll summarize them all in the end. Now it’s time for…</p>
<h2 id="bundle-version">Bundle Version</h2>
<p>The rules for bundle version are not the same as for short version string. For convenience and to reduce tautology in the text, I will call it <em>build version</em> by default.</p>
<p>There are many ways to compose a build version. The most popular options are</p>
<ul>
<li>Integer value (Build Number)</li>
<li>Period-separated non negative integers</li>
<li>Date string in <code class="highlighter-rouge">YYYYMMDD</code> or similar format</li>
<li>Git commit hash</li>
<li>Some weird stuff</li>
</ul>
<p>Let’s look at each option in detail.</p>
<h3 id="build-number">Build Number</h3>
<p>This is the most basic and simple way to manage a bundle/build version. An <em>incremental</em> non-negative integer. Any CI server gives you this number in some way. The <em>incremental</em> part really matters. As I demonstrated before by uploading <code class="highlighter-rouge">1.0.0 (0)</code> after <code class="highlighter-rouge">1.0.0 (5)</code>, the build version of each new upload must be greater than the previous build version <em>on the same train</em>. This time there is no special meaning for <em>greater</em>, just good old integer comparison, so <code class="highlighter-rouge">11</code> is less than <code class="highlighter-rouge">101</code>.</p>
<p>Another important note is that build versions need to increment in the scope of the same train only. In the past, build version had to be incremental <em>across all versions</em>. So if you had <code class="highlighter-rouge">1.0 (10)</code> live and then tried to upload <code class="highlighter-rouge">2.0 (1)</code> it would fail because <code class="highlighter-rouge">1 < 10</code>. Thankfully that’s not the case any more.</p>
<p>So to sum it up, build number used as bundle version</p>
<ul>
<li>Must be incremental</li>
<li>Independent for each short version string train</li>
</ul>
<h3 id="period-separated">Period-separated</h3>
<p>This is a little less popular way to manage build version, but still can be found “in the wild” so to say. For example, a build version is composed by joining short version string with the build number, like <code class="highlighter-rouge">major.minor.patch.build</code>: <code class="highlighter-rouge">1.0.0.1</code>, <code class="highlighter-rouge">2.0.42</code> and so on.</p>
<p>So what happens with this build version string when it gets to iTunes Connect? I will first tell you what happens, then will prove it with concrete examples.</p>
<ul>
<li>The build version is separated into components using <code class="highlighter-rouge">.</code>s as separators</li>
<li>Each component is stripped of <em>leading</em> zeroes</li>
<li>Processed components are joined back together to form one big integer</li>
</ul>
<p>The resulting integer is non negative, to be more specific it’s <code class="highlighter-rouge">unsigned long</code> integer.</p>
<p>Some examples.</p>
<ul>
<li><code class="highlighter-rouge">1.0.0.0</code> -> <code class="highlighter-rouge">1</code>, <code class="highlighter-rouge">0</code>, <code class="highlighter-rouge">0</code>, <code class="highlighter-rouge">0</code> -> <code class="highlighter-rouge">1000</code></li>
<li><code class="highlighter-rouge">2.001.030</code> -> <code class="highlighter-rouge">2</code>, <code class="highlighter-rouge">001</code>, <code class="highlighter-rouge">003</code> -> <code class="highlighter-rouge">2</code>, <code class="highlighter-rouge">1</code>, <code class="highlighter-rouge">30</code> -> <code class="highlighter-rouge">2130</code></li>
<li><code class="highlighter-rouge">1.000.02.03.04</code> -> <code class="highlighter-rouge">1</code>, <code class="highlighter-rouge">000</code>, <code class="highlighter-rouge">02</code>, <code class="highlighter-rouge">03</code>, <code class="highlighter-rouge">04</code> -> <code class="highlighter-rouge">1</code>, <code class="highlighter-rouge">0</code>, <code class="highlighter-rouge">2</code>, <code class="highlighter-rouge">3</code>, <code class="highlighter-rouge">4</code> -> <code class="highlighter-rouge">10234</code></li>
</ul>
<p>As you can see in the last example, the number of period-separated components is not limited this time. At least I tried all the way up to 4, can’t tell what happens when you have 5 or more of them, but I am about 99% sure the sky is the limit, I mean there’s some limit on the maximum length of the string.</p>
<p>Once the build version string is converted into an integer, the same rules apply as for the simple incremental build number. The newly uploaded build version for the given train must be greater than any previous build version.</p>
<p>Some examples again.</p>
<ul>
<li><code class="highlighter-rouge">2 < 1.1</code> [<code class="highlighter-rouge">2 < 11</code>]</li>
<li><code class="highlighter-rouge">1.0 < 1.0.0</code> [<code class="highlighter-rouge">10 < 100</code>]</li>
<li><code class="highlighter-rouge">1.0 == 1.01</code> [<code class="highlighter-rouge">10 == 10</code>]</li>
<li><code class="highlighter-rouge">1.0.1.020 == 1.001.1.20</code> [<code class="highlighter-rouge">10120 == 10120</code>]</li>
</ul>
<p>When you try to upload the same version more than once, you get a “Redundant Binary Upload” error message.</p>
<p><img src="https://mgrebenets.github.io/assets/images/app-version/redundant-upload-error.png" alt="Redundant Upload Error" /></p>
<p>I think I can stop now, the rules are pretty clear.</p>
<h3 id="date-string">Date String</h3>
<p>Date string is another way to compose a build version. For example, when using <code class="highlighter-rouge">YYYYMMDD</code> format your build version may look like <code class="highlighter-rouge">20150604</code>. Actually, this is a very good option. The resulting integer will be always incremental, thanks to the way the world around us works.</p>
<p>If you have an advanced CI setup, you should think about adding more components to the date format. Such as hours and minutes <code class="highlighter-rouge">YYYYMMDDHHmm</code>. This way if you have more than one build happening within the same hour you will be able to tell them apart.</p>
<p>If you choose to go with this option, don’t use any kind of separators, such as periods, colons or alike. With periods you will have unwanted side effects when leading zeroes are removed from components. Stuff like colons falls into Weird Stuff category, which I will describe later on.</p>
<h3 id="git-commit-hash">Git Commit Hash</h3>
<p>Another quite popular approach is to use git commit hash as build version string, or as a part of build version string. One useful property of commit hashes is uniqueness. But that’s not enough for TestFlight.</p>
<p>I tried quite a few things, such as hex numbers like <code class="highlighter-rouge">a</code>, <code class="highlighter-rouge">f</code>, <code class="highlighter-rouge">e</code>, <code class="highlighter-rouge">e4</code>, <code class="highlighter-rouge">5e</code> and even real life git commit hashes. So I lay the evidence before your eyes.</p>
<p><img src="https://mgrebenets.github.io/assets/images/app-version/invalid-value-e.png" alt="Invalid Value "e"" /></p>
<p><img src="https://mgrebenets.github.io/assets/images/app-version/invalid-value-e4.png" alt="Invalid Value "e4"" /></p>
<p><img src="https://mgrebenets.github.io/assets/images/app-version/invalid-value-5e.png" alt="Invalid Value "5e"" /></p>
<p><img src="https://mgrebenets.github.io/assets/images/app-version/invalid-value-git-hash.png" alt="Invalid Value Git Hash" /></p>
<p>Obviously, going outside the <code class="highlighter-rouge">a - f</code> range will take you nowhere, the <code class="highlighter-rouge">poop</code> example in the beginning of the article covers that well, and I tried things like <code class="highlighter-rouge">xyz</code> too.</p>
<h3 id="weird-stuff">Weird Stuff</h3>
<p>Finally, the weird stuff. I’ll just list some of the things I tried.</p>
<ul>
<li><code class="highlighter-rouge">1+0-2/5</code></li>
<li><code class="highlighter-rouge">1+++0---2***5</code></li>
<li><code class="highlighter-rouge">1...0...2...20</code></li>
</ul>
<p>Some error messages from iTunes Connect.</p>
<p><img src="https://mgrebenets.github.io/assets/images/app-version/invalid-value-arithmetic.png" alt="Invalid Value Arithmetics" /></p>
<p><img src="https://mgrebenets.github.io/assets/images/app-version/invalid-value-lotta-dots.png" alt="Invalid Value Lots Of Dots" /></p>
<p>Surprisingly though, despite the fact that upload fails, validation is successful. Whatever validation does it doesn’t check the validity of version strings.</p>
<h1 id="legacy">Legacy</h1>
<p>I subjectively call things like HockeyApp a <em>legacy</em> in this article. You may have different opinion. What I really want to say is that all these iTunes Connect and TestFlight rules do not apply to things like HockeyApp or in-house Over The Air distribution. Despite that fact, it would be reasonable to start making changes towards TestFlight guidelines.</p>
<h1 id="summary">Summary</h1>
<p>In conclusion I will make an attempt to summarize the version string rules.</p>
<p><em>Short Bundle Version String</em></p>
<ul>
<li>A period-separated list of at most three non-negative integers</li>
<li>Must be <em>semantically</em> incremental</li>
<li>Must be greater than current live version</li>
</ul>
<p><em>Bundle Version</em></p>
<ul>
<li>Converted to unsigned long integer</li>
<li>Periods are removed</li>
<li>Leading zeroes removed from each period-separated component</li>
<li>Resulting integer must be incremental
<ul>
<li>But only among other bundle versions for the same short version string (<em>version train</em>)</li>
</ul>
</li>
<li>Alphabet characters and git hashes in particular will not work</li>
<li>Various punctuation marks will not work</li>
</ul>
<p>Of course, I’m not claiming that this is the complete guide. I don’t know what is the limit for maximum version string length. Could be that some punctuation marks are legal, I didn’t try them all. Obviously I am giving no reference to any official documentation, could not find it or didn’t look hard enough. In any case, this information should be enough for you to come up with a robust and reliable versioning strategy for your apps.</p>
https://mgrebenets.github.io/mobile%20ci/2015/06/01/appstore-version-territory
https://mgrebenets.github.io/mobile%20ci/2015/06/01/appstore-version-territory2015-06-01T00:00:00+00:00Jenkins Job DSL - Configure Block
<p>A hands-on experience with <a href="https://github.com/jenkinsci/job-dsl-plugin/wiki/The-Configure-Block">Configure Blocks</a> in Jenkins Job DSL.</p>
<!--more-->
<p><a href="https://github.com/jenkinsci/job-dsl-plugin">Jenkins Job SDL</a> is a crown jewel of all the Jenkins plugins. I had a basic <a href="/mobile%20ci/2015/02/08/bitbucket-branches-job-dsl">write up</a> about it already, and another one in regards to <a href="/mobile%20ci/2015/05/17/jenkins-job-dsl-properties">DSL script properties</a>.</p>
<p>This post is an example of using <a href="https://github.com/jenkinsci/job-dsl-plugin/wiki/The-Configure-Block">Configure Blocks</a>. I’ll make an effort an try to explain what Configure Blocks are with my own words.</p>
<p>Basically, the whole DSL language output is a job configuration XML file. You are given a high level API to shape out that XML, that’s it. In some cases, where there’s no simple high level API available yet, you can use a bit lower level methods to mess around with resulting XML. That’s exactly what configure blocks are - a fallback mechanism to squeeze more juice out of Job DSL plugin.</p>
<p>Here’s an example, a default configuration of <a href="https://wiki.jenkins-ci.org/display/JENKINS/Git+Plugin">Git plugin</a> will not update submodules recursively and will use default 10 minutes timeout for submodules update operation.</p>
<p><img src="https://mgrebenets.github.io/assets/images/job-dsl-configure-block/submodules-default.png" alt="Default Submodule Update Configuration" /></p>
<p>Job DSL <a href="https://github.com/jenkinsci/job-dsl-plugin/wiki/Job-reference#git">provides an API</a> to enable recursive submodules update. This is how you can use it in DSL</p>
<script src="https://gist.github.com/a7225902db25df74c08a47caecddca35.js"> </script>
<p>That was easy. Here’s how the Jenkins job will look like now.</p>
<p><img src="https://mgrebenets.github.io/assets/images/job-dsl-configure-block/submodules-recursive-only.png" alt="Default Submodule Update Configuration" /></p>
<p>What if you want to change default timeout for submodules operations now? Unfortunately there’s no DSL command for that yet. This is exactly the case where you’d want to use Configure Block. Scanning through Configure Block examples, I have found <a href="https://github.com/jenkinsci/job-dsl-plugin/wiki/The-Configure-Block#configure-git">this one</a>. Looks like it’s quite easy to add new nodes to the job XML, but you have to figure out how to name those nodes first. The best way to find that out is to modify the job via Jenkins UI and then look at the job XML. So open the job configuration page in the browser, type in the 20 minutes custom timeout value and click save.</p>
<p><img src="https://mgrebenets.github.io/assets/images/job-dsl-configure-block/submodules-recursive-and-timeout.png" alt="Default Submodule Update Configuration" /></p>
<p>Now it’s time to locate the XML on file system. All the jobs data is located in <code class="highlighter-rouge">JENKINS_HOME</code>, the easiest way to find Jenkins Home location is again via Jenkins UI. Go to <code class="highlighter-rouge">Jenkins > Manage Jenkins > Configure System</code> and have a look at the top of the page.</p>
<p><img src="https://mgrebenets.github.io/assets/images/job-dsl-configure-block/jenkins-home-directory.png" alt="Default Submodule Update Configuration" /></p>
<p>Navigate to Jenkins Home, then to <code class="highlighter-rouge">jobs</code> directory, then find the directory of your particular job, this is very straightforward task, finally you will see <code class="highlighter-rouge">config.xml</code> in that directory, open it and have a look. This is the node you are looking for</p>
<script src="https://gist.github.com/c72d8681ed734e28613c3d8473073239.js"> </script>
<p>Specifically you are interested in this block of code</p>
<script src="https://gist.github.com/97ebd26ef0a466ce510e24050d6a6ed7.js"> </script>
<p>See that <code class="highlighter-rouge"><timeout>20</timeout></code> node? This is exactly what you want to generate using Configure Block. This is how you can do that</p>
<script src="https://gist.github.com/d5dede68e46ac61a163865a78c297e2a.js"> </script>
<p>That looks easy, doesn’t it? But hold on a sec before you celebrate. Run a DSL script first then have a look at resulting XML <em>before</em> looking at job configuration via Jenkins UI. Locate the SCM node again</p>
<script src="https://gist.github.com/de4d135d14704854e48d827011bf6a13.js"> </script>
<p>Hm… Looks a bit strange doesn’t it? The <code class="highlighter-rouge">disableSubmodules</code> and <code class="highlighter-rouge">recursiveSubmodules</code> nodes are outside of <code class="highlighter-rouge">hudson.plugins.git.extensions.impl.SubmoduleOption</code> for some reason. At least the values look right. So now go ahead and open the job configuration in Jenkins UI or hit refresh if you had it open all this time.</p>
<p><img src="https://mgrebenets.github.io/assets/images/job-dsl-configure-block/submodules-timeout-only.png" alt="Default Submodule Update Configuration" /></p>
<p>Wait… What did just happen there? The recursive update checkbox is cleared!</p>
<p>Let’s have a look at job XML one more time.</p>
<script src="https://gist.github.com/b1b27043c63e46acab22720514aa3f46.js"> </script>
<p>Well, the <code class="highlighter-rouge">scm</code> node is moved up in the XML and is changed a bit. Also, the <code class="highlighter-rouge">recursiveSubmodules</code> as well as <code class="highlighter-rouge">disableSubmodules</code> are moved inside the <code class="highlighter-rouge">hudson.plugins.git.extensions.impl.SubmoduleOption</code> node, but somehow <code class="highlighter-rouge">recursiveSubmodules</code> has lost its custom value in the process. Whatever Jenkins is doing under the hood is a mystery for me. This may be a bug in Jenkins Job DSL plugin or a known limitation. Brief search in project <a href="https://issues.jenkins-ci.org/browse/JENKINS-22138?jql=project%20%3D%20JENKINS%20AND%20component%20%3D%20job-dsl-plugin%20AND%20status%20%3D%20Open%20ORDER%20BY%20priority%20DESC">JIRA</a> and discussion <a href="https://groups.google.com/forum/#!searchin/job-dsl-plugin/configure$20block$20overwrites$20values">group</a> didn’t come back with any results. That means if you are working with Configure Blocks, keep the following in mind</p>
<blockquote>
<p>When changing one particular node, either do all changes via Job DSL API or via Configure Block, but never mix the two.</p>
</blockquote>
<p>If you want to have both recursive submodule update and custom timeout configured, set both of them via Configure Block.</p>
<script src="https://gist.github.com/dab7359f219ee70861d3147f9c07055c.js"> </script>
https://mgrebenets.github.io/mobile%20ci/2015/05/30/jenkins-job-dsl-configure-block
https://mgrebenets.github.io/mobile%20ci/2015/05/30/jenkins-job-dsl---configure-block2015-05-30T00:00:00+00:00Fix Objective-C Imports
<p>A way to change Objective-C <code class="highlighter-rouge">#import <Framework/Framework.h></code> to modern <code class="highlighter-rouge">@import Framework;</code>.</p>
<!--more-->
<h1 id="modules-syntax">Modules Syntax</h1>
<p><a href="http://clang.llvm.org/docs/Modules.html">Objective-C modules</a> were first introduced with iOS 7. Modules came to live for a reason, for lots of reasons. They are designed to overcome shortcomings of current preprocessor, specifically the way <code class="highlighter-rouge">#import</code>s are handled. You can find more information <a href="https://stoneofarc.wordpress.com/2013/06/25/introduction-to-objective-c-modules/">here</a> and <a href="http://www.raywenderlich.com/49850/whats-new-in-objective-c-and-foundation-in-ios-7">here</a>.</p>
<p>If your app minimum deployment target is iOS 7.0, you are free to switch to using modules for all system frameworks, such as <code class="highlighter-rouge">UIKit</code>, <code class="highlighter-rouge">Foundation</code> and the rest. With iOS 8.0 and support for custom dynamic frameworks, even your own frameworks can be imported as modules, but in the scope of this article we will look at system frameworks only. In terms of syntax your change would look like this</p>
<pre><code class="language-objective-c">// Old code
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <UIKit/UIImage.h> // Just an example
// New code
@import UIKit;
@import Foundation;
@import UIKit.UIImage;
</code></pre>
<p>A totally valid question to ask is “Should I even bother with fixing this?”. And the answer is “No, not necessarily”. As soon as you enabled modules for your project all <code class="highlighter-rouge">#include</code> and <code class="highlighter-rouge">#import</code> statements are automatically mapped to corresponding <code class="highlighter-rouge">@import</code> statement. This is described in some detail <a href="http://clang.llvm.org/docs/Modules.html#id15">here</a> and <a href="http://useyourloaf.com/blog/2014/12/07/modules-and-precompiled-headers.html">here</a>.</p>
<p>So, technically, fixing imports in legacy code is the question of code base maintenance and code style. It does look a bit off when both <code class="highlighter-rouge">#import</code> and <code class="highlighter-rouge">@import</code> are sitting few lines apart in the same file. Weigh all pros and cons before making a final decision. Keep in mind the fact that if you already have the script at hand, the conversion will take no time at all.</p>
<h1 id="fixing-recipe">Fixing Recipe</h1>
<p>Xcode is know to offer code migration features, such as “Convert to ARC” or “Convert to Modern Objective-C Syntax”. However, converting all <code class="highlighter-rouge">#import</code>s to <code class="highlighter-rouge">@import</code>s is not part of Xcode feature set. I would add “yet”, because I believe sooner or later Apple will proclaim iOS 7.0 as minimum OS supported by Xcode and force all imports conversion. Until that happens we need to handle this migration ourselves.</p>
<p>So what would be the recipe to fix imports for all system frameworks? Here’s one I have in mind</p>
<ul>
<li>Get a list of all system frameworks</li>
<li>For each framework
<ul>
<li>Replace <code class="highlighter-rouge">#import <Framework/Framework.h></code> with <code class="highlighter-rouge">@import Framework;</code></li>
<li>Replace <code class="highlighter-rouge">#import <Framework/Header.h></code> with <code class="highlighter-rouge">@import Framework.Header;</code></li>
</ul>
</li>
</ul>
<h2 id="system-frameworks">System Frameworks</h2>
<p>Let’s solve the first part and get a list of system frameworks. Naturally, I googled first and ended up <a href="https://developer.apple.com/library/ios/documentation/Miscellaneous/Conceptual/iPhoneOSTechOverview/iPhoneOSFrameworks/iPhoneOSFrameworks.html">here</a>. My desire to scrape the web page luckily died off right away, reading through the first paragraph I found out that all system frameworks are located in</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><Xcode.app>/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/<iOS_SDK>/System/Library/Frameworks
</code></pre></div></div>
<p>That path looked a bit familiar to me and I knew I could get at least some of it with help of <code class="highlighter-rouge">xcrun</code>, so this is what I got in the end</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>xcrun <span class="nt">--sdk</span> iphoneos <span class="nt">--show-sdk-path</span>
</code></pre></div></div>
<p>Then just append the missing bit and list the directory. Everything that ends with <code class="highlighter-rouge">.framework</code> is (quite logically) a system framework.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ls</span> <span class="k">$(</span>xcrun <span class="nt">--sdk</span> iphoneos <span class="nt">--show-sdk-path</span><span class="k">)</span>/System/Library/Frameworks | <span class="nb">grep</span> .framework
</code></pre></div></div>
<p>Now I would like to turn this into a regular expression. What I want to have is a regex that says something like <code class="highlighter-rouge">UIKit OR Foundation OR iAd</code> and so on, with POSIX regex syntax it will look like this <code class="highlighter-rouge">UIKit|Foundation|iAd</code>. So I loop through results of <code class="highlighter-rouge">ls</code>, drop the <code class="highlighter-rouge">.framework</code> bit and create a string of or-ed framework names. My bash skills do not shine really bright in this example, but the code does the job.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Get the list of all system frameworks</span>
<span class="nv">LIBS</span><span class="o">=</span><span class="k">$(</span><span class="nb">ls</span> <span class="k">$(</span>xcrun <span class="nt">--sdk</span> iphoneos <span class="nt">--show-sdk-path</span><span class="k">)</span>/System/Library/Frameworks | <span class="nb">grep</span> .framework<span class="k">)</span>
<span class="c"># Collect all library components and combine into or-ed regex</span>
<span class="k">for </span>lib <span class="k">in</span> <span class="k">${</span><span class="nv">LIBS</span><span class="k">}</span><span class="p">;</span> <span class="k">do
</span><span class="nv">BASE_NAME</span><span class="o">=</span><span class="k">${</span><span class="nv">lib</span><span class="p">/.framework/</span><span class="k">}</span>
<span class="o">[[</span> <span class="nt">-z</span> <span class="s2">"</span><span class="k">${</span><span class="nv">LIB_COMPONENTS</span><span class="k">}</span><span class="s2">"</span> <span class="o">]]</span> <span class="se">\</span>
<span class="o">&&</span> <span class="nv">LIB_COMPONENTS</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">BASE_NAME</span><span class="k">}</span><span class="s2">"</span> <span class="se">\</span>
<span class="o">||</span> <span class="nv">LIB_COMPONENTS</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">LIB_COMPONENTS</span><span class="k">}</span><span class="s2">|</span><span class="k">${</span><span class="nv">BASE_NAME</span><span class="k">}</span><span class="s2">"</span>
<span class="k">done
</span><span class="nb">echo</span> <span class="s2">"</span><span class="k">${</span><span class="nv">LIB_COMPONENTS</span><span class="k">}</span><span class="s2">"</span>
</code></pre></div></div>
<p>The output is like this</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>AVFoundation|AVKit|Accelerate|Accounts|AdSupport|AddressBook|AddressBookUI|AssetsLibrary|AudioToolbox|AudioUnit|CFNetwork|CloudKit|CoreAudio|CoreAudioKit|CoreAuthentication|CoreBluetooth|CoreData|CoreFoundation|CoreGraphics|CoreImage|CoreLocation|CoreMIDI|CoreMedia|CoreMotion|CoreTelephony|CoreText|CoreVideo|EventKit|EventKitUI|ExternalAccessory|Foundation|GLKit|GSS|GameController|GameKit|HealthKit|HomeKit|IOKit|ImageIO|JavaScriptCore|LocalAuthentication|MapKit|MediaAccessibility|MediaPlayer|MediaToolbox|MessageUI|Metal|MobileCoreServices|MultipeerConnectivity|NetworkExtension|NewsstandKit|NotificationCenter|OpenAL|OpenGLES|PassKit|Photos|PhotosUI|PushKit|QuartzCore|QuickLook|SafariServices|SceneKit|Security|Social|SpriteKit|StoreKit|SystemConfiguration|Twitter|UIKit|VideoToolbox|WatchKit|WebKit|iAd
</code></pre></div></div>
<p>With this regex pattern it is now possible to fix the imports. For the live of me I couldn’t win the battle with <code class="highlighter-rouge">sed</code> or <code class="highlighter-rouge">awk</code> and use regex back-reference in the pattern itself. This is not to say anything bad about <code class="highlighter-rouge">sed</code> or <code class="highlighter-rouge">awk</code> as such, this is just me lacking the skills. However, I still managed to stay purely within a realm of Unix-based system by using <code class="highlighter-rouge">perl</code>.</p>
<h2 id="frameworkframeworkh">Framework/Framework.h</h2>
<p>This is exactly the case where back reference needs to be used in the pattern expression itself, not in the replacement. This is an illustration to explain what I actually mean</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Use back-reference in match pattern</span>
<span class="s2">"s,(group-capture)/</span><span class="se">\1</span><span class="s2">,replacement,"</span>
<span class="c"># Use back-reference in replacement</span>
<span class="s2">"s,(group-capture),</span><span class="se">\1</span><span class="s2">,"</span>
</code></pre></div></div>
<p>The <code class="highlighter-rouge">()</code> parenthesis are capturing a group and then captured content can be back-referenced using <code class="highlighter-rouge">\1</code>, <code class="highlighter-rouge">\2</code> and so on. In this example <code class="highlighter-rouge">(group-capture)/\1</code> used in pattern match literally means string “group-capture” repeated 2 times and separated by <code class="highlighter-rouge">/</code>: “group-capture/group-capture”.</p>
<p>Anyway, assuming the source file name is stored in <code class="highlighter-rouge">FILE_PATH</code> variable, the in-place replacement with Perl looks like this</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">FILE_PATH</span><span class="o">=</span>SourceFile.m
<span class="c"># LIB_COMPONENTS are set previously</span>
perl <span class="nt">-pi</span> <span class="nt">-e</span> <span class="s2">"s/#import[ </span><span class="se">\t</span><span class="s2">]*<(</span><span class="k">${</span><span class="nv">LIB_COMPONENTS</span><span class="k">}</span><span class="s2">)</span><span class="se">\/\1</span><span class="s2">.h>/</span><span class="se">\@</span><span class="s2">import </span><span class="se">\1</span><span class="s2">;/"</span> <span class="s2">"</span><span class="k">${</span><span class="nv">FILE_PATH</span><span class="k">}</span><span class="s2">"</span>
</code></pre></div></div>
<p>Here you can see that regex accounts for missing or varying number of spaces after <code class="highlighter-rouge">#import</code> and that <code class="highlighter-rouge">\1</code> back-reference works perfect with perl.</p>
<h2 id="frameworkheaderh">Framework/Header.h</h2>
<p>This bit is almost the same as the previous case. In fact, regex is a little bit more common and doesn’t use back-reference in match patter, instead uses 2 back-references in replacement string. It is important to note that these perl commands must be applied exactly in the order they are described, so you don’t end up with <code class="highlighter-rouge">@import Framework.Framework;</code>.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">FILE_PATH</span><span class="o">=</span>SourceFile.m
<span class="c"># LIB_COMPONENTS are set previously</span>
perl <span class="nt">-pi</span> <span class="nt">-e</span> <span class="s2">"s/#import[ </span><span class="se">\t</span><span class="s2">]*<(</span><span class="k">${</span><span class="nv">LIB_COMPONENTS</span><span class="k">}</span><span class="s2">)</span><span class="se">\/</span><span class="s2">(.*).h>/</span><span class="se">\@</span><span class="s2">import </span><span class="se">\1</span><span class="s2">.</span><span class="se">\2</span><span class="s2">;/"</span> <span class="s2">"</span><span class="k">${</span><span class="nv">FILE_PATH</span><span class="k">}</span><span class="s2">"</span>
</code></pre></div></div>
<h1 id="other-modules">Other Modules</h1>
<p>In fact, you know of course there are other modules as well, such as runtime modules, e.g.</p>
<pre><code class="language-objective-c">// Old style
#import <objc/runtime.h>
// Module
@import ObjectiveC.runtime;
</code></pre>
<p>This case is somewhat more complicated than fixing system frameworks. I played a bit with <code class="highlighter-rouge">--show-sdk-platform-path</code> option of <code class="highlighter-rouge">xcrun</code> command and tried other things, but overall there’s no straightforward obvious solution to this problem. You may have to fix these imports by hand or wait until Xcode automates it.</p>
<h1 id="summary">Summary</h1>
<p>As a traditional TL;DR; part, I will just post the link to the <a href="https://gist.github.com/mgrebenets/40eaa2b8d2c724733bd5">upgraded shell script version</a>.</p>
https://mgrebenets.github.io/objective-c/2015/05/29/fix-objective-c-imports
https://mgrebenets.github.io/objective-c/2015/05/29/fix-objective-c-imports2015-05-29T00:00:00+00:00Fix Objective-C File Header Comment
<p>A simple way to fix file headers in your Objective-C (an not only) files.</p>
<!--more-->
<p>Might be worth to clean up confusions, if any. By “file header” in this case I mean the C-style header comment like this</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//
// Copyright (c) 2015 NSBogan. All rights reserved.
//
</span></code></pre></div></div>
<h1 id="problem">Problem</h1>
<p>For some people it doesn’t really matter what sits at the top of the file. In big projects it may become more important. I have one particular case in mind where information in file headers needs to be anonymous and should contain only a company name and copyright notice, just like the code sample at the top. There are pros and cons to this approach. You may argue that it is important to know who created the file to point a finger, but when the project is large enough, dozens of people end up touching the same file, the project <em>outlives</em> developers (they just come and go, but the project stays), there’s no point to point a finger any more (apologies for the tautology here).</p>
<p>Another note is that we are here talking about existing files. When it comes to creating new files, it is <a href="http://stackoverflow.com/questions/2381149/changing-the-default-header-comment-license-in-xcode">possible</a> to modify <a href="http://stackoverflow.com/questions/20311839/change-copyright-top-comment-header-on-all-new-files-in-xcode-5">default Xcode templates</a>, and even manage to <a href="http://stackoverflow.com/questions/33720/change-templates-in-xcode/33743#33743">preserve the changes on Xcode upgrade</a>. There’s even <a href="https://github.com/royclarkson/xcode-templates">a tool</a> to automate the process to a certain level.</p>
<p>However, if you have a script that can fix header comments in existing files, you can reuse the very same script in your git commit hooks to fix the header comments of new files. Kill two birds with one stone (though in my native language we choose hares as objects of violence for this proverb).</p>
<h1 id="solution">Solution</h1>
<p>So, at the high level, the way to approach this problem is</p>
<ul>
<li>Remove all blank lines at the start of the file</li>
<li>Remove all lines that start with <code class="highlighter-rouge">//</code> from the start of the file</li>
<li>Insert you custom header comment at the start of the file</li>
</ul>
<p>Before proceeding further, let’s agree we are working with a source file named <code class="highlighter-rouge">Source.m</code> and have an environment variable defined as <code class="highlighter-rouge">FILE_PATH=Source.m</code>.</p>
<h2 id="remove-blank-lines">Remove Blank Lines</h2>
<p>The blank lines at the start of the file are a rare exception, but sometimes they do occur. Fixing this is possible with <code class="highlighter-rouge">sed</code> is <em>easy</em></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sed <span class="nt">-i</span> <span class="nb">.</span> <span class="s1">'/./,$!d'</span> <span class="s2">"</span><span class="k">${</span><span class="nv">FILE_PATH</span><span class="k">}</span><span class="s2">"</span>
</code></pre></div></div>
<p>This is one of those they call <em>read-only language</em>. A one-liner that takes hours to decipher, unless you are fluent with <code class="highlighter-rouge">sed</code> already.</p>
<ul>
<li>The <code class="highlighter-rouge">-i . </code> option means <em>inplace</em> edit and weird looking <code class="highlighter-rouge">.</code> with a must-have space after <code class="highlighter-rouge">-i</code> option is OS X specific way to tell <code class="highlighter-rouge">sed</code> not to create backup file.</li>
<li>The <code class="highlighter-rouge">/./,$</code> construction is a range and means <em>from <code class="highlighter-rouge">/./</code> to <code class="highlighter-rouge">$</code></em>. <code class="highlighter-rouge">/./</code> is a regex that matches any non-blank line, <code class="highlighter-rouge">$</code> is a special address and means last line of the input. So <code class="highlighter-rouge">/./,$</code> in English means <em>from first non-blank line to the end of file</em>.</li>
<li><code class="highlighter-rouge">!</code> means negation. So if you negate <code class="highlighter-rouge">/./,$</code> you get the following human language description <em>from first line of the input to last blank line inclusive</em>. In other words, all consequent leading blank lines in the file.</li>
<li>Finally, <code class="highlighter-rouge">d</code> command means <em>delete</em>, so you tell <code class="highlighter-rouge">sed</code> to delete all lines in the given range.</li>
</ul>
<p>Whoa, that was a lot of words to explain one 7-characters <code class="highlighter-rouge">sed</code> command…</p>
<h2 id="remove-header">Remove Header</h2>
<p>Next thing to do is to remove existing header comment. This is a matter of removing consequent lines starting with <code class="highlighter-rouge">//</code> from the start of the file. You may think this sounds just like removing consequent blank lines. It does! But I failed big time to do it with sed. I originally assumed this is just a matter of replacing <code class="highlighter-rouge">/./</code> regex with something like <code class="highlighter-rouge">/^\/\//</code>, but no, it didn’t work for me. I spent a fair amount of time googling and trying my best with <code class="highlighter-rouge">sed</code> and <code class="highlighter-rouge">awk</code>, before I gave up and came up with the solution you will see below. However, it would be fair to say that my seding and awking skills are nowhere near good enough, I am sure there’s a better way to do it and I would welcome any comments.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Count number of consequent lines starting with // at the beginning of the file</span>
<span class="nv">N</span><span class="o">=</span><span class="k">$(</span><span class="nb">cat</span> <span class="s2">"</span><span class="k">${</span><span class="nv">FILE_PATH</span><span class="k">}</span><span class="s2">"</span> | awk <span class="s1">'{ if(/^\/\//) print; else exit; }'</span> | wc <span class="nt">-l</span> | xargs<span class="k">)</span>
<span class="c"># Remove first N lines from the file</span>
<span class="o">[[</span> <span class="k">${</span><span class="nv">N</span><span class="k">}</span> <span class="nt">-gt</span> 0 <span class="o">]]</span> <span class="o">&&</span> sed <span class="nt">-i</span> <span class="nb">.</span> <span class="s2">"1,</span><span class="k">${</span><span class="nv">N</span><span class="k">}</span><span class="s2">d"</span> <span class="s2">"</span><span class="k">${</span><span class="nv">FILE_PATH</span><span class="k">}</span><span class="s2">"</span>
</code></pre></div></div>
<p>You can see here that the very same <code class="highlighter-rouge">/^\/\//</code> regex I tried to use with <code class="highlighter-rouge">sed</code> works perfectly with <code class="highlighter-rouge">awk</code>. The <code class="highlighter-rouge">awk</code> command will execute <code class="highlighter-rouge">print</code> until file lines match the pattern and will stop (using <code class="highlighter-rouge">exit</code> command) as soon as the first non-matching line occurs.</p>
<p>Word count (<code class="highlighter-rouge">wc</code>) command is used to count lines then (<code class="highlighter-rouge">-l</code> option) and <code class="highlighter-rouge">xargs</code> is handy in this case because it strips leading and trailing spaces from the input.</p>
<p>Next if <code class="highlighter-rouge">N</code> is greater than zero, use good old <code class="highlighter-rouge">sed</code> to remove first <code class="highlighter-rouge">N</code> lines from the file. This is done by using <code class="highlighter-rouge">1,${N}</code> address range and <code class="highlighter-rouge">d</code>elete command. Note the use of <em>“weak”</em> quotation marks in sed regex, this is to resolve reference to <code class="highlighter-rouge">N</code> inside the regex string.</p>
<h2 id="insert-new-header">Insert New Header</h2>
<p>Finally, you have the file stripped of its old header comment, time to insert a new header.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Insert new header using current year</span>
<span class="nv">HEADER</span><span class="o">=</span><span class="s2">"//</span><span class="se">\\</span><span class="s2">
// Copyright (c) </span><span class="k">$(</span>date +<span class="s1">'%Y'</span><span class="k">)</span><span class="s2"> NSBogan All rights reserved.</span><span class="se">\\</span><span class="s2">
//</span><span class="se">\\</span><span class="s2">
</span><span class="se">\\</span><span class="s2">
"</span>
sed <span class="nt">-i</span> <span class="nb">.</span> <span class="s2">"1s|^|</span><span class="k">${</span><span class="nv">HEADER</span><span class="k">}</span><span class="s2">|g"</span> <span class="s2">"</span><span class="k">${</span><span class="nv">FILE_PATH</span><span class="k">}</span><span class="s2">"</span>
</code></pre></div></div>
<p>The header here is using <code class="highlighter-rouge">date</code> command to insert current year in <em>YYYY</em> format, e.g. 2015.</p>
<p><code class="highlighter-rouge">sed</code> matches the beginning of the line (<code class="highlighter-rouge">^</code> anchor) and inserts the header there. The <code class="highlighter-rouge">1</code> before replacement pattern is there to make sure replacement is made only once.</p>
<h2 id="edge-cases">Edge Cases</h2>
<p>The described approach will not work for header comments that use block style, e.g.</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
File header comment.
*/</span>
</code></pre></div></div>
<h1 id="summary">Summary</h1>
<p>As usual I link a version of <a href="https://gist.github.com/mgrebenets/109fedfc7d5c8ebfff7f">slightly improved script</a>. As a bonus this script can fix header comments in <code class="highlighter-rouge">xcconfig</code> files as well. I still say <em>slightly</em>, because it can be improved more. One possible step up is to create a text file with you custom header comment and pass this file path as an input to a header fixing script.</p>
<p>You can bundle this script up with <a href="/objective-c/2015/05/29/fix-objective-c-imports">imports fixing script</a> and use as part of git commit hooks to eliminate some of the code style debates during code reviews.</p>
https://mgrebenets.github.io/objective-c/2015/05/29/fix-objective-c-file-header
https://mgrebenets.github.io/objective-c/2015/05/29/fix-objective-c-file-header2015-05-29T00:00:00+00:00Jenkins Job DSL - Properties
<p>Learn how to work with global properties in DSL Groovy script, and how to handle missing properties.</p>
<!--more-->
<p>If you are not familiar with Jenkins Job DSL, <a href="/mobile%20ci/2015/02/08/bitbucket-branches-job-dsl">this post may be a good starting point</a>;</p>
<h1 id="properties">Properties</h1>
<p>When you are working with main Groovy script, all Jenkins environment variables are available as so called properties. Properties, because you main script is more than just a similar shell script, in fact you are working with an instance of a Groovy class, that’s why there are properties. For example, you can read the value of Jenkins’ <code class="highlighter-rouge">BUILD_NUMBER</code> environment variable in DSL script like this</p>
<script src="https://gist.github.com/87ed464b14f1a1e86ad297207ebbbd9e.js"> </script>
<p>Very convenient way to read any environment variable. Additionally you can use <a href="https://wiki.jenkins-ci.org/display/JENKINS/EnvInject+Plugin">EnvInject</a> plugin and inject more environment variables to the build job.</p>
<h1 id="missing-properties">Missing Properties</h1>
<p>But what happens if environment variable is not defined? In that case corresponding property will not be defined as well, so if you try to read that property, you will get a runtime error.</p>
<script src="https://gist.github.com/9ce75d70138ffe908ddf9b3a4cc03329.js"> </script>
<p>So what do you do if you really want to read the variable first and if it’s not there just use sensible default? For example</p>
<script src="https://gist.github.com/14bebdb1a29f9cd87e305e839771bafd.js"> </script>
<p>First thing you may try is to use <code class="highlighter-rouge">hasProperty</code> method which is a member of any Groovy class.</p>
<script src="https://gist.github.com/135333a5b31b566dda62e0b5885dc958.js"> </script>
<p>This code will not throw a runtime error. The problem is that <code class="highlighter-rouge">hasProperty</code> will always return <code class="highlighter-rouge">false</code>.</p>
<h1 id="bindings">Bindings</h1>
<p>All is not lost though. Each Jenkins DSL script has a reference to so called “bindings”. Apparently, bindings are used to bind all the environment variables and make them available for the script. Additionally bindings include references to things like standard output, which will come handy later on.</p>
<script src="https://gist.github.com/54c9692b9caf4d3dfbff6a972f71a772.js"> </script>
<p>That’s all you have to do to get the script bindings. Now you can access environment variables in a safe way.</p>
<script src="https://gist.github.com/c650e41f14249f1048ea3d580622083a.js"> </script>
<p>If the property is not defined, the return value is <code class="highlighter-rouge">null</code> and your code will fallback to a default value.</p>
<h1 id="standard-output">Standard Output</h1>
<p>As I mentioned before, bindings also bind such things as standard output. By default <code class="highlighter-rouge">println</code> statements will work only when called from the body of the main script. If you use packages and other classes in your DSL, logging from other modules via <code class="highlighter-rouge">println</code> statement will not work, will not yield any output to console to be more specific.</p>
<script src="https://gist.github.com/69291c413caa8ea7757fba7ee3ab7561.js"> </script>
<p>Of course it makes no sense to declare Logger class in the body of the main script. Proper way is to factor it out into a separate file and import the package instead. I plan to have a write up on advanced DSL with classes and packages.</p>
https://mgrebenets.github.io/mobile%20ci/2015/05/17/jenkins-job-dsl-properties
https://mgrebenets.github.io/mobile%20ci/2015/05/17/jenkins-job-dsl---properties2015-05-17T00:00:00+00:00Provisioning Profiles, Sigh...
<p>In this article you will find out why iOS provisioning profiles are a nightmare and if there is a way to automate provisioning profiles management.</p>
<!--more-->
<h2 id="provisioning-profiles">Provisioning Profiles</h2>
<p>Anyone who calls themselves an iOS Developer, knows what this is all about. You have to generate profiles, make sure they use proper certificates and are configured for the right app identifier. Should you renew a certificate or change the app’s entitlements, you now have to regenerate all related provisioning profiles, then make sure you install new profiles everywhere you need them. If it wasn’t difficult enough already, there are 2 types of provisioning profiles: Development and Distribution; and if that wasn’t enough, Distribution profiles come in two more flavors: App Store and AdHoc.</p>
<p>But that’s not the end of the nightmare either! What if you are a member of more than one iOS developer program? For example, you are part of both App Store and Enterprise programs, or you are a freelancer and happen to be a member of a dozen teams. Did you use different Apple IDs for different teams? Doesn’t make it any easier at all. I’m sure many of you know what it feels like.</p>
<p>Finally, things go wild if you have to manage that provisioning zoo for Continuous Integration setup. Just one build box is painful enough to keep up to date, I’m not even mentioning multiple build agents yet…</p>
<p>Of course I’m over pessimistic, but that’s on purpose. One could say that Xcode can manage your accounts and profiles. That’s true but Xcode is known to do a very sloppy job in that regards, and in no way Xcode’s provisioning profile management can be <em>automated</em>.</p>
<p>Overall, managing provisioning profiles involves a lot of <strong>manual</strong> interactions with web browser. What if there was a tool that would let you manage profiles automatically, via command line and scripts? Well, it so happens that there is one now! Meet <a href="https://docs.fastlane.tools/actions/sigh/">Sigh</a> a part of <a href="https://docs.fastlane.tools/">Fastlane</a> tools. Fastlane is a collection of tools that cover all aspects of iOS development, Sigh in particular is designed to help you with managing provisioning profiles and certificates. You can manage profiles installed locally as well as create, renew, update, regenerate and delete profiles from developer portal.</p>
<p>There are so many uses for the tool, but in this article I’ll describe the most basic one, that is downloading an existing provisioning profile. As a bonus, you will see how to parse provisioning profiles and get all the details from it, especially profile UUID and signing identity of the related certificate.</p>
<h2 id="download-profile">Download Profile</h2>
<p>Time to fix all the assumptions before going forward.</p>
<ul>
<li>You have an account with Enterprise development program and that account has <strong>Admin</strong> level of access.</li>
<li>You have a Distribution provisioning profile created for Wildcard App ID (*).</li>
</ul>
<p>That will do it. First thing to do is to install Fastlane Ruby gem.</p>
<blockquote>
<p>gem install fastlane</p>
</blockquote>
<p>Time to get a profile now.</p>
<script src="https://gist.github.com/f19e6e75a2725d2e42c4931104f808e9.js"> </script>
<p>So what’s going on here?</p>
<ul>
<li><code class="highlighter-rouge">--username</code> is the Apple ID you used to join the developer program.</li>
<li><code class="highlighter-rouge">--team_id</code> is the 10 character ID of the team. This is mandatory if the Apple ID is part of multiple teams (aka programs). In general, it’s just a good rule of thumb to be as explicit as possible.</li>
<li><code class="highlighter-rouge">--provisioning_name</code> is the name of provisioning profile. That’s the very same name you see when you login to developer portal, not UUID or any other kind of identifier.</li>
<li><code class="highlighter-rouge">--app_identifier</code> is the App identifier in the provisioning profile. The same thing you use as Bundle ID most of the time. In this example the profile is a wildcard profile, so app identifier is just “*” (wildcard). Be cautious! Those quotes around <code class="highlighter-rouge">*</code> <em>really matter</em>!</li>
<li><code class="highlighter-rouge">--filename</code> tell sigh where to save a copy of the provisioning profile file. By default it will be installed in <code class="highlighter-rouge">~/Library/MobileDevice/Provisioning Profiles/</code>. If you don’t want the profile to be installed, add <code class="highlighter-rouge">--skip_install</code> option to the command.</li>
</ul>
<p>The very first time you use a given combination of Apple ID and Team ID you will be asked for a password. Fastlane will safely store your password in keychain and you will not have to type it in anymore (well, until the moment you change it, of course). So for CI setup you will have to use Sigh (or any other tool from Fastlane) at least once for each developer account, to have the password stored, and from that moment on all CI scripts will be able to work without user intervention required.</p>
<p>The above is not the case with the introduction of 2FA. You would have to configure <code class="highlighter-rouge">FASTLANE_SESSION</code> as described <a href="https://github.com/fastlane/fastlane/tree/master/spaceship#support-for-ci-machines">here</a>.</p>
<blockquote>
<p>A side note in regards to Team ID. For some reason the real ID is very obscure and doesn’t match the one you would see in Member Center. Luckily, you can run Sigh with wrong Team ID and it will output the list of all correct IDs.</p>
</blockquote>
<h2 id="parse-profile">Parse Profile</h2>
<p>Another step towards total automation is to include profile download as part of CI job. Usually all CI jobs expect latest provisioning profiles to be installed on the box. CI is either using UUID explicitly, expects profile to have a specific file name or delegates profile lookup task to Xcode. With Sigh you can simplify this bit immensely. Each CI job will make sure the latest profile is downloaded and installed, and named the way it should be named.</p>
<p>Additionally, you may want to extract information from the profile, such as the profile UUID and the name of the signing identity. Why would you do that? Well, you can build the very same project using various provisioning profiles and signing identities, this is the way you can get different builds for Enterprise, AdHoc and App Store distribution, with different bundle IDs, etc. Usually build scripts are configured to specify the provisioning profile specifier and signing identity explicitly via <code class="highlighter-rouge">xcodebuild</code>’s <code class="highlighter-rouge">PROVISIONING_PROFILE_SPECIFIER</code> and <code class="highlighter-rouge">CODE_SIGN_IDENTITY</code> build settings. This is how you can overwrite default build settings in Xcode project.</p>
<p>While specifying signing identity explicitly is important, specifying profile specifier is something that should be done with a lot of caution. The reason is Today Widget and WatchKit extensions. These extensions are separate targets in Xcode project and by default extension targets are dependencies for main app target. It means when you build a main target, all extensions are built as well. Nothing bad so far. The problem is that each of those extensions has its own bundle ID and, as you would expect, a separate provisioning profile. Now, if you explicitly specify profile specifier when building main app target, this build setting will overwrite build settings for all dependent targets as well. Naturally, the build will fail when trying to build Today Widget extension with bundle ID and entitlements from main app target provisioning profile.</p>
<p>So what do you do? Well, previously I’d say to trust Xcode, but these days I’d recommend to use custom build settings instead. E.g. define build settings in this way:</p>
<ul>
<li>For main app: <code class="highlighter-rouge">PROVISIONING_PROFILE_SPECIFIER = MAIN_APP_PROVISIONING_PROFILE_SPECIFIER</code></li>
<li>For extension: <code class="highlighter-rouge">PROVISIONING_PROFILE_SPECIFIER = EXTENSION_PROVISIONING_PROFILE_SPECIFIER</code></li>
</ul>
<p>Now you can control individual provisioning profile specifiers for each target, or even put them in a <code class="highlighter-rouge">xcconfig</code> file and use that file to override build settings.</p>
<p>In any case, it’ still helpful to be able to parse the provisioning profile, e.g. if you want to have some post build verification to make sure the correct profile has been used for the build.</p>
<p>Start with dropping all the digital signature stuff and getting just the profile XML (plist) part.</p>
<script src="https://gist.github.com/cd82c1d6776432e0f72080d72bd1b06f.js"> </script>
<p>I can’t tell you what <em>exactly</em> all arguments of <code class="highlighter-rouge">security</code> command mean, you may find better answers in the <a href="http://www.objc.io/issue-17/inside-code-signing.html">Inside Code Signing</a> article, where I learned about this command and other commands you will see in the rest of this post. The result is saved to <code class="highlighter-rouge">profile.plist</code>.</p>
<p>Now you have a plist with all the data. Let’s get UUID first. The tool that can work with plists is <code class="highlighter-rouge">/usr/libexec/PlistBuddy</code>.</p>
<script src="https://gist.github.com/281a61bc772983c8d5f404fb2cad8927.js"> </script>
<p>This doesn’t need much explanation. If you run this command you will get the UUID of the profile as an output.</p>
<p>Next is signing identity, which is a bit more difficult. Signing identity name is not stored as plain text in the profile, however, it is part of the certificate. The profile stores all associated certificates in <code class="highlighter-rouge">DeveloperCertificates</code> key-value pair. That’s right, there can be more than one certificate associated with one provisioning profile. It’s hard to figure out which of the certificates to pick automatically. The assumption is that all of those certificates are valid and any of them can be used to sign the app bundle. If that’s not the case, you need to tidy up things in your developer portal. Sigh can actually help you to do that from command line as well. Anyway, let’s assume the first certificate is the one you need, time to get it.</p>
<script src="https://gist.github.com/7b3453c593c9845f971c08b1a7e864bf.js"> </script>
<p>Oops, looks rather ugly. Seems like PlistBuddy is doing some base 64 decoding under the hood. You can feed this output to <code class="highlighter-rouge">base64</code> utility to encode it back and see the same data as in plist, but do you really need to? Instead, just feed this unreadable data directly to <code class="highlighter-rouge">openssl</code> and ask for the subject field.</p>
<script src="https://gist.github.com/1abcd3f21110e293b55d23ee74783267.js"> </script>
<p>The output is something like</p>
<script src="https://gist.github.com/6a692924876abf25a60bd4c869dd06f4.js"> </script>
<p>You only need to get Common Name (CN) part. At the moment I didn’t find anything better than using <code class="highlighter-rouge">sed</code> as you can see below. It extracts the string between “/CN=” and “/OU=”. I don’t know in which flavors certificates come, could be this regex needs adjustments in case the order of fields in subject is different.</p>
<script src="https://gist.github.com/03305cac3b7af5d940a6e6a977e1234e.js"> </script>
<p>Alternatively, you can use this regex</p>
<script src="https://gist.github.com/fa522da226c3a236a7074fe05000f4b6.js"> </script>
<p>It works with the assumption there are no <code class="highlighter-rouge">/</code>s in the common name. I think the message here is</p>
<blockquote>
<p>Be reasonable and don’t use <code class="highlighter-rouge">=</code>s or <code class="highlighter-rouge">/</code>s when naming new certificate.</p>
</blockquote>
<h2 id="summary">Summary</h2>
<p>So now you have a way to download and parse provisioning profile. Automatically, in one go. With little bit of work you can come up with a proper shell script for the task.</p>
<script src="https://gist.github.com/8d722a2cf263fbff81b40527c61e88f0.js"> </script>
<p>Wit a bit more work you can refactor it to take username, team id and other parameters as input arguments.</p>
https://mgrebenets.github.io/mobile%20ci/2015/05/15/provisioning-profiles-sigh
https://mgrebenets.github.io/mobile%20ci/2015/05/15/provisioning-profiles-sigh2015-05-15T00:00:00+00:00Hacker Rank in Swift - Reuse Code
<p>[<font color="red">OUTDATED</font>]</p>
<p>Reuse Swift IO code for multiple <a href="https://hackerrank.com">HackerRank</a> assignments.</p>
<!--more-->
<p>If you have read <a href="/hackerrank/2015/03/15/hackerrank-in-swift-io">this article</a>, you have probably noticed that code to read from stdin must be copied to each assignment file. Even though you need to copy-paste entire solution to HackerRank web site, this goes against <a href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY</a> principle. In this post I’ll explain how you can keep all stdin code in one file and use it to run code for assignments.</p>
<p>Start by grabbing Swift code, you can use <a href="https://github.com/mgrebenets/hackerrank/blob/master/StdIO.swift">this file</a> for example. Put it in a file, name it <code class="highlighter-rouge">StdIO.swift</code> and put it in the root of your HackerRank folder alongside the makefile from <a href="/hackerrank/2015/03/16/hackerrank-in-swift-makefiles">this post</a> (you’ll need that makefile later on).</p>
<h1 id="swift-module">Swift Module</h1>
<p>For next step you should have 2 files. A <code class="highlighter-rouge">StdIO.swift</code> file created earlier and, say, <code class="highlighter-rouge">solve-me-first.swift</code> for the <a href="https://www.hackerrank.com/challenges/solve-me-first">warmup assignment</a>.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">a</span><span class="p">:</span> <span class="kt">Int</span> <span class="o">=</span> <span class="nf">readLn</span><span class="p">()</span>
<span class="k">let</span> <span class="nv">b</span><span class="p">:</span> <span class="kt">Int</span> <span class="o">=</span> <span class="nf">readLn</span><span class="p">()</span>
<span class="nf">println</span><span class="p">(</span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">)</span>
</code></pre></div></div>
<p>If you try to run <code class="highlighter-rouge">solve-me-first.swift</code> with makefile created in the article mentioned before, you’ll get nowhere. Swift compiler has no idea where to look for <code class="highlighter-rouge">readLn</code> methods, so it can’t interpret this script file alone. We have to build a Swift Module for <code class="highlighter-rouge">StdIO.swift</code> and then link it with our main Swift file.</p>
<p>Check out <a href="http://railsware.com/blog/2014/06/26/creation-of-pure-swift-module/">this</a> and <a href="http://stackoverflow.com/questions/25860471/xcrun-swift-on-command-line-generate-unknown0-error-could-not-load-shared-l">this</a> link to find out more about building a Swift module. I’ll just provide a summary here. Once a Swift Module for <code class="highlighter-rouge">StdIO.swift</code> is built, it will consist of 3 files:</p>
<ul>
<li><code class="highlighter-rouge">StdIO.swiftmodule</code> - public interface and definitions. An analogue of header files from Objective-C world.</li>
<li><code class="highlighter-rouge">StdIO.swiftdoc</code> - documentation.</li>
<li><code class="highlighter-rouge">libStdIO.dylib</code> - a shared (aka dynamic) library. That’s actually a binary that has all all your code compiled, much alike dynamic library for C, C++, Objective-C and so on. There’s a way to build a static (<code class="highlighter-rouge">.a</code>) library as well.</li>
</ul>
<p>In general, Swift Module can include more than one Swift file. It just so happens that we have only one. To build a module you need to run this command</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Get location of OS X SDK.</span>
<span class="nb">export </span><span class="nv">OSX_SDK</span><span class="o">=</span><span class="k">$(</span>xcrun <span class="nt">--show-sdk-path</span> <span class="nt">--sdk</span> macosx<span class="k">)</span>
<span class="c"># Build StdIO module (use `xcrun swiftc` for OS X 10.9).</span>
swiftc <span class="nt">-sdk</span> <span class="k">${</span><span class="nv">OSX_SDK</span><span class="k">}</span> <span class="se">\</span>
<span class="nt">-emit-library</span> <span class="se">\</span>
<span class="nt">-emit-module</span> StdIO.swift <span class="se">\</span>
<span class="nt">-module-name</span> StdIO
</code></pre></div></div>
<p>The options are instructing compiler to emit Swift module and shared library. Compiler also needs to know which SDK to build for. As expected, you should have 3 new files created.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>StdIO.swiftdoc
StdIO.swiftmodule
libStdIO.dylib
</code></pre></div></div>
<p>That’s great, the module is ready. Next step is to link it with your main Swift file and run the code. Before you run any command in the shell, you need to add one more line to <code class="highlighter-rouge">solve-me-first.swift</code> file.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"># This line is new, import StdIO module</span>
<span class="kd">import</span> <span class="kt">StdIO</span>
<span class="k">let</span> <span class="nv">a</span><span class="p">:</span> <span class="kt">Int</span> <span class="o">=</span> <span class="nf">readLn</span><span class="p">()</span>
<span class="k">let</span> <span class="nv">b</span><span class="p">:</span> <span class="kt">Int</span> <span class="o">=</span> <span class="nf">readLn</span><span class="p">()</span>
<span class="nf">println</span><span class="p">(</span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">)</span>
</code></pre></div></div>
<p>Now it’s time to link the two and run the code. This time we can use <code class="highlighter-rouge">swift</code> command.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Get location of OS X SDK</span>
<span class="nb">export </span><span class="nv">OSX_SDK</span><span class="o">=</span><span class="k">$(</span>xcrun <span class="nt">--show-sdk-path</span> <span class="nt">--sdk</span> macosx<span class="k">)</span>
<span class="nb">cat </span>tc/solve-me-first-tc0.txt | <span class="se">\</span>
swift <span class="se">\</span>
<span class="nt">-sdk</span> <span class="k">${</span><span class="nv">OSX_SDK</span><span class="k">}</span> <span class="se">\</span>
<span class="nt">-l</span><span class="k">$(</span><span class="nb">pwd</span><span class="k">)</span>/libStdIO.dylib <span class="se">\</span>
<span class="nt">-I</span> <span class="k">$(</span><span class="nb">pwd</span><span class="k">)</span> <span class="nt">-module-link-name</span> StdIO <span class="se">\</span>
solve-me-first.swift
</code></pre></div></div>
<p>Let’s talk about each option separately.</p>
<ul>
<li><code class="highlighter-rouge">-l<library></code> - this is a flag that should be followed by the name of the library to link with.
<ul>
<li>Actually, <code class="highlighter-rouge">-lStdIO</code> works as well, but that’s because <code class="highlighter-rouge">libStdIO.dylib</code> is sitting in the same folder. I choose to be more verbose and use the full path to shared library. My intentions will become clear later when we talk about makefiles.</li>
</ul>
</li>
<li><code class="highlighter-rouge">-I <import-path></code> - this flag is used to specify import path. Similar to include path in Objective-C world, this way we tell the compiler where to look for Swift modules to resolve <code class="highlighter-rouge">import</code> statements in the code.
<ul>
<li>Once again, instead of specifying current folder as <code class="highlighter-rouge">.</code>, I’m using full path. That will be explained later.</li>
</ul>
</li>
<li><code class="highlighter-rouge">-module-link-name <name></code> - well, it expects a name of the module to link with.</li>
</ul>
<blockquote>
<p>Actually, this is a bit of a cheat. This second command does not compile the code, but interprets it while linking with existing module. There is a way to use Swift compiler here as well, you can find the reference in the end of this post.</p>
</blockquote>
<p>OK, so run this command and you should get a (high) <code class="highlighter-rouge">5</code> as output. Replace the name of the test case file and the name of Swift file and you can run code for any other assignment. But that is too verbose. It should be automated with…</p>
<h2 id="makefile">Makefile</h2>
<p>… with Makefile, of course. With small effort we can convert shell script into a makefile script.</p>
<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Makefile
</span>
<span class="c"># Actual directory of this Makefile, not where it is called form
</span><span class="nv">SELF_DIR</span> <span class="o">:=</span> <span class="err">$</span><span class="o">(</span>dir <span class="err">$</span><span class="o">(</span>lastword <span class="nv">$(MAKEFILE_LIST)</span><span class="o">))</span>
<span class="c"># Build directory
</span><span class="nv">BUILD_DIR</span> <span class="o">:=</span> <span class="nv">$(CURDIR)</span>/build
<span class="c"># OSX SDK
</span><span class="nv">OSX_SDK</span> <span class="o">:=</span> <span class="nf">$(</span><span class="nb">shell</span> xcrun <span class="nt">--show-sdk-path</span> <span class="nt">--sdk</span> macosx<span class="nv">)</span>
<span class="c"># Swift executables and StdIO library name
# TODO: 10.9 use 'xcrun swift(c)', since 10.10 can use just 'swift(c)'
</span><span class="nv">SWIFT</span> <span class="o">=</span> swift
<span class="nv">SWIFTC</span> <span class="o">=</span> swiftc
<span class="nv">SWIFT_STDIO</span> <span class="o">=</span> StdIO
<span class="nv">SWIFT_STDIO_LIB_NAME</span> <span class="o">=</span> lib<span class="nv">$(SWIFT_STDIO)</span>.dylib
<span class="c"># Test cases configuration
</span><span class="nv">TC_DIR</span> <span class="o">=</span> tc
<span class="nv">TC</span> <span class="o">=</span> 0
<span class="nv">tc-path</span> <span class="o">=</span> <span class="nv">$(TC_DIR)</span>/<span class="err">$</span><span class="o">(</span>patsubst %.<span class="err">$</span><span class="o">(</span>2<span class="o">)</span>,%-tc<span class="err">$</span><span class="o">(</span>1<span class="o">)</span>.txt,<span class="err">$</span><span class="o">(</span>3<span class="o">))</span>
<span class="c"># Enable phony targets
</span><span class="nl">.PHONY</span><span class="o">:</span>
<span class="c"># Swift compile and run
</span><span class="nl">%.swift</span><span class="o">:</span> <span class="nf">.PHONY</span>
<span class="p">@</span>mkdir <span class="nt">-p</span> <span class="nv">$(BUILD_DIR)</span>
<span class="err">@</span><span class="c"># build stdio module
</span> <span class="err">@$(SWIFTC)</span> <span class="err">\</span>
<span class="err">-sdk</span> <span class="err">$(OSX_SDK)</span> <span class="err">\</span>
<span class="err">-emit-library</span> <span class="err">\</span>
<span class="err">-o</span> <span class="err">$(BUILD_DIR)/$(SWIFT_STDIO_LIB_NAME)</span> <span class="err">\</span>
<span class="err">-emit-module</span> <span class="err">$(SELF_DIR)/$(SWIFT_STDIO).swift</span> <span class="err">\</span>
<span class="err">-module-name</span> <span class="err">$(SWIFT_STDIO)</span>
<span class="err">@</span><span class="c"># run linking against stdio module
</span> <span class="err">@cat</span> <span class="err">$(call</span> <span class="err">tc-path,$(TC),swift,$@)</span> <span class="err">\</span>
<span class="err">|</span> <span class="err">$(SWIFT)</span> <span class="err">\</span>
<span class="err">-sdk</span> <span class="err">$(OSX_SDK)</span> <span class="err">\</span>
<span class="err">-l$(BUILD_DIR)/$(SWIFT_STDIO_LIB_NAME)</span> <span class="err">\</span>
<span class="err">-I</span> <span class="err">$(BUILD_DIR)</span> <span class="err">-module-link-name</span> <span class="err">$(SWIFT_STDIO)</span> <span class="err">\</span>
<span class="err">$@</span>
</code></pre></div></div>
<p>OK, so let’s walk the code.</p>
<p>First we declare 3 variables: <code class="highlighter-rouge">SELF_DIR</code>, <code class="highlighter-rouge">BUILD_DIR</code> and <code class="highlighter-rouge">OSX_SDK</code>.</p>
<ul>
<li><code class="highlighter-rouge">SELF_DIR</code> is an absolute path to the location of the makefile itself. We need to know this information, because we also know that <code class="highlighter-rouge">StdIO.swift</code> is located in the same folder as <code class="highlighter-rouge">Makefile</code>. It is <em>not</em> the same as <code class="highlighter-rouge">$(CURDIR)</code>, <code class="highlighter-rouge">$(CURDIR)</code> is the folder you run makefile <em>from</em>.</li>
<li><code class="highlighter-rouge">BUILD_DIR</code> is the place to put build output. Don’t forget to put it in your <code class="highlighter-rouge">.gitignore</code> and remove it as part of <code class="highlighter-rouge">clean</code> target.</li>
<li><code class="highlighter-rouge">OSX_SDK</code> is the path to current Mac OS X SDK.</li>
</ul>
<p>One important note is the use of <code class="highlighter-rouge">:=</code> instead of just <code class="highlighter-rouge">=</code> when assigning values to the variables. If right side of assignment is one of the makefile functions, like <code class="highlighter-rouge">shell</code> to execute shell command, or <code class="highlighter-rouge">dir</code>, then each time you reference a variable, for example <code class="highlighter-rouge">$(OSX_SDK)</code>, the shell command will be executed. If the command is expensive, this will slow down execution of your makefile targets. Using <code class="highlighter-rouge">:=</code> ensures that variable is assigned a value only when initialized, when it’s reference later on it uses that initial value.</p>
<p>Next block declares group of variables used as a reference to Swift executables, StdIO module and library name.</p>
<p>Then there are 2 variables and 2 functions related to test cases configuration. To get more details about <code class="highlighter-rouge">tc-path</code> function, check out <a href="/hackerrank/2015/03/16/hackerrank-in-swift-makefiles">previous post</a>. Declaring targets as phony is something that’s explained in that article as well.</p>
<p>Finally, the <code class="highlighter-rouge">%.swift</code> target runs all the compile commands. This code is almost identical to the shell code we had before, with minor differences.</p>
<ul>
<li><code class="highlighter-rouge">-o <library-name></code> option is used to explicitly tell compiler to put library file and accompanying module files into a build directory. That’s just to keep your workspace clean of compiler output.</li>
<li>file name for <code class="highlighter-rouge">-emit-module</code> is referencing <code class="highlighter-rouge">$(SELF_DIR)</code> variable to find <code class="highlighter-rouge">StdIO.swift</code> in the same folder as <code class="highlighter-rouge">Makefile</code> file.</li>
</ul>
<p>Give it a try and run it.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Using `make` directly</span>
make <span class="nt">-f</span> ../../Makefile solve-me-first.swift
<span class="c"># Using `hrrun` alias</span>
hrrun solve-me-first.swift
</code></pre></div></div>
<p><code class="highlighter-rouge">hrrun</code> is an alias defined in <a href="/hackerrank/2015/03/16/hackerrank-in-swift-makefiles">previous article</a> as well.</p>
<p>So it works now and you can keep stdin code separately and reuse it in assignments source. By now you know how to run code in interpreter and how to compile it, wouldn’t it be nice to be able to choose any of the two options?</p>
<h2 id="interpret-or-compile">Interpret or Compile</h2>
<p>Since makefiles support if-else flow control statements, you can add a conditional statement and split your makefile code in 2 parts, one for running code using interpreters, another to compile before running. It’s as easy as this</p>
<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Makefile
</span>
<span class="c"># Compile (YES) vs interpret (NO)
</span><span class="nv">COMPILE</span> <span class="o">=</span> NO
<span class="c"># Enable phony targets
</span><span class="nl">.PHONY</span><span class="o">:</span>
<span class="err">ifeq</span> <span class="err">($(COMPILE),</span> <span class="err">NO)</span> <span class="c"># Interpret
</span>
<span class="c"># Swift
</span><span class="nl">%.swift</span><span class="o">:</span> <span class="nf">.PHONY</span>
<span class="c"># TODO: Interpret</span>
<span class="err">else</span> <span class="c"># Compile and run
</span>
<span class="c"># Swift compile and run
</span><span class="nl">%.swift</span><span class="o">:</span> <span class="nf">.PHONY</span>
<span class="c"># TODO: Compile and run</span>
<span class="err">endif</span>
</code></pre></div></div>
<p>By controlling value of <code class="highlighter-rouge">COMPILE</code> variable you can choose one of the two ways to run assignments code. Another alias would be handy as well.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">HACKER_RANK_HOME</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">HOME</span><span class="k">}</span><span class="s2">/Projects/hackerrank"</span>
<span class="nb">alias </span><span class="nv">hrrun</span><span class="o">=</span><span class="s2">"make -f </span><span class="k">${</span><span class="nv">HACKER_RANK_HOME</span><span class="k">}</span><span class="s2">/Makefile"</span>
<span class="nb">alias </span><span class="nv">hrrunc</span><span class="o">=</span><span class="s2">"make -f </span><span class="k">${</span><span class="nv">HACKER_RANK_HOME</span><span class="k">}</span><span class="s2">/Makefile COMPILE=YES"</span>
</code></pre></div></div>
<h2 id="summary">Summary</h2>
<p>You can now do the same thing for Haskell, Python, C, C++, Java or any other language that support compilation. Grab the latest version of <a href="https://github.com/mgrebenets/hackerrank/blob/master/Makefile">Makefile</a> for your reference, and happy HackerRanking!</p>
https://mgrebenets.github.io/hackerrank/2015/03/17/hackerrank-in-swift-reuse-io
https://mgrebenets.github.io/hackerrank/2015/03/17/hackerrank-in-swift---reuse-io2015-03-17T00:00:00+00:00HackerRank in Swift - Makefiles
<p>A basic makefile to help you with testing your <a href="https://hackerrank.com">HackerRank</a> solutions locally.</p>
<!--more-->
<p>So you are into HackerRank and want to be able to run the code locally before submitting it. This is useful when you have one of the test cases failing and you want to debug it and find the problem.</p>
<p>In this article I’ll show how you can run Haskell and Swift code locally via command line in a convenient way.</p>
<h1 id="manual-mode">Manual Mode</h1>
<p>Before you automate any process, you need to understand what’s there to automate in the first place. The usual approach is to run all the commands manually, so you can notice common patterns and find out certain edge-cases.</p>
<p>Let’s look at first challenge, which is already solved <a href="/hackerrank/2015/03/15/hackerrank-in-swift-io">in this article</a>. Let’s agree that all test cases will be put in <code class="highlighter-rouge">tc</code> folder, then create <code class="highlighter-rouge">tc/solve-me-first-tc0.txt</code> with the following contents.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2
3
</code></pre></div></div>
<p>The <code class="highlighter-rouge">tc<N></code> part of the file name stands for “test case N”, the default test case provided as part of assignment has index <code class="highlighter-rouge">0</code>. So to run your code against test cases 0 and 1, you would run commands like these.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Haskell</span>
<span class="nb">cat </span>tc/solve-me-first-tc0.txt | runghc solve-me-first.hs
<span class="nb">cat </span>tc/solve-me-first-tc1.txt | runghc solve-me-first.hs
<span class="c"># Swift (use `xcrun swift` for OS X 10.9)</span>
<span class="nb">cat </span>tc/solve-me-first-tc0.txt | swift solve-me-first.hs
<span class="nb">cat </span>tc/solve-me-first-tc1.txt | swift solve-me-first.hs
</code></pre></div></div>
<p>Clearly there’s a pattern there, let’s express it using bash syntax.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Test cases directory</span>
<span class="nv">TC_DIR</span><span class="o">=</span>tc
<span class="c"># Test case number</span>
<span class="nv">TC</span><span class="o">=</span>0
<span class="c"># Base name for assignment</span>
<span class="nv">ASSIGNMENT</span><span class="o">=</span>solve-me-first
<span class="c"># Run Haskell, test case 0</span>
<span class="c"># Interpreter command</span>
<span class="nv">CMD</span><span class="o">=</span>runghc
<span class="c"># File name extension</span>
<span class="nv">EXT</span><span class="o">=</span>hs
<span class="nb">cat</span> <span class="k">${</span><span class="nv">TC_DIR</span><span class="k">}</span>/<span class="k">${</span><span class="nv">ASSIGNMENT</span><span class="k">}</span><span class="nt">-tc</span><span class="k">${</span><span class="nv">TC</span><span class="k">}</span>.txt | <span class="k">${</span><span class="nv">CMD</span><span class="k">}</span> <span class="k">${</span><span class="nv">ASSIGNMENT</span><span class="k">}</span>.<span class="k">${</span><span class="nv">EXT</span><span class="k">}</span>
<span class="c"># Run Swift, test case 1</span>
<span class="c"># Interpreter command</span>
<span class="nv">CMD</span><span class="o">=</span>swift
<span class="c"># File name extension</span>
<span class="nv">EXT</span><span class="o">=</span>swift
<span class="nv">TC</span><span class="o">=</span>1 <span class="nb">cat</span> <span class="k">${</span><span class="nv">TC_DIR</span><span class="k">}</span>/<span class="k">${</span><span class="nv">ASSIGNMENT</span><span class="k">}</span><span class="nt">-tc</span><span class="k">${</span><span class="nv">TC</span><span class="k">}</span>.txt | <span class="k">${</span><span class="nv">CMD</span><span class="k">}</span> <span class="k">${</span><span class="nv">ASSIGNMENT</span><span class="k">}</span>.<span class="k">${</span><span class="nv">EXT</span><span class="k">}</span>
</code></pre></div></div>
<p>The script above is a valid bash script. With little work you can turn it into a script that takes file name as a argument and does all the magic of figuring out the extension and interpreter command under the hood, but there is a better way (in my humble opinion).</p>
<h1 id="makefile">Makefile</h1>
<p>Yes, makefiles. I already <a href="/mobile%20ci/2015/02/08/mobile-ci-makefiles">wrote about them</a> in regards to automating mobile CI tasks. Check that write up if you need to refresh some make and makefile basics. So let’s turn bash script from previous paragraph into a makefile.</p>
<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Makefile
</span>
<span class="c"># Test cases directory
</span><span class="nv">TC_DIR</span> <span class="o">=</span> tc
<span class="c"># Test case number
</span><span class="nv">TC</span> <span class="o">=</span> 0
<span class="c"># Enable phony targets
</span><span class="nl">.PHONY</span><span class="o">:</span>
<span class="c"># Haskell
</span><span class="nl">%.hs</span><span class="o">:</span> <span class="nf">.PHONY</span>
<span class="p">@</span><span class="nb">cat</span> <span class="nv">$(TC_DIR)</span>/<span class="err">$</span><span class="o">(</span>patsubst %.hs,%-tc<span class="nv">$(TC)</span>.txt,<span class="nv">$@</span><span class="o">)</span> | runghc <span class="nv">$@</span>
<span class="c"># Swift
</span><span class="nl">%.swift</span><span class="o">:</span> <span class="nf">.PHONY</span>
<span class="p">@</span><span class="nb">cat</span> <span class="nv">$(TC_DIR)</span>/<span class="err">$</span><span class="o">(</span>patsubst %.swift,%-tc<span class="nv">$(TC)</span>.txt,<span class="nv">$@</span><span class="o">)</span> | swift <span class="nv">$@</span>
<span class="nl">help</span><span class="o">:</span>
<span class="p">@</span><span class="nb">echo</span> <span class="s2">"Run test case </span><span class="nv">$(TC)</span><span class="s2"> for given source file."</span>
<span class="p">@</span><span class="nb">echo</span> <span class="s2">"Use TC variable to specify test case number."</span>
<span class="p">@</span><span class="nb">echo</span> <span class="s2">"Targets:"</span>
<span class="p">@</span><span class="nb">echo</span> <span class="s2">"</span><span class="se">\t</span><span class="s2">- .hs files for Haskell."</span>
<span class="p">@</span><span class="nb">echo</span> <span class="s2">"</span><span class="se">\t</span><span class="s2">- .swift files for Swift."</span>
</code></pre></div></div>
<p>Nice feature or makefiles is pattern matching for targets based on the input. If you run this makefile specifying Haskell source file as input (that means file has <code class="highlighter-rouge">.hs</code> extension), it will match agains <code class="highlighter-rouge">%.hs</code> target and run commands for Haskell. <code class="highlighter-rouge">patsubst</code> is short for “path substitution” and turns input file name into a test case file name, here <code class="highlighter-rouge">$@</code> is the way to refer to target name.</p>
<p>Save it as, say, <code class="highlighter-rouge">Makefile</code> and give it a try.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Run Haskell for default test case (0)</span>
make <span class="nt">-f</span> Makefile solve-me-first.hs
<span class="c"># Run Swift for test case 1 (you have to create one)</span>
make <span class="nt">-f</span> Makefile solve-me-first.hs <span class="nv">TC</span><span class="o">=</span>1
</code></pre></div></div>
<p>Works as expected. All you have to do now for each new assignment is to create source file and test case files and then run <code class="highlighter-rouge">make</code>. Annoying part is that you have to specify makefile name explicitly each time. Say, you have <code class="highlighter-rouge">hackerrank</code> directory with <code class="highlighter-rouge">Makefile</code> in it, and you organize assignments in their own directories.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hackerrank
├── Makefile
├── alg
│ ├── arr-n-srt
│ │ └── tc
│ ├── geometry
│ │ └── tc
│ └── warmup
│ └── tc
└── shell
</code></pre></div></div>
<p>So if your working directory is <code class="highlighter-rouge">warmup</code> and you want to run assignment code from there, you have to do somethign like this</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>make <span class="nt">-f</span> ../../Makefile solve-me-first.hs
</code></pre></div></div>
<p>The solution is to use an alias like this</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># in your shell profile (.bash_profile, .zshrc, etc.)</span>
<span class="nv">HACKER_RANK_HOME</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">HOME</span><span class="k">}</span><span class="s2">/Projects/hackerrank"</span>
<span class="nb">alias </span><span class="nv">hrrun</span><span class="o">=</span><span class="s2">"make -f </span><span class="k">${</span><span class="nv">HACKER_RANK_HOME</span><span class="k">}</span><span class="s2">/Makefile"</span>
</code></pre></div></div>
<p>Put this alias in your shell profile and now running assignments code from any folder is as easy as</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hrrun solve-me-first.hs
hrrun solve-me-first.swift <span class="nv">TC</span><span class="o">=</span>1
</code></pre></div></div>
<h1 id="optimize-makefile">Optimize Makefile</h1>
<p>Just like with shell scripts, there a bits of reusable code noticeable in the makefile. With use of functions and bit of refactoring, it can be turned into this.</p>
<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Test cases directory
</span><span class="nv">TC_DIR</span> <span class="o">=</span> tc
<span class="c"># Test case number
</span><span class="nv">TC</span> <span class="o">=</span> 0
<span class="c"># Get the path to test case file
# usage: $(call tc-path,TC,EXT,FILE)
# where:
# TC - test case number
# EXT - file extension (e.g. hs, swift, rb, py, etc.)
# FILE - name of the source file (use $@ to pass it from recipe)
</span><span class="nv">tc-path</span> <span class="o">=</span> <span class="nv">$(TC_DIR)</span>/<span class="err">$</span><span class="o">(</span>patsubst %.<span class="err">$</span><span class="o">(</span>2<span class="o">)</span>,%-tc<span class="err">$</span><span class="o">(</span>1<span class="o">)</span>.txt,<span class="err">$</span><span class="o">(</span>3<span class="o">))</span>
<span class="c"># Run test case using interpreter
# usage: $(call run-tc,TC,EXT,FILE,CMD)
# where:
# TC - test case number
# EXT - file extension (e.g. hs, swift, rb, py, etc.)
# FILE - name of the source file (use $@ to pass it from recipe)
# CMD - interpreter command to run the source file (e.g. runghc, xcrun swift, etc.)
</span><span class="nv">run-tc</span> <span class="o">=</span> <span class="nb">cat</span> <span class="err">$</span><span class="o">(</span>call tc-path,<span class="err">$</span><span class="o">(</span>1<span class="o">)</span>,<span class="err">$</span><span class="o">(</span>2<span class="o">)</span>,<span class="err">$</span><span class="o">(</span>3<span class="o">))</span> | <span class="err">$</span><span class="o">(</span>4<span class="o">)</span> <span class="nv">$@</span>
<span class="c"># Enable phony targets
</span><span class="nl">.PHONY</span><span class="o">:</span>
<span class="c"># Haskell
</span><span class="nl">%.hs</span><span class="o">:</span> <span class="nf">.PHONY</span>
<span class="p">@</span><span class="err">$</span><span class="o">(</span>call run-tc,<span class="nv">$(TC)</span>,hs,<span class="nv">$@</span>,runghc<span class="o">)</span>
<span class="c"># Swift
</span><span class="nl">%.swift</span><span class="o">:</span> <span class="nf">.PHONY</span>
<span class="p">@</span><span class="err">$</span><span class="o">(</span>call run-tc,<span class="nv">$(TC)</span>,swift,<span class="nv">$@</span>,swift<span class="o">)</span>
<span class="nl">help</span><span class="o">:</span>
<span class="p">@</span><span class="nb">echo</span> <span class="s2">"Run test case </span><span class="nv">$(TC)</span><span class="s2"> for given source file."</span>
<span class="p">@</span><span class="nb">echo</span> <span class="s2">"Use TC variable to specify test case number."</span>
<span class="p">@</span><span class="nb">echo</span> <span class="s2">"Targets:"</span>
<span class="p">@</span><span class="nb">echo</span> <span class="s2">"</span><span class="se">\t</span><span class="s2">- .hs files for Haskell."</span>
<span class="p">@</span><span class="nb">echo</span> <span class="s2">"</span><span class="se">\t</span><span class="s2">- .swift files for Swift."</span>
</code></pre></div></div>
<p>This can be improved and improved until the moment your internal perfectionist is happy, but let’s stop here for now. More important feature of this makefile is how easy it is to add another <em>interpretable</em> language support, for example Ruby.</p>
<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Makefile
</span>
<span class="c"># ***
</span>
<span class="c"># Ruby
</span><span class="nl">%.rb</span><span class="o">:</span> <span class="nf">.PHONY</span>
<span class="p">@</span><span class="err">$</span><span class="o">(</span>call run-tc,<span class="nv">$(TC)</span>,rb,<span class="nv">$@</span>,ruby<span class="o">)</span>
</code></pre></div></div>
<p>Use slightly modified Ruby solution for <a href="https://www.hackerrank.com/challenges/solve-me-first">Solve me first</a> from HackerRank and try it out.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># solve-me-first.rb</span>
<span class="n">a</span> <span class="o">=</span> <span class="nb">gets</span><span class="p">.</span><span class="nf">to_i</span>
<span class="n">b</span> <span class="o">=</span> <span class="nb">gets</span><span class="p">.</span><span class="nf">to_i</span>
<span class="nb">print</span><span class="p">(</span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">)</span>
</code></pre></div></div>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hrrun solve-me-first.rb
</code></pre></div></div>
<p>Works like a charm. You can add Python, Go, JavaScript and any other <em>interpretable</em> language in this way. I keep putting stress on <em>interpretable</em> because languages like C or C++ would require to compile and link the code before you could run it, but that’s a story for another post…</p>
https://mgrebenets.github.io/hackerrank/2015/03/16/hackerrank-in-swift-makefiles
https://mgrebenets.github.io/hackerrank/2015/03/16/hackerrank-in-swift---makefiles2015-03-16T00:00:00+00:00HackerRank in Swift - StdIn
<p>[<font color="red">OUTDATED</font>]</p>
<p>A way to read standard input for <a href="https://hackerrank.com">HackerRank</a> assignments in Swift.</p>
<!--more-->
<p><a href="https://hackerrank.com">HackerRank</a> is an amazing resource. It features lots of programming assignments from multitude of domains. This is a perfect place to prep yourself up for upcoming interview, to improve your problem solving skills and even to learn a new language.</p>
<p>For all those who follows Swift programming language closely, it is now <a href="https://www.hackerrank.com/environment">supported by HackerRank</a>. So if you are desperate to write some Swift code and don’t have any real projects to apply it, HackerRank might be an excellent place to do just that.</p>
<blockquote>
<p>Well, Swift support with HackerRank has been on and off lately. Few months after I wrote this post Swift 1.2 was released, few days later it disappeared from HackerRank. Probably they have problems catching up with Swift development schedule. In any case you can still solve the problems in Swift and then submit them in bulk once HackerRank engineers get it working.</p>
</blockquote>
<p>Most (if not all) of the assignments require reading data from standard input. The format is usually like this.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><N>
<test-case-1>
<test-case-2>
...
<test-case-N>
</code></pre></div></div>
<p>In this example <code class="highlighter-rouge">N</code> is total number of test cases. It is then followed by <code class="highlighter-rouge">N</code> lines each corresponding to an input for a test case. This is common, but not the only way to provide input. Some assignments would have 2-line test cases or other format. In any case, one common feature between all assignments is that you need to read data line by line. So let’s start with implementation of core <code class="highlighter-rouge">getLine</code> function in Swift.</p>
<h1 id="get-line">Get Line</h1>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">import</span> <span class="kt">Foundation</span>
<span class="c1">// MARK: Standard Input</span>
<span class="c1">/// Reads a line from standard input</span>
<span class="c1">///:returns: string form stdin</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">getLine</span><span class="p">()</span> <span class="o">-></span> <span class="kt">String</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">buf</span> <span class="o">=</span> <span class="kt">String</span><span class="p">()</span>
<span class="k">var</span> <span class="nv">c</span> <span class="o">=</span> <span class="nf">getchar</span><span class="p">()</span>
<span class="c1">// 10 is ascii code for newline</span>
<span class="k">while</span> <span class="n">c</span> <span class="o">!=</span> <span class="kt">EOF</span> <span class="o">&&</span> <span class="n">c</span> <span class="o">!=</span> <span class="mi">10</span> <span class="p">{</span>
<span class="n">buf</span><span class="o">.</span><span class="nf">append</span><span class="p">(</span><span class="kt">UnicodeScalar</span><span class="p">(</span><span class="kt">UInt32</span><span class="p">(</span><span class="n">c</span><span class="p">)))</span>
<span class="n">c</span> <span class="o">=</span> <span class="nf">getchar</span><span class="p">()</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">buf</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The code is straightforward.</p>
<ul>
<li>Declare <code class="highlighter-rouge">buf</code> variable used to accumulate the result string.</li>
<li>Declare <code class="highlighter-rouge">c</code> variable used to read next character from stdin with <code class="highlighter-rouge">getchar</code></li>
<li>Loop until reach the end of file (<code class="highlighter-rouge">EOF</code>), or newline (ASCII code <code class="highlighter-rouge">10</code>)
<ul>
<li>On each iteration append newly read character to the accumulator string</li>
</ul>
</li>
</ul>
<p>You’ve probably heard lots of things about Swift. Among all the things, one very important feature is its interoperability with Objective-C and C languages. This small code snippet isn’t a 100% “pure” Swift code. First of all, it’s using <a href="http://www.opensource.apple.com/source/gcc/gcc-926/libio/stdio/getchar.c">getchar</a> function from C Standard Library made available via <code class="highlighter-rouge">Foundation</code> framework import. No worries though, all these APIs are toll-free bridged to Swift. This also explains a chain of initializers / type-casts when appending new character to accumulator string. <code class="highlighter-rouge">getchar()</code> returns ASCII code of the character of <code class="highlighter-rouge">Int32</code> type. The thing is that Swift’s <a href="http://swiftdoc.org/type/String/">String</a> is not your good old ASCII null-teminated C string, it is actually a collection of <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html">Unicode scalars</a>. Bear in mind, that <em>collection</em> isn’t just a figure of speech, it actually means that <code class="highlighter-rouge">String</code> type conforms to <a href="http://swiftdoc.org/protocol/CollectionType/">CollectionType</a> protocol. Anyway, to create an instance of <a href="http://swiftdoc.org/type/UnicodeScalar/">UnicodeScalar</a> you need to have a value of <code class="highlighter-rouge">UInt32</code> type, hence the conversion of <code class="highlighter-rouge">c</code> to <code class="highlighter-rouge">UInt32</code>.</p>
<blockquote>
<p>An important note. This code <em>will not</em> work properly with actual Unicode input. Anything outside of standard ASCII table will be rendered as some gibberish. Obviously <code class="highlighter-rouge">getchar</code> is not up for the job of reading unicode characters. However, on HackerRank you would never get non-ASCII input (at least for assignments that I saw), so this function does perfect job for its targeted application area.</p>
</blockquote>
<h1 id="read-line">Read Line</h1>
<p>Now when you can get a line, next thing you will want is to convert that line into something else. For example, if the line is just one integer, you would like to convert into a value of <code class="highlighter-rouge">Int</code> type. It it’s a list of integers (space- or comma-, or whatever- separated), you would obviously want to convert it to <code class="highlighter-rouge">Array<Int></code> or <code class="highlighter-rouge">[Int]</code>. And so on and so forth.</p>
<p>I am actually inspired by Haskell here. It has a core <code class="highlighter-rouge">getLine</code> function to get a line as string, then it also has <code class="highlighter-rouge">readLn</code> method, which doesn’t just get the line, but also allows converting it into a value of desired type.</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- Haskell</span>
<span class="c1">-- Read a line and convert to IO Int</span>
<span class="n">n</span> <span class="o"><-</span> <span class="n">readLn</span> <span class="o">::</span> <span class="kt">IO</span> <span class="kt">Int</span>
<span class="c1">-- Get a line and convert (read) it as array of Int</span>
<span class="n">line</span> <span class="o"><-</span> <span class="n">getLine</span>
<span class="kr">let</span> <span class="n">input</span> <span class="o">=</span> <span class="n">read</span> <span class="n">line</span> <span class="o">::</span> <span class="p">[</span><span class="kt">Int</span><span class="p">]</span>
</code></pre></div></div>
<p>So I wanted to have something similar or alike to use in Swift. This is <em>one of</em> solutions.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">/// Read line from standard input</span>
<span class="c1">///:returns: string</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">readLn</span><span class="p">()</span> <span class="o">-></span> <span class="kt">String</span> <span class="p">{</span>
<span class="k">return</span> <span class="nf">getLine</span><span class="p">()</span>
<span class="p">}</span>
<span class="c1">/// Read line from standard input and convert to integer</span>
<span class="c1">///:returns: integer value</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">readLn</span><span class="p">()</span> <span class="o">-></span> <span class="kt">Int</span> <span class="p">{</span>
<span class="k">return</span> <span class="nf">getLine</span><span class="p">()</span><span class="o">.</span><span class="nf">toInt</span><span class="p">()</span><span class="o">!</span>
<span class="p">}</span>
<span class="c1">/// Read line and convert to array of strings (words)</span>
<span class="c1">///:returns: array of strings</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">readLn</span><span class="p">()</span> <span class="o">-></span> <span class="p">[</span><span class="kt">String</span><span class="p">]</span> <span class="p">{</span>
<span class="k">return</span> <span class="nf">getLine</span><span class="p">()</span><span class="o">.</span><span class="nf">componentsSeparatedByCharactersInSet</span><span class="p">(</span><span class="kt">NSCharacterSet</span><span class="o">.</span><span class="nf">whitespaceCharacterSet</span><span class="p">())</span>
<span class="p">}</span>
<span class="c1">/// Read line and convert to array of integers</span>
<span class="c1">///:returns: array of integers</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">readLn</span><span class="p">()</span> <span class="o">-></span> <span class="p">[</span><span class="kt">Int</span><span class="p">]</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">words</span><span class="p">:</span> <span class="p">[</span><span class="kt">String</span><span class="p">]</span> <span class="o">=</span> <span class="nf">readLn</span><span class="p">()</span>
<span class="k">return</span> <span class="n">words</span><span class="o">.</span><span class="n">map</span> <span class="p">{</span> <span class="nv">$0</span><span class="o">.</span><span class="nf">toInt</span><span class="p">()</span><span class="o">!</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Let’s review each function.</p>
<ul>
<li><code class="highlighter-rouge">public func readLn() -> String</code>
<ul>
<li>This is really just an alias for <code class="highlighter-rouge">getLine()</code> as you can clearly see from its implementation.</li>
</ul>
</li>
<li><code class="highlighter-rouge">public func readLn() -> Int</code>
<ul>
<li>This function gets the line and converts it to <code class="highlighter-rouge">Int</code> using <code class="highlighter-rouge">toInt()</code> method. Since <code class="highlighter-rouge">toInt()</code> returns an optional, we have to use explicit unwrapping (<code class="highlighter-rouge">!</code> operator). Needless to say that if the string can’t be parsed into an integer, the code will crash.</li>
</ul>
</li>
<li><code class="highlighter-rouge">public func readLn() -> [Strings]</code>
<ul>
<li>Get the line and parse it into an array of strings. It works from the assumption that default separator is whitespace. Luckily, this is the case with all HackerRank assignments I’ve seen so far. It’s possible to improve this function and pass custom separator string as an argument.</li>
</ul>
</li>
<li><code class="highlighter-rouge">public func readLn() -> [Int]</code>
<ul>
<li>Get the line and parse it into an array of integers. You might have thought that this function <em>kind of</em> calls itself. Of course it’s not true and there’s no recursion here. Because the line <code class="highlighter-rouge">let words: [String] = readLn()</code> explicitly specifies the type of the <code class="highlighter-rouge">words</code> constant, Swift compiler calls the <code class="highlighter-rouge">public func readLn() -> [String]</code> function matching the <code class="highlighter-rouge">[String]</code> type of <code class="highlighter-rouge">words</code>. Once it gets an array of strings, it maps each value to its integer counterpart with <code class="highlighter-rouge">toInt()</code> call.</li>
</ul>
</li>
</ul>
<p>Obviously, you can define as many <code class="highlighter-rouge">readLn</code> functions as you wish, but the sane thing to do is to define new function when particular assignment requires it. For example, somewhere down the middle of Warmup section in Algorithms domain, you will need a function like this.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// An array of (Int, String) tuples</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">readLn</span><span class="p">()</span> <span class="o">-></span> <span class="p">[(</span><span class="kt">Int</span><span class="p">,</span> <span class="kt">String</span><span class="p">)]</span> <span class="p">{</span>
<span class="c1">// ...</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="generics">Generics?</h2>
<p>OK, so when you see 4 <code class="highlighter-rouge">readLn</code> functions that differ by return type only, what does the common sense tell you? And what does each and every functional programming text book recommend in this case? Right - use generics.</p>
<p>But hold on, this is probably the case where generics wouldn’t work right away (I’d be happy to be proven wrong). Generics really work well when lots of functions differ only in types they use, but still have the <em>same</em> implementation details. In this case, each <code class="highlighter-rouge">readLn</code> implementation is specific and there aren’t lots of common patterns to be reused. Let’s have a pseudo-code-thought experiment though.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">func</span> <span class="n">readLn</span><span class="o"><</span><span class="kt">T</span><span class="o">></span><span class="p">()</span> <span class="o">-></span> <span class="kt">T</span> <span class="p">{</span>
<span class="c1">// Not a real Swift code!</span>
<span class="k">switch</span> <span class="kt">T</span> <span class="p">{</span>
<span class="k">case</span> <span class="kt">String</span><span class="p">:</span>
<span class="k">return</span> <span class="nf">getLine</span><span class="p">()</span>
<span class="k">case</span> <span class="kt">Int</span><span class="p">:</span>
<span class="k">return</span> <span class="nf">getLine</span><span class="p">()</span><span class="o">.</span><span class="nf">toInt</span><span class="p">()</span><span class="o">!</span>
<span class="k">case</span> <span class="p">[</span><span class="kt">String</span><span class="p">]:</span>
<span class="k">return</span> <span class="nf">getLine</span><span class="p">()</span><span class="o">.</span><span class="nf">componentsSeparatedByCharactersInSet</span><span class="p">(</span><span class="kt">NSCharacterSet</span><span class="o">.</span><span class="nf">whitespaceCharacterSet</span><span class="p">())</span>
<span class="k">case</span> <span class="p">[</span><span class="kt">Int</span><span class="p">]:</span>
<span class="k">let</span> <span class="nv">words</span><span class="p">:</span> <span class="p">[</span><span class="kt">String</span><span class="p">]</span> <span class="o">=</span> <span class="nf">readLn</span><span class="p">()</span>
<span class="k">return</span> <span class="n">words</span><span class="o">.</span><span class="n">map</span> <span class="p">{</span> <span class="nv">$0</span><span class="o">.</span><span class="nf">toInt</span><span class="p">()</span><span class="o">!</span> <span class="p">}</span>
<span class="k">default</span><span class="p">:</span>
<span class="k">return</span> <span class="nf">getLine</span><span class="p">()</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Now, this is not a real code and would never compile. The reason is that there’s no simple way to do a switch by the type <code class="highlighter-rouge">T</code>. I have found an ugly way to work around this limitation.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">func</span> <span class="n">readLn</span><span class="o"><</span><span class="kt">T</span><span class="o">></span><span class="p">()</span> <span class="o">-></span> <span class="kt">T</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="kt">T</span><span class="o">.</span><span class="k">self</span> <span class="k">as?</span> <span class="kt">String</span><span class="o">.</span><span class="k">Type</span> <span class="o">!=</span> <span class="kc">nil</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nf">getLine</span><span class="p">()</span>
<span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="kt">T</span><span class="o">.</span><span class="k">self</span> <span class="k">as?</span> <span class="kt">Int</span><span class="o">.</span><span class="k">Type</span> <span class="o">!=</span> <span class="kc">nil</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nf">getLine</span><span class="p">()</span><span class="o">.</span><span class="nf">toInt</span><span class="p">()</span><span class="o">!</span>
<span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="kt">T</span><span class="o">.</span><span class="k">self</span> <span class="k">as?</span> <span class="p">[</span><span class="kt">String</span><span class="p">]</span><span class="o">.</span><span class="k">Type</span> <span class="o">!=</span> <span class="kc">nil</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nf">getLine</span><span class="p">()</span><span class="o">.</span><span class="nf">componentsSeparatedByCharactersInSet</span><span class="p">(</span><span class="kt">NSCharacterSet</span><span class="o">.</span><span class="nf">whitespaceCharacterSet</span><span class="p">())</span>
<span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="kt">T</span><span class="o">.</span><span class="k">self</span> <span class="k">as?</span> <span class="p">[</span><span class="kt">Int</span><span class="p">]</span><span class="o">.</span><span class="k">Type</span> <span class="o">!=</span> <span class="kc">nil</span><span class="p">)</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">words</span><span class="p">:</span> <span class="p">[</span><span class="kt">String</span><span class="p">]</span> <span class="o">=</span> <span class="nf">readLn</span><span class="p">()</span>
<span class="k">return</span> <span class="n">words</span><span class="o">.</span><span class="n">map</span> <span class="p">{</span> <span class="nv">$0</span><span class="o">.</span><span class="nf">toInt</span><span class="p">()</span><span class="o">!</span> <span class="p">}</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="k">return</span> <span class="nf">getLine</span><span class="p">()</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The conditions for <code class="highlighter-rouge">if</code>s are actually a valid Swift code, though they don’t look pretty. The code still doesn’t compile. The problem is that each return statement returns one of these types: <code class="highlighter-rouge">String</code>, <code class="highlighter-rouge">Int</code>, <code class="highlighter-rouge">[String]</code> or <code class="highlighter-rouge">[Int]</code>, and compiler doesn’t know how to initialize an instance of type <code class="highlighter-rouge">T</code> with any of these types. Compiler doesn’t really know anything about <code class="highlighter-rouge">T</code>, but it does know that <code class="highlighter-rouge">T</code> gives no guarantee to provide <code class="highlighter-rouge">init(_: Int)</code> or any other initializer.</p>
<p>What you could do next, is to try to come up with a protocol which <code class="highlighter-rouge">T</code> would conform to. Pack all these initializers inside the protocol, and then much more; and probably this path of generic functional madness would take you somewhere after all. But look at this from another angle: even if you succeed in making this generic function to compile and work, you effectively have implementations of each and every separate functions sitting right there, each in its own if-clause. So what’s the point then?</p>
<p>My personal takeaway from this exercise is: do not overcomplicate things. Just think of a group of N different <code class="highlighter-rouge">readLn</code> functions as some single abstract generic function. After all, when you use it in code, that’s exactly how it looks and works.</p>
<h1 id="use">Use</h1>
<p>Finally, after all this abstract talk, it is time to put these standard input functions to a good use.</p>
<p>Let’s start with <a href="https://www.hackerrank.com/challenges/solve-me-first">Solve me first</a>. Here’s the solution in Swift.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">a</span><span class="p">:</span> <span class="kt">Int</span> <span class="o">=</span> <span class="nf">readLn</span><span class="p">()</span> <span class="c1">// calls readLn() -> Int, because a is of Int type</span>
<span class="k">let</span> <span class="nv">b</span><span class="p">:</span> <span class="kt">Int</span> <span class="o">=</span> <span class="nf">readLn</span><span class="p">()</span>
<span class="nf">println</span><span class="p">(</span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">)</span>
</code></pre></div></div>
<p>To test it, make a simple <code class="highlighter-rouge">solve-me-first-tc0.txt</code> file with test input.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2
3
</code></pre></div></div>
<p>Then run this command in the terminal.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Mac OS X 10.9+</span>
<span class="nb">cat </span>solve-me-first-tc0.txt | xcrun swift solve-me-first.swift
<span class="c"># Mac OS X 10.10+</span>
<span class="nb">cat </span>solve-me-first-tc0.txt | swift solve-me-first.swift
</code></pre></div></div>
<p>As expected, the output is <code class="highlighter-rouge">5</code> and you’ve just got your first assignment solved in Swift.</p>
<p>While we are at it, let’s solve the <a href="https://www.hackerrank.com/challenges/solve-me-second">Solve me second</a>. You have to read an array of integers from each line and sum them up. Calculating the sum of all elements in an array is a text book example of using <code class="highlighter-rouge">reduce</code> method.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">n</span><span class="p">:</span> <span class="kt">Int</span> <span class="o">=</span> <span class="nf">readLn</span><span class="p">()</span>
<span class="k">for</span> <span class="n">_</span> <span class="k">in</span> <span class="mi">0</span><span class="o">..<</span><span class="n">n</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">ints</span><span class="p">:</span> <span class="p">[</span><span class="kt">Int</span><span class="p">]</span> <span class="o">=</span> <span class="nf">readLn</span><span class="p">()</span> <span class="c1">// calls readLn() -> [Int]</span>
<span class="k">let</span> <span class="nv">sum</span> <span class="o">=</span> <span class="n">ints</span><span class="o">.</span><span class="nf">reduce</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="o">+</span><span class="p">)</span>
<span class="nf">println</span><span class="p">(</span><span class="n">sum</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Now, if you are one of fresh functional programming converts, you might frown at the for-loop. I had the same feeling originally. Reading a lot about functional approach made me think that <em>any</em> for-loop should be effectively replaced with map, reduce or filter. But is it really so? Swift does have a number of features which are part of functional programming paradigm, but that doesn’t mean that for-loop is now banned from use. For-loop is one of the native Swift idioms and does have its own use where appropriate. As an example, check <a href="http://inessential.com/2015/02/19/looping_through_objects_in_an_array?utm_campaign=This_Week_in_Swift_30&utm_medium=email&utm_source=This%2BWeek%2Bin%2BSwift">this post</a> and <a href="https://devforums.apple.com/message/1105131">related discussion on Apple Developers forum</a>.</p>
<h2 id="summary">Summary</h2>
<p>You now have a handy stdin Swift library to get you going with most of assignments. If you are not a big fan of copy-pasting these functions each time, check out my other posts about <a href="/hackerrank/2015/03/16/hackerrank-in-swift-makefiles">HackerRank makefiles</a> and <a href="/hackerrank/2015/03/17/hackerrank-in-swift-reuse-io">reusing Swift IO library</a>.</p>
https://mgrebenets.github.io/hackerrank/2015/03/15/hackerrank-in-swift-io
https://mgrebenets.github.io/hackerrank/2015/03/15/hackerrank-in-swift---io2015-03-15T00:00:00+00:00Password Generator in Swift
<p>Simple password generator in Swift.</p>
<!--more-->
<p>One day I was chatting with other iOS devs and someone posted an example of password generator code. The code featured “for-i-in” loops and other things which didn’t look much swifty to my eye.</p>
<p>I tried to find a real application for nice Swift features like generators, sequences and some functional methods like <code class="highlighter-rouge">reduce</code>. I went through a number of iterations to get to the final state. Here’s the code I eventually came up with.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">import</span> <span class="kt">Foundation</span>
<span class="kd">struct</span> <span class="kt">PasswordGenerator</span><span class="p">:</span> <span class="kt">SequenceType</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">length</span><span class="p">:</span> <span class="kt">Int</span>
<span class="k">let</span> <span class="nv">characters</span><span class="p">:</span> <span class="kt">Set</span><span class="o"><</span><span class="kt">Character</span><span class="o">></span>
<span class="kd">func</span> <span class="nf">generate</span><span class="p">()</span> <span class="o">-></span> <span class="kt">GeneratorOf</span><span class="o"><</span><span class="kt">Character</span><span class="o">></span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">currentLength</span><span class="p">:</span> <span class="kt">Int</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">return</span> <span class="kt">GeneratorOf</span><span class="o"><</span><span class="kt">Character</span><span class="o">></span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">randomIndex</span> <span class="o">=</span> <span class="kt">Int</span><span class="p">(</span><span class="nf">arc4random_uniform</span><span class="p">(</span><span class="kt">UInt32</span><span class="p">(</span><span class="nf">count</span><span class="p">(</span><span class="k">self</span><span class="o">.</span><span class="n">characters</span><span class="p">))))</span>
<span class="k">let</span> <span class="nv">setIndex</span> <span class="o">=</span> <span class="nf">advance</span><span class="p">(</span><span class="k">self</span><span class="o">.</span><span class="n">characters</span><span class="o">.</span><span class="n">startIndex</span><span class="p">,</span> <span class="n">randomIndex</span><span class="p">)</span>
<span class="nf">return</span> <span class="p">(</span><span class="n">currentLength</span><span class="o">++</span> <span class="o"><</span> <span class="k">self</span><span class="o">.</span><span class="n">length</span> <span class="p">?</span> <span class="k">self</span><span class="o">.</span><span class="n">characters</span><span class="p">[</span><span class="n">setIndex</span><span class="p">]</span> <span class="p">:</span> <span class="kc">nil</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">password</span><span class="p">()</span> <span class="o">-></span> <span class="kt">String</span> <span class="p">{</span>
<span class="k">return</span> <span class="nf">reduce</span><span class="p">(</span><span class="k">self</span><span class="p">,</span> <span class="s">""</span><span class="p">)</span> <span class="p">{</span> <span class="p">(</span><span class="nv">pwd</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="nv">char</span><span class="p">:</span> <span class="kt">Character</span><span class="p">)</span> <span class="o">-></span> <span class="kt">String</span> <span class="k">in</span>
<span class="s">""</span><span class="o">.</span><span class="nf">join</span><span class="p">([</span><span class="n">pwd</span><span class="p">,</span> <span class="kt">String</span><span class="p">(</span><span class="n">char</span><span class="p">)])</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">let</span> <span class="nv">characters</span> <span class="o">=</span> <span class="kt">Set</span><span class="p">(</span><span class="s">"АБВГДAAAAbCd1234567890-=!@#$%^&*()_+QWE˙ÎÓÔ◊ı´¨°•RTYUIOP{}ASDFGHJKL:</span><span class="se">\"</span><span class="s">ZXCVBNM<>?"</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">passwordGenerator</span> <span class="o">=</span> <span class="kt">PasswordGenerator</span><span class="p">(</span><span class="nv">length</span><span class="p">:</span> <span class="mi">10</span><span class="p">,</span> <span class="nv">characters</span><span class="p">:</span> <span class="n">characters</span><span class="p">)</span>
<span class="nf">println</span><span class="p">(</span><span class="n">passwordGenerator</span><span class="o">.</span><span class="nf">password</span><span class="p">())</span>
<span class="nf">println</span><span class="p">(</span><span class="n">passwordGenerator</span><span class="o">.</span><span class="nf">password</span><span class="p">())</span>
<span class="nf">println</span><span class="p">(</span><span class="n">passwordGenerator</span><span class="o">.</span><span class="nf">password</span><span class="p">())</span>
<span class="nf">println</span><span class="p">(</span><span class="n">passwordGenerator</span><span class="o">.</span><span class="nf">password</span><span class="p">())</span>
</code></pre></div></div>
<p>As you can see this code is using Swift 1.2 features, such as new <code class="highlighter-rouge">Set</code> data type.</p>
<p>The general idea is to create a password generator for a given set of characters to generate passwords of the given length. I’m not claiming here that this is the best design ever. Probably it would be better to have a function that takes a set of characters and password length as an input and then do all heavy lifting in that function.</p>
<p>However, let’s walk through this code.</p>
<p>The <code class="highlighter-rouge">PasswordGenerator</code> is a sequence since it conforms to <code class="highlighter-rouge">SequenceType</code> protocol. As part of protocol implementation this struct needs to implement <code class="highlighter-rouge">generate()</code> function that returns another Swift type <code class="highlighter-rouge">Generator</code>. In this example I’m generating characters for a password, so I chose to initialize password generator with a set of characters (<code class="highlighter-rouge">characters</code>) and length of the password to be generated (<code class="highlighter-rouge">length</code>).</p>
<p>Note that I’m not using any unicode specific code at all. That’s the beauty of <code class="highlighter-rouge">String</code> type in Swift. Since <code class="highlighter-rouge">String</code> conforms to the very same <code class="highlighter-rouge">SequenceType</code> it can easily be converted to an array or a set, and what’s even better, it will be an array or a set of <strong>unicode</strong> characters.</p>
<p>OK, so back to <code class="highlighter-rouge">PasswordGenerator</code>. <code class="highlighter-rouge">generate()</code> function returns generator of <code class="highlighter-rouge">Character</code> where <code class="highlighter-rouge">GeneratorOf</code> is another Swift generic type useful to declare generators of a certain type. Inside the function I’m creating a generator of <code class="highlighter-rouge">Character</code> with a closure, this closure captures <code class="highlighter-rouge">currentLength</code> variable as well as <code class="highlighter-rouge">self</code>. The closure first generates a random index of an element in the set using good old <code class="highlighter-rouge">arc4random_uniform</code>. The <code class="highlighter-rouge">randomIndex</code> is of type <code class="highlighter-rouge">Int</code> and can not be used as a set index. The set index in this case needs to be of type <code class="highlighter-rouge">SetIndex<Character></code>. To get set index I’m using standard library function <code class="highlighter-rouge">advance</code> that gives me a <code class="highlighter-rouge">randomIndex</code> set index equivalent for a set. Finally I can get a character from the set, incrementing <code class="highlighter-rouge">currentLength</code> and comparing it to <code class="highlighter-rouge">self.length</code> along the lines to know when to stop. Note the use of <code class="highlighter-rouge">self</code>, this is required because it’s a closure.</p>
<p>Last step is to implement <code class="highlighter-rouge">password()</code> function that actually generates passwords. This is where I can use the fact that <code class="highlighter-rouge">PasswordGenerator</code> is a sequence. Thanks to that I am able to use standard library <code class="highlighter-rouge">reduce</code> on <code class="highlighter-rouge">self</code>. Reduce iterates through the sequence on each step getting a random element from the characters set it then appends new character to accumulator string using <code class="highlighter-rouge">join</code> function.</p>
<p>Without a single for-i-in loop I get a simple password generator that demoes beauty and flexibility of Swift and is yet open for further improvements.</p>
https://mgrebenets.github.io/swift/2015/02/23/password-generator-in-swift
https://mgrebenets.github.io/swift/2015/02/23/password-generator-in-swift2015-02-23T00:00:00+00:00What's your destination?
<p>Few hands on tricks about <code class="highlighter-rouge">-destination</code> option of <code class="highlighter-rouge">xcodebuild</code>.</p>
<!--more-->
<p>Destination option (<code class="highlighter-rouge">-destination</code>) was a new addition to Xcode 5 release. It is documented on <a href="https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/xcodebuild.1.html">xcodebuild man page</a> and you get the same by running <code class="highlighter-rouge">man xcodebuild</code>. This option lets you be more verbose with your <code class="highlighter-rouge">xcodebuild</code> commands. For example, if you have a physical device plugged in, running <code class="highlighter-rouge">xcodebuild</code> with no destination specifier will build the project for this physical device. Using destination specifier you can explicitly tell <code class="highlighter-rouge">xcodebuild</code> to build for simulator.</p>
<p>Allow me just to quote the man page here</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>The <span class="nt">-destination</span> option takes as its argument a destination specifier describing the device <span class="o">(</span>or devices<span class="o">)</span> to use as a destination. A destination specifier is a single argument consisting of a <span class="nb">set </span>of comma-separated <span class="nv">key</span><span class="o">=</span>value pairs. The <span class="nt">-destination</span> option may be specified multiple <span class="nb">times </span>to cause xcodebuild to perform the specified action on multiple destinations.
</code></pre></div></div>
<p>By the way, pay a closer attention to the last sentence. It’s a really nice feature, for example with single command you can run tests on multiple simulators.</p>
<p>One of the keys supported is “platform” and there are 3 options: “OS X”, “iOS” and “iOS Simulator”. Let’s get more details on the last two. iOS and iOS Simulator platforms both require a “name” and “OS” keys to specify device name and iOS version. The question is “How to get list of all names and OS versions?”. There are many ways to do that.</p>
<h1 id="instruments">Instruments</h1>
<p>The Xcode Instruments command line utility has an undocumented <code class="highlighter-rouge">-s</code> option, which lists all devices and templates. By adding <code class="highlighter-rouge">devices</code> to the invocation only devices are be listed.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>instruments <span class="nt">-s</span> devices
<span class="c"># Or</span>
xcrun instruments <span class="nt">-s</span> devices
</code></pre></div></div>
<p>Example output, note that it also includes your Mac as a device.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Known Devices:
R5003398 <span class="o">[</span>5C25B8A6-EDF5-5856-B8B9-CB28DFBFADC4]
Maksym<span class="s1">'s iPhone (8.1.3) [5dc0e5a8a9f7c0af1feea4bfa13860c9e61350d6]
MyIPhone6 (8.1 Simulator) [9151073B-3B7D-441A-8069-E797FA5059CE]
Resizable iPad (8.1 Simulator) [15FC1628-B369-44DE-8CE0-756439D9AEBC]
Resizable iPhone (8.1 Simulator) [5E7A9E8C-D3A8-4E58-935F-8754B100E867]
iPad 2 (7.1 Simulator) [43DD0C31-685F-4FC8-941F-0BB9B305CD2D]
iPad 2 (8.1 Simulator) [8D722A9F-2DA9-45A2-BAFB-44075AA519D6]
iPad Air (7.1 Simulator) [2FB923E2-F0F4-49DE-8FC3-81960386B8CE]
iPad Air (8.1 Simulator) [6032BE94-1A62-4ADB-9013-50FAB2B088F6]
iPad Retina (7.1 Simulator) [F1967F38-BE03-430F-BFB1-AFF4E2E4511C]
iPad Retina (8.1 Simulator) [E8652514-3042-4958-9027-48A9A95392CE]
iPhone 4s (7.1 Simulator) [57DBC56E-1E04-4384-9A07-7B47C119BEAB]
iPhone 4s (8.1 Simulator) [DDF255C3-8BEF-4A97-8B3F-AD651BABF6CB]
iPhone 5 (7.1 Simulator) [BAF484D4-803C-478D-BAC1-916376C22C48]
iPhone 5 (8.1 Simulator) [45E5CE55-093D-48C0-AA26-AA4E5C569FDB]
iPhone 5s (7.1 Simulator) [6856CCCF-842E-48E8-897B-87BB1865CD10]
iPhone 5s (8.1 Simulator) [0AC6BB28-E860-4320-A532-272BE43C067C]
iPhone 6 (8.1 Simulator) [7953EE9F-19E8-4D0C-9219-268FB0BA6626]
iPhone 6 Plus (8.1 Simulator) [E574C367-1BAA-4F9F-BB92-BD5F6BAB1226]
</span></code></pre></div></div>
<h1 id="simctl"><code class="highlighter-rouge">simctl</code></h1>
<p>Another option is to use <code class="highlighter-rouge">xcrun simctl</code>, which is a new addition to Xcode 6. In fact, <code class="highlighter-rouge">simctl</code> looks like a very promising tool that allows you to create, boot, launch and then shutdown and destroy iOS simulators on the fly, and provides commands to install and launch specific apps. If you ever used <a href="https://www.genymotion.com/#!/">Genymotion</a> you might have created Android simulators using <a href="https://www.virtualbox.org/">VirtualBox</a> command line utility, Apple works towards the same flexibility with <code class="highlighter-rouge">simctl</code>.</p>
<p>In context of this article, to see a list of available devices, run this command</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>xcrun simctl list
</code></pre></div></div>
<p>You will get the list of device types, runtimes and devices. Device types and runtimes will be handy if you need to create new simulators. You can tell <code class="highlighter-rouge">simctl</code> to filter output, for example, list devices only</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>xcrun simctl list devices
</code></pre></div></div>
<p>Sample output</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">==</span> Devices <span class="o">==</span>
<span class="nt">--</span> iOS 7.0 <span class="nt">--</span>
iPhone 4s <span class="o">(</span>6CF0F409-F4F8-4BCD-AC4E-30E58947A3EB<span class="o">)</span> <span class="o">(</span>Shutdown<span class="o">)</span> <span class="o">(</span>unavailable<span class="o">)</span>
iPhone 5 <span class="o">(</span>1C08AA1B-9C0C-499B-9570-972EF52941D9<span class="o">)</span> <span class="o">(</span>Shutdown<span class="o">)</span> <span class="o">(</span>unavailable<span class="o">)</span>
iPhone 5s <span class="o">(</span>3DD4CAA5-6CD7-4DFB-AF95-6494EAE6E90F<span class="o">)</span> <span class="o">(</span>Shutdown<span class="o">)</span> <span class="o">(</span>unavailable<span class="o">)</span>
iPad 2 <span class="o">(</span>C4E52F2A-C1C0-408F-8177-5AAF7895D3B5<span class="o">)</span> <span class="o">(</span>Shutdown<span class="o">)</span> <span class="o">(</span>unavailable<span class="o">)</span>
iPad Retina <span class="o">(</span>D145A9C9-DFD0-4564-8A45-BF68A80426AC<span class="o">)</span> <span class="o">(</span>Shutdown<span class="o">)</span> <span class="o">(</span>unavailable<span class="o">)</span>
iPad Air <span class="o">(</span>091FC037-5C7F-45FC-9089-E424A9806D60<span class="o">)</span> <span class="o">(</span>Shutdown<span class="o">)</span> <span class="o">(</span>unavailable<span class="o">)</span>
<span class="nt">--</span> iOS 7.1 <span class="nt">--</span>
iPhone 4s <span class="o">(</span>57DBC56E-1E04-4384-9A07-7B47C119BEAB<span class="o">)</span> <span class="o">(</span>Shutdown<span class="o">)</span>
iPhone 5 <span class="o">(</span>BAF484D4-803C-478D-BAC1-916376C22C48<span class="o">)</span> <span class="o">(</span>Shutdown<span class="o">)</span>
iPhone 5s <span class="o">(</span>6856CCCF-842E-48E8-897B-87BB1865CD10<span class="o">)</span> <span class="o">(</span>Shutdown<span class="o">)</span>
iPad 2 <span class="o">(</span>43DD0C31-685F-4FC8-941F-0BB9B305CD2D<span class="o">)</span> <span class="o">(</span>Shutdown<span class="o">)</span>
iPad Retina <span class="o">(</span>F1967F38-BE03-430F-BFB1-AFF4E2E4511C<span class="o">)</span> <span class="o">(</span>Shutdown<span class="o">)</span>
iPad Air <span class="o">(</span>2FB923E2-F0F4-49DE-8FC3-81960386B8CE<span class="o">)</span> <span class="o">(</span>Shutdown<span class="o">)</span>
<span class="nt">--</span> iOS 8.1 <span class="nt">--</span>
iPhone 4s <span class="o">(</span>DDF255C3-8BEF-4A97-8B3F-AD651BABF6CB<span class="o">)</span> <span class="o">(</span>Shutdown<span class="o">)</span>
iPhone 5 <span class="o">(</span>45E5CE55-093D-48C0-AA26-AA4E5C569FDB<span class="o">)</span> <span class="o">(</span>Shutdown<span class="o">)</span>
iPhone 5s <span class="o">(</span>0AC6BB28-E860-4320-A532-272BE43C067C<span class="o">)</span> <span class="o">(</span>Shutdown<span class="o">)</span>
iPhone 6 Plus <span class="o">(</span>E574C367-1BAA-4F9F-BB92-BD5F6BAB1226<span class="o">)</span> <span class="o">(</span>Shutdown<span class="o">)</span>
iPhone 6 <span class="o">(</span>7953EE9F-19E8-4D0C-9219-268FB0BA6626<span class="o">)</span> <span class="o">(</span>Shutdown<span class="o">)</span>
MyIPhone6 <span class="o">(</span>9151073B-3B7D-441A-8069-E797FA5059CE<span class="o">)</span> <span class="o">(</span>Shutdown<span class="o">)</span>
iPad 2 <span class="o">(</span>8D722A9F-2DA9-45A2-BAFB-44075AA519D6<span class="o">)</span> <span class="o">(</span>Booted<span class="o">)</span>
iPad Retina <span class="o">(</span>E8652514-3042-4958-9027-48A9A95392CE<span class="o">)</span> <span class="o">(</span>Shutdown<span class="o">)</span>
iPad Air <span class="o">(</span>6032BE94-1A62-4ADB-9013-50FAB2B088F6<span class="o">)</span> <span class="o">(</span>Shutdown<span class="o">)</span>
Resizable iPhone <span class="o">(</span>5E7A9E8C-D3A8-4E58-935F-8754B100E867<span class="o">)</span> <span class="o">(</span>Shutdown<span class="o">)</span>
Resizable iPad <span class="o">(</span>15FC1628-B369-44DE-8CE0-756439D9AEBC<span class="o">)</span> <span class="o">(</span>Shutdown<span class="o">)</span>
</code></pre></div></div>
<p>To get more details just run <code class="highlighter-rouge">xcrun simctl list -h</code> to get help on <code class="highlighter-rouge">list</code> command.</p>
<h1 id="xcodebuild"><code class="highlighter-rouge">xcodebuild</code></h1>
<p>Finally, to get the most detailed output, ask <code class="highlighter-rouge">xcodebuild</code> itself. It is not really documented and doesn’t look like a proper approach, but it works. The idea is to give <code class="highlighter-rouge">xcodebuild</code> invalid key-value pair in destination specifier and wait until it complains about it offering a list of valid options in return.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>xcodebuild <span class="nb">test</span> <span class="nt">-project</span> MyProject.xcodeproj <span class="nt">-scheme</span> MyScheme <span class="se">\</span>
<span class="nt">-destination</span> <span class="s2">"name=NoSuchName"</span> <span class="nt">-destination-timeout</span> 1
</code></pre></div></div>
<p>The output is</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>xcodebuild: error: Unable to find a destination matching the provided destination specifier:
<span class="o">{</span> name:NoSuchName <span class="o">}</span>
Unsupported device specifier option.
The device “My Mac” does not support the following options: name
Please supply only supported device specifier options.
Available destinations <span class="k">for </span>the <span class="s2">"MyScheme"</span> scheme:
<span class="o">{</span> platform:iOS Simulator, id:C4E52F2A-C1C0-408F-8177-5AAF7895D3B5, OS:7.0, name:iPad 2 <span class="o">}</span>
<span class="o">{</span> platform:iOS Simulator, id:43DD0C31-685F-4FC8-941F-0BB9B305CD2D, OS:7.1, name:iPad 2 <span class="o">}</span>
<span class="o">{</span> platform:iOS Simulator, id:8D722A9F-2DA9-45A2-BAFB-44075AA519D6, OS:8.1, name:iPad 2 <span class="o">}</span>
<span class="o">{</span> platform:iOS Simulator, id:091FC037-5C7F-45FC-9089-E424A9806D60, OS:7.0, name:iPad Air <span class="o">}</span>
<span class="o">{</span> platform:iOS Simulator, id:2FB923E2-F0F4-49DE-8FC3-81960386B8CE, OS:7.1, name:iPad Air <span class="o">}</span>
<span class="o">{</span> platform:iOS Simulator, id:6032BE94-1A62-4ADB-9013-50FAB2B088F6, OS:8.1, name:iPad Air <span class="o">}</span>
<span class="o">{</span> platform:iOS Simulator, id:D145A9C9-DFD0-4564-8A45-BF68A80426AC, OS:7.0, name:iPad Retina <span class="o">}</span>
<span class="o">{</span> platform:iOS Simulator, id:F1967F38-BE03-430F-BFB1-AFF4E2E4511C, OS:7.1, name:iPad Retina <span class="o">}</span>
<span class="o">{</span> platform:iOS Simulator, id:E8652514-3042-4958-9027-48A9A95392CE, OS:8.1, name:iPad Retina <span class="o">}</span>
<span class="o">{</span> platform:iOS Simulator, id:6CF0F409-F4F8-4BCD-AC4E-30E58947A3EB, OS:7.0, name:iPhone 4s <span class="o">}</span>
<span class="o">{</span> platform:iOS Simulator, id:57DBC56E-1E04-4384-9A07-7B47C119BEAB, OS:7.1, name:iPhone 4s <span class="o">}</span>
<span class="o">{</span> platform:iOS Simulator, id:DDF255C3-8BEF-4A97-8B3F-AD651BABF6CB, OS:8.1, name:iPhone 4s <span class="o">}</span>
<span class="o">{</span> platform:iOS Simulator, id:1C08AA1B-9C0C-499B-9570-972EF52941D9, OS:7.0, name:iPhone 5 <span class="o">}</span>
<span class="o">{</span> platform:iOS Simulator, id:BAF484D4-803C-478D-BAC1-916376C22C48, OS:7.1, name:iPhone 5 <span class="o">}</span>
<span class="o">{</span> platform:iOS Simulator, id:45E5CE55-093D-48C0-AA26-AA4E5C569FDB, OS:8.1, name:iPhone 5 <span class="o">}</span>
<span class="o">{</span> platform:iOS Simulator, id:3DD4CAA5-6CD7-4DFB-AF95-6494EAE6E90F, OS:7.0, name:iPhone 5s <span class="o">}</span>
<span class="o">{</span> platform:iOS Simulator, id:6856CCCF-842E-48E8-897B-87BB1865CD10, OS:7.1, name:iPhone 5s <span class="o">}</span>
<span class="o">{</span> platform:iOS Simulator, id:0AC6BB28-E860-4320-A532-272BE43C067C, OS:8.1, name:iPhone 5s <span class="o">}</span>
<span class="o">{</span> platform:iOS Simulator, id:E574C367-1BAA-4F9F-BB92-BD5F6BAB1226, OS:8.1, name:iPhone 6 Plus <span class="o">}</span>
<span class="o">{</span> platform:iOS Simulator, id:7953EE9F-19E8-4D0C-9219-268FB0BA6626, OS:8.1, name:iPhone 6 <span class="o">}</span>
<span class="o">{</span> platform:iOS Simulator, id:15FC1628-B369-44DE-8CE0-756439D9AEBC, OS:8.1, name:Resizable iPad <span class="o">}</span>
<span class="o">{</span> platform:iOS Simulator, id:5E7A9E8C-D3A8-4E58-935F-8754B100E867, OS:8.1, name:Resizable iPhone <span class="o">}</span>
<span class="o">{</span> platform:iOS Simulator, id:9151073B-3B7D-441A-8069-E797FA5059CE, OS:8.1, name:MyIPhone6 <span class="o">}</span>
<span class="o">{</span> platform:iOS, id:5dc0e5a8a9f7c0af1feea4bfa13860c9e61350d6, name:Maksym<span class="s1">'s iPhone }
</span></code></pre></div></div>
<p>Thanks <a href="https://disqus.com/by/disqus_ToXiGZRJLc/">Tor Arne</a> for pointing out <code class="highlighter-rouge">-destination-timeout</code> option in the comments. Without this option <code class="highlighter-rouge">xcodebuild</code> will take way too long to figure out that destination doesn’t exist.</p>
<h1 id="back-to-destination">Back to Destination</h1>
<p>Now that last output from <code class="highlighter-rouge">xcodebuild</code> is much better than anything else. It gives you all the key-value pairs as is, no additional guesswork involved. You get the “platform”, “OS” and “name” keys, and as a bonus you get an undocumented “id” key. Give it a try and see that it actually works.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>xcodebuild <span class="nb">test</span> <span class="nt">-project</span> MyProject.xcodeproj <span class="nt">-scheme</span> MyScheme <span class="nt">-destination</span> <span class="s2">"id=E574C367-1BAA-4F9F-BB92-BD5F6BAB1226"</span>
</code></pre></div></div>
<p>You can adopt this approach as part of CI workflow automation and grep all key-value pairs from <code class="highlighter-rouge">xcodebuild</code> output.</p>
https://mgrebenets.github.io/xcode/2015/02/18/whats-your-destination
https://mgrebenets.github.io/xcode/2015/02/18/whats-your-destination2015-02-18T00:00:00+00:00Install Java on Mac OS X
<p>A short how-to for installing and configuring Java Development Kit on Mac OS X.</p>
<!--more-->
<p>Java is core technology used by CI servers like <a href="/mobile%20ci/2015/02/01/jenkins-ci-server-on-osx">Jenkins</a>, <a href="/mobile%20ci/2015/02/01/bamboo-ci-server-on-osx">Bamboo</a> and others. It is also used by <a href="/atlassian/2014/05/29/atlassian-cli">Atlassian CLI Client</a>. In fact installing and configuring JDK is such a common task that it deserves its own post.</p>
<h1 id="java-version">Java Version</h1>
<p>Select JDK version which you need: <a href="http://support.apple.com/kb/DL1572">1.6</a>, <a href="http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html">1.7</a> or <a href="http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html">1.8</a>. Better install all of them, you never know what you might need one day.</p>
<p>I find that for most applications I’m using 1.7, rarely 1.6 for some outdated and unsupported application. These days more and more applications are updated to work with 1.8 without issues.</p>
<h1 id="java-home">Java Home</h1>
<p>Lots of applications, if not all, expect <code class="highlighter-rouge">JAVA_HOME</code> environment variable to be set. This tells them where the Java Virtual Machine (JVM) is located. I would recommend to update your <code class="highlighter-rouge">~/.bash_profile</code> and add something like this:</p>
<script src="https://gist.github.com/388ee1ee1d4345e7973a8d9251891829.js"> </script>
<p>This is an over-defensive version. It can safely run on OS other than Mac, but will not set <code class="highlighter-rouge">JAVA_HOME</code> in that case. It uses OS X specific <code class="highlighter-rouge">java_home</code> executable found in <code class="highlighter-rouge">/usr/libexec</code>. A very convenient utility to get JVM path for Java installation. Try <code class="highlighter-rouge">-V</code> to get a list of all JVMs installed.</p>
<script src="https://gist.github.com/3ade6a7f892a8eb0e720a1d3a737d798.js"> </script>
<p>If you are using shell other than bash, include the same in your shell’s version of <code class="highlighter-rouge">.bash_profile</code> or source it directly with <code class="highlighter-rouge">source .bash_profile</code>.</p>
https://mgrebenets.github.io/mobile%20ci/2015/02/15/install-java-on-mac-os-x
https://mgrebenets.github.io/mobile%20ci/2015/02/15/install-java-on-mac-os-x2015-02-15T00:00:00+00:00CocoaPods for Enterprise
<p>A practical example of using CocoaPods for enterprise projects.</p>
<!--more-->
<p>The “Enterprise” definition isn’t that clear and is not something standard. I will define it as follows.</p>
<ul>
<li>Enterprise is a company that builds more that one app on the same platform.</li>
<li>Has a large number of in-house libraries and modules.</li>
<li>Has a rather complex project configuration.</li>
</ul>
<p>The challenge is to adopt CocoaPods for such projects. This is actually more of a case-study than success story of adopting CocoaPods.</p>
<h1 id="xcconfig"><code class="highlighter-rouge">xcconfig</code></h1>
<p>One thing that “complex” project setup means is extensive use of <em>xcconfig</em> files. The problem is that CocoaPods generates it’s own <em>xcconfigs</em> and expects them to be applied to project target. If it detects existing <em>xcconfigs</em> it displays a warning in the end of generation step. Solution is to follow the advise and include Pods <em>xcconfig</em> in the very last <em>xcconfig</em> file which is applied to a target.</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Pods
</span><span class="cp">#include "Pods/Target Support Files/Pods/Pods.debug.xcconfig"
</span></code></pre></div></div>
<p>Make sure you do that for all targets and all configurations.</p>
<h1 id="inherited"><code class="highlighter-rouge">$(inherited)</code></h1>
<p>This is next issue which is <a href="https://github.com/CocoaPods/CocoaPods/issues/1761">known to CocoaPods users</a>.</p>
<p>The problem is that CocoaPods assumes it’s the only thing in the world using <em>xcconfigs</em>. So it never ever uses <code class="highlighter-rouge">$(inherited)</code> thus it doesn’t pick up any of the previous definitions when included into other <em>xcconfigs</em>.</p>
<p>One of the solutions is to patch Pods <em>xcconfig</em> files as part of <code class="highlighter-rouge">pod update</code> or <code class="highlighter-rouge">pod install</code> command. This is what post-install hooks are for. Consider this example</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Podfile for Project with xcconfig files</span>
<span class="n">source</span> <span class="s1">'https://github.com/CocoaPods/Specs.git'</span>
<span class="n">platform</span> <span class="ss">:ios</span><span class="p">,</span> <span class="s1">'7.0'</span>
<span class="n">link_with</span> <span class="s1">'TargetName'</span>
<span class="n">pod</span> <span class="s1">'Facebook-iOS-SDK'</span><span class="p">,</span> <span class="s1">'~> 3.20.0'</span>
<span class="n">post_install</span> <span class="k">do</span> <span class="o">|</span><span class="n">installer</span><span class="o">|</span>
<span class="nb">puts</span> <span class="s2">"Running post install hooks"</span>
<span class="nb">puts</span> <span class="s2">"Patching Pods xcconfig files"</span>
<span class="n">workDir</span> <span class="o">=</span> <span class="no">Dir</span><span class="p">.</span><span class="nf">pwd</span>
<span class="n">installer</span><span class="p">.</span><span class="nf">project</span><span class="p">.</span><span class="nf">targets</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">target</span><span class="o">|</span>
<span class="n">target</span><span class="p">.</span><span class="nf">build_configurations</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">config</span><span class="o">|</span>
<span class="n">xcconfigFilename</span> <span class="o">=</span> <span class="s2">"</span><span class="si">#{</span><span class="n">workDir</span><span class="si">}</span><span class="s2">/Pods/Target Support Files/Pods/Pods.</span><span class="si">#{</span><span class="n">config</span><span class="p">.</span><span class="nf">name</span><span class="p">.</span><span class="nf">downcase</span><span class="si">}</span><span class="s2">.xcconfig"</span>
<span class="n">xcconfig</span> <span class="o">=</span> <span class="no">File</span><span class="p">.</span><span class="nf">read</span><span class="p">(</span><span class="n">xcconfigFilename</span><span class="p">)</span>
<span class="c1"># insert $(inherited) for HEADER_SEARCH_PATHS and OTHER_LDFLAGS, make sure there's only one occurrence</span>
<span class="n">patchedXcconfig</span> <span class="o">=</span> <span class="n">xcconfig</span><span class="p">.</span><span class="nf">gsub</span><span class="p">(</span><span class="sr">/HEADER_SEARCH_PATHS = (?<first>[^\$])/</span><span class="p">,</span> <span class="s1">'HEADER_SEARCH_PATHS = $(inherited) \k<first>'</span><span class="p">).</span><span class="nf">gsub</span><span class="p">(</span><span class="sr">/OTHER_LDFLAGS = (?<first>[^\$])/</span><span class="p">,</span> <span class="s1">'OTHER_LDFLAGS = $(inherited) \k<first>'</span><span class="p">)</span>
<span class="no">File</span><span class="p">.</span><span class="nf">open</span><span class="p">(</span><span class="n">xcconfigFilename</span><span class="p">,</span> <span class="s2">"w"</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">file</span><span class="o">|</span> <span class="n">file</span> <span class="o"><<</span> <span class="n">patchedXcconfig</span> <span class="p">}</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>The <code class="highlighter-rouge">post_install</code> hook iterates through all targets, figures out the full path to generated Pods <em>xcconfig</em> and patches it by prepending <code class="highlighter-rouge">$(inherited)</code> for all occurrences of <code class="highlighter-rouge">HEADER_SEARCH_PATHS</code> and <code class="highlighter-rouge">OTHER_LDFLAGS</code>.</p>
<h1 id="git-submodules-and-proxy">Git Submodules and Proxy</h1>
<p>This is another issue that may happen in “enterprise” environment, especially if proxy is involved. CocoaPods is not able to checkout pods with submodules. An example of a pod with such problems is <a href="http://stackoverflow.com/questions/25953246/facebook-ios-sdk-installation-via-cocoapods">Facebook SDK</a>.</p>
<p>To avoid this problem in the first place I would recommend to use pods with static frameworks instead of those that clone whole source base. Well, not for all pods, but this is often useful for 3rd party SDKs that are not updated often. This is what pods like Flurry, Crashlytics and others do. For some reason Facebook doesn’t have official podspec for framework only, but nothing stops you from creating one yourself and host it in-house.</p>
<p>If you have to have those submodules, use the following git trick:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git config <span class="nt">--global</span> url.https://github.com/.insteadOf git://github.com/
</code></pre></div></div>
<p>See discussions on <a href="http://stackoverflow.com/questions/1722807/git-convert-git-urls-to-http-urls">StackOverflow</a> and <a href="https://coderwall.com/p/sitezg/force-git-to-clone-with-https-instead-of-git-urls">this post</a>. This command will modify your <code class="highlighter-rouge">.gitconfig</code> by adding this line</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span>url <span class="s2">"https://"</span><span class="o">]</span> insteadOf <span class="o">=</span> git://
</code></pre></div></div>
<p>This will solve submodule issue and is much easier than other workarounds like messing up with proxy stuff and tools like <code class="highlighter-rouge">socat</code>.</p>
<h1 id="git-submodules-for-internal-components">Git Submodules for Internal Components</h1>
<p>Another blocker for migration is all those internal libraries you already use as submodules in your project. You still want to be able to change their code right inside submodule directory and work with git in-place. With pure CocoaPods approach this is not possible since all your changes will be reset on next <code class="highlighter-rouge">pod update</code>.</p>
<p>However, there’s a beautiful work-around that allows you to benefit from both worlds (submodules and pods). Here’s <a href="http://albertodebortoli.github.io/blog/2014/03/11/cocoapods-working-with-internal-pods/">a great article</a> on the matter.</p>
<p>The idea is to use so called <em>Development Pods</em>. That means in your Podfile you specify the path to a submodule directory which has podspec file. This way CocoaPods ignores version information in podspec and uses latest files from submodule directory to generate pods. You get all the benefits of working with submodules code directly and then get all the flexibility of CocoaPods approach.</p>
<h1 id="build-problems">Build Problems</h1>
<p>Final paragraph is related to building projects with <code class="highlighter-rouge">xcodebuild</code> from command line. This is what happens on CI box after all.</p>
<p>If you try to run your old scripts which use custom configuration build directory you may run into link errors with Xcode not being able to find library file for Pods (<code class="highlighter-rouge">libPods.a</code>). Tools like <code class="highlighter-rouge">xctool</code> have this problem fixed, but I recall earlier version of <code class="highlighter-rouge">xctool</code> being prone to the same problem.</p>
<p>The solution is twofold.</p>
<ul>
<li>If specifying custom <code class="highlighter-rouge">CONFIGURATION_BUILD_DIR</code> then make it an <strong>absolute</strong> path</li>
</ul>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Bad.</span>
<span class="nv">CONFIGURATION_BUILD_DIR</span><span class="o">=</span>build
<span class="c"># Good.</span>
<span class="nv">CONFIGURATION_BUILD_DIR</span><span class="o">=</span><span class="k">$(</span><span class="nb">pwd</span><span class="k">)</span>/build
</code></pre></div></div>
<ul>
<li>If overriding <code class="highlighter-rouge">CONFIGURATION_BUILD_DIR</code> you <strong>must</strong> also specify <code class="highlighter-rouge">OBJROOT</code>, <code class="highlighter-rouge">SYMROOT</code> and <code class="highlighter-rouge">DSTROOT</code> and make sure all those are <strong>absolute</strong> paths as well</li>
</ul>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Example.</span>
<span class="nv">OBJROOT</span><span class="o">=</span><span class="k">$(</span><span class="nb">pwd</span><span class="k">)</span>/build <span class="nv">SYMROOT</span><span class="o">=</span><span class="k">$(</span><span class="nb">pwd</span><span class="k">)</span>/build <span class="nv">DSTROOT</span><span class="o">=</span><span class="k">$(</span><span class="nb">pwd</span><span class="k">)</span>/build
</code></pre></div></div>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Example of complete build command.</span>
xcodebuild clean build <span class="se">\</span>
<span class="nt">-workspace</span> Sandbox-ObjC.xcworkspace <span class="se">\</span>
<span class="nt">-scheme</span> Sandbox-ObjC <span class="se">\</span>
<span class="nt">-configuration</span> Release <span class="se">\</span>
<span class="nv">CONFIGURATION_BUILD_DIR</span><span class="o">=</span><span class="k">$(</span><span class="nb">pwd</span><span class="k">)</span>/build <span class="se">\</span>
<span class="nv">OBJROOT</span><span class="o">=</span><span class="k">$(</span><span class="nb">pwd</span><span class="k">)</span>/build <span class="se">\</span>
<span class="nv">SYMROOT</span><span class="o">=</span><span class="k">$(</span><span class="nb">pwd</span><span class="k">)</span>/build <span class="se">\</span>
<span class="nv">DSTROOT</span><span class="o">=</span><span class="k">$(</span><span class="nb">pwd</span><span class="k">)</span>/build
</code></pre></div></div>
https://mgrebenets.github.io/mobile%20ci/2015/02/15/cocoapods-for-enterprise
https://mgrebenets.github.io/mobile%20ci/2015/02/15/cocoapods-for-enterprise2015-02-15T00:00:00+00:00OCLint
<p><a href="http://oclint.org/">OCLint</a> is a fantastic static code analysis tool for improving quality and reducing defects by inspecting C, C++ and Objective-C code.</p>
<!--more-->
<p>I’m not going to copy-paste the rest of <a href="http://oclint.org">oclint.org</a> here, check it out to see what the tool can do. In this article you will learn how to set it up and use for Mobile CI.</p>
<p>OCLint is often referred as a <a href="http://en.wikipedia.org/wiki/Lint_%28software%29">lint</a> tool, but in the end of the day it’s a static analysis tool, meaning it analyses your code statically, that is without running it.</p>
<h1 id="install">Install</h1>
<p>For quite a while I though OCLint wasn’t available via <a href="http://brew.sh/">Homebrew</a> package manager. While it technically isn’t there yet, it’s supported by <a href="http://caskroom.io/">Homebrew Cask</a>. If you never used it yet, Homebrew Cask is an extension for Homebrew and lets you to manage OS X applications just like packages. Another benefit of this tool is that it includes other packages like OCLint which are not yet available in Homebrew.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew install caskroom/cask/brew-cask
</code></pre></div></div>
<p>Now install OCLint</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew cask install oclint
</code></pre></div></div>
<p>Check the installation, it’s now sitting in <code class="highlighter-rouge">usr/local/</code>.</p>
<h1 id="use">Use</h1>
<p>I will write about using OCLint with <code class="highlighter-rouge">xcodebuild</code>, basically rewording <a href="http://docs.oclint.org/en/stable/guide/xcodebuild.html">official documentation</a>. OCLint supports all other tools, check out <a href="http://docs.oclint.org/en/stable/#usage">documentation for details</a>.</p>
<p>Using OCLint with <code class="highlighter-rouge">xcodebuild</code> requires 3 steps.</p>
<ul>
<li>Build and capture output.</li>
<li>Generate compile commands database (JSON format) for OCLint using <code class="highlighter-rouge">xcodebuild</code> output.</li>
<li>Run OCLint using generated JSON database.</li>
</ul>
<p>The first step is straightforward, run <code class="highlighter-rouge">xcodebuild</code> the way you would run it normally, the only difference is that you want to capture build output. Use <code class="highlighter-rouge">tee</code> command to do that, for example</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>xcodebuild clean build <span class="nt">-project</span> MyProject <span class="nt">-scheme</span> MyScheme <span class="nt">-configuration</span> Debug | tee xcodebuild.log
</code></pre></div></div>
<p>It is recommended to use <em>Debug</em> configuration for static analysis.</p>
<p>Next, generate compilation commands database with <code class="highlighter-rouge">oclint-xcodebuild</code> command. This command expects a file named <code class="highlighter-rouge">xcodebuild.log</code> by default, but in the example I will pass it explicitly. The default output file name is <code class="highlighter-rouge">compile_commands.json</code> but I’ll be more verbose anyway and specify output file name.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>oclint-xcodebuild <span class="nt">-output</span> compile_commands.json xcodebuild.log
</code></pre></div></div>
<p>Optionally you can use <code class="highlighter-rouge">-e | -exclude</code> option and pass regular expression which will exclude the files you are not interested in, such as 3rd party source code.</p>
<p>Finally, use <code class="highlighter-rouge">oclint-json-compilation-database</code> to run oclint and generate report.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>oclint-json-compilation-database <span class="se">\</span>
<span class="nt">-exclude</span> <span class="k">${</span><span class="nv">LINT_EXCLUDES</span><span class="k">}</span> <span class="se">\</span>
<span class="nt">--</span> <span class="se">\</span>
<span class="nt">-report-type</span> <span class="k">${</span><span class="nv">LINT_REPORT_TYPE</span><span class="k">}</span> <span class="se">\</span>
<span class="k">${</span><span class="nv">LINT_RULES</span><span class="k">}</span> <span class="se">\</span>
<span class="k">${</span><span class="nv">LINT_DISABLE_RULES</span><span class="k">}</span> <span class="se">\</span>
<span class="k">${</span><span class="nv">LINT_THRESHOLD</span><span class="k">}</span> <span class="se">\</span>
<span class="nt">-o</span> <span class="k">${</span><span class="nv">LINT_REPORTS_DIR</span><span class="k">}</span>/<span class="k">${</span><span class="nv">LINT_REPORT_FILE</span><span class="k">}</span> <span class="se">\</span>
<span class="nt">-stats</span> <span class="se">\</span>
<span class="nt">-verbose</span> <span class="se">\</span>
<span class="nt">-list-enabled-rules</span>
</code></pre></div></div>
<p>Let’s analyze this call in details and expand actual values of all environment variables.</p>
<p>First you call <code class="highlighter-rouge">oclint-json-compilation-database</code> and specify it’s own arguments. In this case it is a list of excludes passed as <code class="highlighter-rouge">${LINT_EXCLUDES}</code>. OCLint understands grep-like regular expressions syntax, for example</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">LINT_EXCLUDES</span><span class="o">=</span><span class="s2">"Libraries|lib|Pods|Carthage"</span>
</code></pre></div></div>
<p>The <code class="highlighter-rouge">-i [INCLUDES]</code> option is used to do the opposite to exclude.</p>
<p>The double dash <code class="highlighter-rouge">--</code> indicates the start of arguments which will be passed to invocation of <code class="highlighter-rouge">oclint</code> command.</p>
<p><strong>Report type</strong> (<code class="highlighter-rouge">LINT_REPORT_TYPE</code>) specified via <code class="highlighter-rouge">-report-type</code> can be one of <code class="highlighter-rouge">text</code>, <code class="highlighter-rouge">html</code>, <code class="highlighter-rouge">xml</code>, <code class="highlighter-rouge">json</code> and <code class="highlighter-rouge">pmd</code>. For CI tasks you should definitely use <a href="http://en.wikipedia.org/wiki/PMD_%28software%29">PMD</a> report type. While running locally stick with <code class="highlighter-rouge">html</code>. So you should set <code class="highlighter-rouge">LINT_REPORT_TYPE</code> to one of these values. Read the <a href="http://docs.oclint.org/en/dev/customizing/reports.html">full documentation</a> for more.</p>
<p><strong>Lint rules</strong> (<code class="highlighter-rouge">LINT_RULES</code>) is an option with which you can override default threshold values for rules. For example, Objective-C is very verbose language, so let’s increase thresholds for the the max length of line of code, name of method and name of variable. This is how it will look in shell script</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Rules.</span>
<span class="nv">LINT_LONG_LINE</span><span class="o">=</span>300
<span class="nv">LINT_LONG_VARIABLE_NAME</span><span class="o">=</span>64
<span class="nv">LINT_LONG_METHOD</span><span class="o">=</span>150
<span class="nv">LINT_RULES</span><span class="o">=</span><span class="s2">"-rc LONG_LINE=</span><span class="k">${</span><span class="nv">LINT_LONG_LINE</span><span class="k">}</span><span class="s2"> </span><span class="se">\</span><span class="s2">
-rc LONG_VARIABLE_NAME=</span><span class="k">${</span><span class="nv">LINT_LONG_VARIABLE_NAME</span><span class="k">}</span><span class="s2"> </span><span class="se">\</span><span class="s2">
-rc LONG_METHOD=</span><span class="k">${</span><span class="nv">LINT_LONG_METHOD</span><span class="k">}</span><span class="s2">"</span>
</code></pre></div></div>
<p>You may want to disable some rules as well. This could be useful when working with some legacy code which smells a lot and there are no plans to fix it ever. In cases like this it’s easier to silent some warnings. For example, let’s disable warning about the use of <code class="highlighter-rouge">_ivarName</code> outside of accessors and initializers. Let’s also ignore useless parentheses and warnings about unused method parameters.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Disable rules.</span>
<span class="nv">LINT_DISABLE_RULES</span><span class="o">=</span><span class="s2">"-disable-rule=UnusedMethodParameter </span><span class="se">\</span><span class="s2">
-disable-rule=UselessParentheses </span><span class="se">\</span><span class="s2">
-disable-rule=IvarAssignmentOutsideAccessorsOrInit"</span>
</code></pre></div></div>
<p><a href="http://docs.oclint.org/en/stable/rules/index.html">Full list of rules</a> for further reference.</p>
<p><em>Note!</em>: The names of the rules on documentation page <em>do not</em> match the names you should be using to disable them.
For example <a href="http://docs.oclint.org/en/stable/rules/convention.html#coveredswitchstatementsdontneeddefault">CoveredSwitchStatementsDontNeedDefault</a>, should be specified as <code class="highlighter-rouge">SwitchStatementsDon\'TNeedDefaultWhenFullyCovered</code> when used in command line scripts (note escaping the <code class="highlighter-rouge">'</code> too). To get the correct names use <code class="highlighter-rouge">--list-enabled-rules</code> option, which is mentioned further in the post.</p>
<p><strong>Threshold</strong> allows you to control when analysis passes or fails. There are 3 priorities (Priority 1, 2 and 3) and each comes with default thresholds (0, 10 and 20). You can use <code class="highlighter-rouge">-max-priority-<N></code> command line option to customize priority <code class="highlighter-rouge">N</code> threshold. This is how you would change it to 0, 20 and 30 correspondingly</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Threshold.</span>
<span class="nv">LINT_PRIORITY_1_THRESHOLD</span><span class="o">=</span>0
<span class="nv">LINT_PRIORITY_2_THRESHOLD</span><span class="o">=</span>20
<span class="nv">LINT_PRIORITY_3_THRESHOLD</span><span class="o">=</span>30
LINT_THRESHOLD <span class="o">=</span> <span class="s2">"-max-priority-1=</span><span class="k">${</span><span class="nv">LINT_PRIORITY_1_THRESHOLD</span><span class="k">}</span><span class="s2"> </span><span class="se">\</span><span class="s2">
-max-priority-2=</span><span class="k">${</span><span class="nv">LINT_PRIORITY_2_THRESHOLD</span><span class="k">}</span><span class="s2"> </span><span class="se">\</span><span class="s2">
-max-priority-3=</span><span class="k">${</span><span class="nv">LINT_PRIORITY_3_THRESHOLD</span><span class="k">}</span><span class="s2">"</span>
</code></pre></div></div>
<p><strong>Output</strong> can be specified via <code class="highlighter-rouge">-o</code> option. If you are using PMD report type, write out to XML file, for HTML report, write to HTML format. Better create a separate directory for reports, for example</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Reports.</span>
<span class="nv">LINT_REPORTS_DIR</span><span class="o">=</span>oclint-reports
<span class="c"># Use .html for HTML report type.</span>
<span class="nv">LINT_REPORT_FILE</span><span class="o">=</span>oclint.xml
mkdir <span class="nt">-p</span> <span class="k">${</span><span class="nv">LINT_REPORTS_DIR</span><span class="k">}</span>
</code></pre></div></div>
<p>Finally add some verbosity with <code class="highlighter-rouge">-stats</code> to output statistics, <code class="highlighter-rouge">-list-enabled-rules</code> to eyeball the rules being used and <code class="highlighter-rouge">-verbose</code> for what it stands.</p>
<h2 id="config-file">Config File</h2>
<p>Instead of having lengthy shell scripts, you can opt out to using <code class="highlighter-rouge">.oclint</code> config file. Put it in you project’s root folder and list all the thresholds and other rules configs it YAML format, for example:</p>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># OCLint config example</span>
<span class="na">rules</span><span class="pi">:</span>
<span class="na">disable-rules</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s">GotoStatement</span>
<span class="pi">-</span> <span class="s">UnusedMethodParameter</span>
<span class="pi">-</span> <span class="s">EmptyIfStatement</span>
<span class="pi">-</span> <span class="s">SwitchStatementsDon'TNeedDefaultWhenFullyCovered</span>
<span class="na">rule-configurations</span><span class="pi">:</span>
<span class="pi">-</span> <span class="na">key</span><span class="pi">:</span> <span class="s">LONG_LINE</span>
<span class="na">value</span><span class="pi">:</span> <span class="s">300</span>
<span class="pi">-</span> <span class="na">key</span><span class="pi">:</span> <span class="s">SHORT_VARIABLE_NAME</span>
<span class="na">value</span><span class="pi">:</span> <span class="s">1</span>
<span class="pi">-</span> <span class="na">key</span><span class="pi">:</span> <span class="s">LONG_VARIABLE_NAME</span>
<span class="na">value</span><span class="pi">:</span> <span class="s">64</span>
<span class="na">max-priority-1</span><span class="pi">:</span> <span class="s">0</span>
<span class="na">max-priority-2</span><span class="pi">:</span> <span class="s">20</span>
<span class="na">max-priority-3</span><span class="pi">:</span> <span class="s">30</span>
<span class="na">enable-clang-static-analyzer</span><span class="pi">:</span> <span class="no">false</span>
</code></pre></div></div>
<p>Read <a href="http://docs.oclint.org/en/stable/howto/rcfile.html">official documentation</a> for more details.</p>
<h1 id="other-notes">Other Notes</h1>
<h2 id="integrate-with-xcode">Integrate with Xcode</h2>
<p>There are ways to integrate OCLint with Xcode. This is actually worth a separate post on its own. The goal is to allow non-script-and-command-line-savvy teammates to run OCLint analyzer in Xcode. <em>Don’t set your hopes too hight though, they just won’t do that anyway :)</em> However, <a href="https://gavrix.wordpress.com/2013/02/28/integrating-oclint-in-xcode/">check this post</a> for some examples.</p>
<h2 id="suppress-warnings">Suppress Warnings</h2>
<p>Sometimes you just <em>have</em> to violate the rule. Let’s say it’s a legacy code base and there’s just this one violation and nothing you can do about it. Instead of disabling a useful rule completely, consider <a href="http://docs.oclint.org/en/stable/howto/suppress.html">suppressing the warning</a>.</p>
<p><em>Note:</em> 0.10.1 <em>doesn’t</em> understand <code class="highlighter-rouge">//!OCLint</code> suppress comments. It is case-sensitive and must be <code class="highlighter-rouge">//!OCLINT</code>. This should be <a href="https://github.com/oclint/oclint/pull/281">fixed</a> in next releases though.</p>
<h2 id="save-time">Save Time</h2>
<p>Running a project build to generate Xcode build log, then running OCLint is very time consuming task. Consider generating Xcode build log once and then reusing it for OCLint. You will have to generate fresh build log when the project structure changes.</p>
<p>If you run unit tests as part of CI pipeline, then capture build log when building unit tests target.</p>
<h1 id="summary">Summary</h1>
<p>Give it a go. You now have a very powerful tool in your tool belt. Figure out your custom project thresholds, integrate it as part of your project <a href="/mobile%20ci/2015/02/08/mobile-ci-makefiles">makefile</a> or <a href="https://github.com/fastlane/fastlane/blob/master/docs/Actions.md#oclint">Fastfile</a>, run it as CI job and output reports using one of the plugins available.</p>
<p>You may actually unearth a pair of real bugs in your code.</p>
https://mgrebenets.github.io/mobile%20ci/2015/02/08/oclint
https://mgrebenets.github.io/mobile%20ci/2015/02/08/oclint2015-02-08T00:00:00+00:00Makefiles for Mobile CI
<p>A look at Xcode projects from another angle, trying to build things on another level.</p>
<!--more-->
<p>When I started with iOS development, not much really existed in my noob view outside the Xcode IDE. For quite a while Xcode used to be my whole universe. I could go through the whole app life cycle from first line of code all the way to uploading it to App Store, all of that in Xcode (except minor detour to iTunes Connect web interface). At some point my universe had to expand and I learned about basics of internal Xcode project structure, Xcode workspaces, <code class="highlighter-rouge">xcconfig</code> files, custom build phases and so on. Eventually I got out of the metaphorical Solar system (Xcode IDE) and dived into the black void of terminal window and command line interface.</p>
<h1 id="xcode-limits">Xcode Limits</h1>
<p>In this article I will try to show you other ways to build Xcode projects. There’s nothing bad with Xcode projects as such. As I mentioned before, you can have quite an elaborate configuration with multiple targets, schemes, cross-target dependencies. You can include and build sub-projects, define custom build phases such as running shell scripts. Then finally you can use <em>xcconfig</em> files to take out project settings out of ASCII plist format and control them in plain text.</p>
<p>With all that goodness you will eventually get to the limits of what Xcode project can do. Here are some examples.</p>
<p><a href="http://cocoapods.org/">CocoaPods</a>. You have to get out of your “comfort zone” and run <code class="highlighter-rouge">pod install</code> and <code class="highlighter-rouge">pod setup</code> from command line to get Xcode project all set up. Though you could create a custom target with a shell script pre-build phase to do just that.</p>
<p>If you have a lot of post-build phases with shell scripts, you probably want some of those to be executed only when you really need it. Have you ever seen hundreds of dSYMs uploaded to <a href="https://try.crashlytics.com/">Crashlytics</a> because that small shell script phase was executed each time a developer would hit <code class="highlighter-rouge">Cmd + B</code>? That’s just one example.</p>
<p>No matter how sophisticated is your use of <em>xcconfigs</em>, you’ll eventually want to build an app overriding some of build settings from command line. That’s often the case in CI setup, where you want to build with another provisioning profile, sign with another signing identity, etc. Going into the code and changing <em>xcconfig</em> manually doesn’t work for CI and it’s too manual. Having dozens of targets with <em>xcconfigs</em> that differ in one or two lines is another not so pleasant experience.</p>
<p>Back to shell scripts as custom build phases. Given that you have half a dozen of those, you will want to reuse them for other projects as well. Does copy-paste feel right? It should not and that’s yet another reason to see how building iOS projects can be taken to the next level.</p>
<h1 id="make-utility">Make Utility</h1>
<p>The answer, well, one of the answers, is <a href="http://en.wikipedia.org/wiki/Make_%28software%29">make</a> utility and <a href="http://en.wikipedia.org/wiki/Makefile">makefiles</a>.</p>
<p><code class="highlighter-rouge">make</code> is a build automation tool. It automatically builds programs and libraries from source code by reading files called <strong>makefiles</strong> which specify how to derive the target program. Phew, that’s enough of Wiki copy-paste. <code class="highlighter-rouge">make</code> was initially released in 1977! That’s years before I myself was “released” so to say. By ways of evolution and inheritance <code class="highlighter-rouge">make</code> is a part Mac OS X by default, so why not trying to use it for something good?</p>
<h1 id="makefile">Makefile</h1>
<p><code class="highlighter-rouge">make</code> is using makefiles, which contain so called <em>recipes</em> often referred to as <em>targets</em>, a set of instructions for building the app, library, or whatever you are up to. Does <code class="highlighter-rouge">make clean</code> sound familiar now?</p>
<p>Makefile syntax is similar to shell syntax, but not exactly the same. The fact that you can use shell commands in makefile makes it a bit more confusing.</p>
<h2 id="basic-recipes">Basic Recipes</h2>
<p>Let’s start with a set of simple targets. To define a target you normally tell <em>what</em> you want to build and after a colon (<code class="highlighter-rouge">:</code>) you tell <em>how</em>. Let’s create a file named <code class="highlighter-rouge">Makefile</code>.</p>
<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">PROJECT</span> <span class="o">=</span> MyProject.xcodeproj
<span class="nv">SCHEME</span> <span class="o">=</span> MyScheme
<span class="nv">BUILD_DIR</span> <span class="o">=</span> build
<span class="c"># phony targets
</span><span class="nl">.PHONY</span><span class="o">:</span> <span class="nf">all clean help</span>
<span class="c"># default target
</span><span class="nl">all</span><span class="o">:</span> <span class="nf">help</span>
<span class="c"># clean target
</span><span class="nl">clean</span><span class="o">:</span>
<span class="err">@echo</span> <span class="err">Cleaning</span> <span class="err">up...</span>
<span class="err">xcodebuild</span> <span class="err">clean</span> <span class="err">-project</span> <span class="err">$(PROJECT)</span> <span class="err">\</span>
<span class="err">-scheme</span> <span class="err">$(MYSCHEME)</span>
<span class="err">@rm</span> <span class="err">-rf</span> <span class="err">$(BUILD_DIR)</span>
<span class="nl">help</span><span class="o">:</span>
<span class="nl">@echo Targets</span><span class="o">:</span>
<span class="err">@echo</span> <span class="s2">"clean - clean the project"</span>
<span class="err">@echo</span> <span class="s2">"help - display this message"</span>
</code></pre></div></div>
<p>Let’s see what’s going on here. <code class="highlighter-rouge">all</code> is the default target which is executed when you just run <code class="highlighter-rouge">make</code>. Here you can see how target <em>dependencies</em> can be used. <code class="highlighter-rouge">all</code> is dependent on <code class="highlighter-rouge">help</code> and <code class="highlighter-rouge">help</code> is just printing information about all available targets. Other than causing <code class="highlighter-rouge">help</code> to run, <code class="highlighter-rouge">all</code> doesn’t do anything else.</p>
<p>Another trick - phony targets, those are all listed as dependencies for a special <code class="highlighter-rouge">.PHONY</code> target. Using phony targets is the way you can tell <code class="highlighter-rouge">make</code> utility to build those targets each time. By default <code class="highlighter-rouge">make</code> is smart and checks for any changes since last build and does nothing if it detects no changes. In this case I don’t want that behavior, that’s why I use phony targets.</p>
<p>The <code class="highlighter-rouge">clean</code> target cleans Xcode project using <code class="highlighter-rouge">xcodebuild</code> under the hood. It also removes the <code class="highlighter-rouge">build</code> folder. The actual recipe for <code class="highlighter-rouge">clean</code> is a number of shell commands. By default <code class="highlighter-rouge">make</code> will print out all the executed commands to stdout. The use of <code class="highlighter-rouge">@</code> as in <code class="highlighter-rouge">@echo</code> will remove the “echo Cleaning up…” line form stdout and you will see only the “Cleaning up…” message. Another nice thing is that just like with shell you can use <code class="highlighter-rouge">\</code> to split single command into multiple lines.</p>
<p>This example also features the use of variables in a makefile. You might have noticed that it’s less strict than the shell syntax, e.g. it allows use of spaces around assignment operation. Using <code class="highlighter-rouge">$()</code> you can reference variables, shell-like <code class="highlighter-rouge">${}</code> is also a valid syntax. You could as well just use <code class="highlighter-rouge">$</code> without <code class="highlighter-rouge">()</code> or <code class="highlighter-rouge">{}</code>, but I’d recommend sticking with <code class="highlighter-rouge">$()</code> all the time. Having <code class="highlighter-rouge">$PROJECT</code> resolved as <code class="highlighter-rouge">$P</code> <code class="highlighter-rouge">ROJECT</code> is not the easiest thing to figure out. Finally <code class="highlighter-rouge">make</code> lets you override variables from command line.</p>
<p>Try running <code class="highlighter-rouge">make clean</code> to see how it works.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>make clean <span class="nv">SCHEME</span><span class="o">=</span>MyOtherScheme
</code></pre></div></div>
<p><code class="highlighter-rouge">make</code> will look for a file named <code class="highlighter-rouge">Makefile</code> by default, though you can always feed it any makefile you want.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>make <span class="nt">-f</span> MyOtherMakefile clean
</code></pre></div></div>
<h2 id="functions">Functions</h2>
<p>At this moment it should be obvious that makefiles are using <a href="http://en.wikipedia.org/wiki/Domain-specific_language">Domain Specific Language</a> or DSL. It so happens that this language has functions among other things.</p>
<p>Let’s look at two targets, <code class="highlighter-rouge">build</code> and <code class="highlighter-rouge">test</code>.</p>
<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">PROJECT</span> <span class="o">=</span> MyProject.xcodeproj
<span class="nv">SCHEME</span> <span class="o">=</span> MySceme
<span class="nl">build</span><span class="o">:</span>
<span class="err">xcodebuild</span> <span class="err">build</span> <span class="err">\</span>
<span class="err">-project</span> <span class="err">$(PROJECT)</span> <span class="err">\</span>
<span class="err">-scheme</span> <span class="err">$(SCHEME)</span>
<span class="nl">test</span><span class="o">:</span>
<span class="err">xcodebuild</span> <span class="err">test</span> <span class="err">\</span>
<span class="err">-project</span> <span class="err">$(PROJECT)</span> <span class="err">\</span>
<span class="err">-scheme</span> <span class="err">$(SCHEME)</span>
</code></pre></div></div>
<p>Looks a bit <a href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY</a> doesn’t it? Here’s how you can define a function called <code class="highlighter-rouge">xcodebuild</code> to be able to reuse some code.</p>
<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">PROJECT</span> <span class="o">=</span> MyProject.xcodeproj
<span class="nv">SCHEME</span> <span class="o">=</span> MySceme
<span class="c"># Build with xcodebuild
# usage: $(call xcodebuild,ACTION,PROJECT,SCHEME)
</span><span class="nv">xcodebuild</span> <span class="o">=</span> <span class="se">\</span>
xcodebuild <span class="err">$</span><span class="o">(</span>1<span class="o">)</span> <span class="se">\</span>
<span class="nt">-project</span> <span class="err">$</span><span class="o">(</span>2<span class="o">)</span> <span class="se">\</span>
<span class="nt">-scheme</span> <span class="err">$</span><span class="o">(</span>3<span class="o">)</span>
<span class="nl">build</span><span class="o">:</span>
<span class="err">$(call</span> <span class="err">xcodebuild,build,$(PROJECT),$(SCHEME))</span>
<span class="nl">test</span><span class="o">:</span>
<span class="err">@$(call</span> <span class="err">xcodebuild,test,$(PROJECT),$(SCHEME))</span>
</code></pre></div></div>
<p>Well, to be honest, this doesn’t look like the best example in the world, but still it demonstrates the use of functions. You can pack some reusable code into the function, then call functions from functions and eventually gain benefit from this approach. Interestingly enough, when it comes to calling functions makefiles do not tolerate spaces, as you can see I put no spaces after <code class="highlighter-rouge">,</code> when passing arguments. Arguments are positional and not named, you have to refer to them with <code class="highlighter-rouge">$(1)</code>, <code class="highlighter-rouge">$(2)</code> and so on. You can still use <code class="highlighter-rouge">@</code> to filter out extra output from stdout.</p>
<p>To call a function you use <code class="highlighter-rouge">$(call function-name,arg1,arg2,...)</code> syntax.</p>
<h2 id="shell-commands">Shell Commands</h2>
<p>When writing code outside of target recipe, you can call shell commands using <code class="highlighter-rouge">shell</code> keyword.</p>
<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">PROJECT</span> <span class="o">=</span> <span class="nf">$(</span><span class="nb">shell</span> <span class="nb">ls</span> <span class="nt">-1</span> <span class="nb">.</span> | <span class="nb">grep</span> .xcodeproj<span class="nv">)</span>
</code></pre></div></div>
<p>This example will find first file with <code class="highlighter-rouge">.xcodeproj</code> extension and save it to <code class="highlighter-rouge">PROJECT</code> variable. If using CocoaPods you can modify shell script to filter out <code class="highlighter-rouge">Pods.xcodeproj</code>.</p>
<p>Here’s more advanced example, that demonstrates nesting of shell commands.</p>
<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">CLANG_ANALYZER</span> <span class="o">=</span> <span class="nf">$(</span><span class="nb">shell</span> dirname <span class="err">$$</span><span class="o">(</span>which scan-build<span class="nv">))</span>/bin/clang-check
</code></pre></div></div>
<p>Note how I have to escape <code class="highlighter-rouge">$</code> with another <code class="highlighter-rouge">$</code> when capturing results of <code class="highlighter-rouge">which</code> command, that’s because single <code class="highlighter-rouge">$</code> is part of makefile syntax and will try to resolve <code class="highlighter-rouge">$(which scan-biuild)</code> as makefile variable but not as shell expression.</p>
<p>An example for shell for-loop.</p>
<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">SCOPE</span> <span class="o">=</span> <span class="nt">-iregex</span> <span class="s2">".*</span><span class="se">\.</span><span class="s2">(h|m|mm)</span><span class="nv">$$</span><span class="s2">"</span>
<span class="nv">MAKEFILE_VAR</span> <span class="o">=</span> Value
<span class="nl">for-loop</span><span class="o">:</span>
<span class="err">@(for</span> <span class="err">file</span> <span class="err">in</span> <span class="err">$(shell</span> <span class="err">find</span> <span class="err">-E</span> <span class="err">.</span> <span class="err">$(SCOPE));</span> <span class="err">do</span> <span class="err">\</span>
<span class="err">echo</span> <span class="s2">"Do something for $${file} using $(MAKEFILE_VAR)"</span><span class="err">;</span> <span class="err">\</span>
<span class="err">done)</span>
</code></pre></div></div>
<p>This code will loop through all files with <code class="highlighter-rouge">.h</code>, <code class="highlighter-rouge">.m</code> or <code class="highlighter-rouge">.mm</code> extensions. Again notice the use of double <code class="highlighter-rouge">$$</code> for referring to shell variables vs single <code class="highlighter-rouge">$</code> for makefile variables. The <code class="highlighter-rouge">@(...)</code> is used to wrap the whole expression and prevent it from showing up in stdout. It also demoes the use of multiline scripts. Here’s an example of a one-liner for-loop.</p>
<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">BUILD_DIR</span> <span class="o">=</span> build
<span class="nl">one-liner-for-loop</span><span class="o">:</span>
<span class="err">for</span> <span class="err">f</span> <span class="err">in</span> <span class="err">$(shell</span> <span class="err">find</span> <span class="err">.</span> <span class="err">-name</span> <span class="err">$(BUILD_DIR));</span> <span class="err">do</span> <span class="err">echo</span> <span class="err">Removing</span> <span class="err">$${f}</span> <span class="err">...;</span> <span class="err">rm</span> <span class="err">-rf</span> <span class="err">$${f};</span> <span class="err">done</span>
</code></pre></div></div>
<p>In general, any shell script will work, just don’t forget to escape <code class="highlighter-rouge">$</code>s properly and keep an eye for makefile/shell syntax differences.</p>
<h2 id="flow-control">Flow Control</h2>
<p>You have already seen that it’s possible to use all shell flow control operators in the recipe. If you want that level of control outside the recipe, you can use makefile’s own flow control operators.</p>
<p>For example, a basic if-block.</p>
<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">ANALYZER</span> <span class="o">=</span> xcode
<span class="nv">CLANG_ANALYZER</span> <span class="o">=</span> Xcode
<span class="err">ifeq</span> <span class="err">($(CLANG_ANALYZER),</span> <span class="err">scan-build)</span>
<span class="nv">CLANG_ANALYZER</span> <span class="o">=</span> <span class="nf">$(</span><span class="nb">shell</span> dirname <span class="err">$$</span><span class="o">(</span>which scan-build<span class="nv">))</span>/bin/clang-check
<span class="err">endif</span>
</code></pre></div></div>
<p>Now by calling <code class="highlighter-rouge">make</code> with different parameter you can influence the value of <code class="highlighter-rouge">CLANG_ANALYZER</code> variable.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>make analyze <span class="nv">ANALYZER</span><span class="o">=</span>scan-build
<span class="c"># Value of CLANG_ANALYZER will be /usr/local/bin/clang-check/</span>
</code></pre></div></div>
<p>These flow control operators can be used outside as well as inside recipes. Have a look at <code class="highlighter-rouge">foreach</code> example.</p>
<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">PLATFORMS</span> <span class="o">=</span> linux mac windows
<span class="nv">RUBY_FILES</span> <span class="o">=</span> <span class="nf">$(</span><span class="nb">shell</span> find <span class="nb">.</span> <span class="nt">-type</span> f <span class="nt">-name</span> <span class="s1">'*.rb'</span><span class="nv">)</span>
<span class="nv">RUBY_LOG</span> <span class="o">=</span> check-ruby-syntax.log
<span class="nl">check-ruby-syntax</span><span class="o">:</span>
<span class="err">@$(foreach</span> <span class="err">platform,</span> <span class="err">$(PLATFORMS),</span> <span class="err">\</span>
<span class="nl">echo Platform</span><span class="o">:</span> <span class="nf">$(platform); </span>\
<span class="nf"> $(foreach file</span><span class="p">,</span><span class="nf"> $(RUBY_FILES)</span><span class="p">,</span><span class="nf"> </span>\
<span class="nf"> export PLATFORM=$(platform); </span>\
<span class="nf"> ruby -wc $(file) 1>>$(RUBY_LOG) 2>>$(RUBY_LOG); </span>\
<span class="nf"> ) </span>\
<span class="nf"> )</span>
</code></pre></div></div>
<p>This example is from a bit different world of Ruby. It iterates through a list of platforms (linux, mac and windows), then for each platform it iterates through all <code class="highlighter-rouge">.rb</code> files it can find. For each file it sets the shell environment variable <code class="highlighter-rouge">PLATFORM</code> and runs Ruby syntax check command (<code class="highlighter-rouge">ruby -wc</code>) writing errors and warnings to the log file.</p>
<p>One more makefile command worth mentioning is <code class="highlighter-rouge">eval</code>. It can be used inside the recipe to assign new value to makefile variable, for example</p>
<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">MAKEFILE_VAR</span> <span class="o">=</span> 0
<span class="nl">eval</span><span class="o">:</span>
<span class="nl">$(eval MAKEFILE_VAR </span><span class="o">:</span><span class="nf">= 1)</span>
</code></pre></div></div>
<p>Of course you can use more complex expressions, e.g. assign a result of some function to <code class="highlighter-rouge">MAKEFILE_VAR</code>.</p>
<h2 id="includes-and-reuse">Includes and Reuse</h2>
<p>If rich DSL syntax wasn’t enough, you can get another level of reuse from makefiles. You can include them to each other just like good old C header files.</p>
<p>Consider this example</p>
<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Actual directory of this Makefile, not where it is called form
</span><span class="nv">SELF_DIR</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span>dir <span class="err">$</span><span class="o">(</span>lastword <span class="nv">$(MAKEFILE_LIST)</span><span class="o">))</span>
<span class="c"># Include common Batman Makefile
</span><span class="err">include</span> <span class="err">$(SELF_DIR)/CommonMakefile</span>
</code></pre></div></div>
<p>This is how you can include <code class="highlighter-rouge">CommonMakefile</code> into another makefile. The magical <code class="highlighter-rouge">SELF_DIR</code> construction is the way to get absolute path of the makefile itself. This is useful when you call <code class="highlighter-rouge">make</code> and give it a path to makefile which is located in some other folder and then <code class="highlighter-rouge">CommonMakefile</code> is located in the same directory with original makefile. Kind of <code class="highlighter-rouge">require_relative</code> if you ever dealt with Ruby.</p>
<p>Including makefiles suggests the ability to reuse recipes, and that’s possible indeed. To make recipe reusable use double colon <code class="highlighter-rouge">::</code> when defining it.</p>
<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Nn CommonMakefile.
</span><span class="nl">clean</span><span class="o">::</span>
<span class="err">echo</span> <span class="s2">"Common clean..."</span>
<span class="err">@rm</span> <span class="err">-rf</span> <span class="err">CommonBuildDir</span>
<span class="c"># In SpecificMakefile.
</span><span class="nl">clean</span><span class="o">::</span>
<span class="err">echo</span> <span class="s2">"Specific clean..."</span>
<span class="err">@rm</span> <span class="err">-rf</span> <span class="err">SpecificBuildDir</span>
</code></pre></div></div>
<p>As you’d expect, the <code class="highlighter-rouge">clean</code> recipe in <code class="highlighter-rouge">SpecificMakefile</code> will first run <code class="highlighter-rouge">clean</code> recipe from <code class="highlighter-rouge">CommonMakefile</code>.</p>
<h1 id="configuration-as-a-code">Configuration as a Code</h1>
<p>Imagine that you’ve created a bunch of recipes in your makefile, for example</p>
<ul>
<li>clean</li>
<li>build</li>
<li>test</li>
<li>analyze (e.g. <a href="/mobile%20ci/2015/02/08/clang-static-analyzer">Clang Static Analyzer</a>)</li>
<li>lint (e.g. <a href="/mobile%20ci/2015/02/08/oclint">OCLint</a>)</li>
<li>deploy (e.g. to <a href="http://hockeyapp.net/">HockeyApp</a>)</li>
</ul>
<p>You have practically created all the build tasks for your CI job. Depending on the size of your project, you can execute those separately, e.g. <code class="highlighter-rouge">make test</code> or combine into one recipe and run as one <code class="highlighter-rouge">make ci</code> command.</p>
<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">ci</span><span class="o">:</span> <span class="nf">clean build test analyze lint deploy</span>
<span class="err">echo</span> <span class="s2">"Running CI target ..."</span>
</code></pre></div></div>
<p>All what is left to do is to collect reports. The beauty of this approach is that you don’t have to open Jenkins/Bamboo/Team City/Whatever UI to modify the build job each time. Your whole build configuration is a code now and you make changes inside the project repository, that means all changes are tracked in version control system and can be reviewed.</p>
<p>Even more, if multiple projects share the same structure, you can move build configuration into a common makefile and make it available on CI box as part of Ruby gem, for example. There are certain tradeoffs if you do it this way. The latest version of common makefile has to be backwards compatible with all the projects. I have successfully applied this approach building 21 libraries with one common makefile, so it’s something that can be done.</p>
<h1 id="summary">Summary</h1>
<p>I’ll admit that this not the best use of makefiles. If you ever had to build complex C or C++ projects, you should be familiar with much more complex recipes and use of extensive pattern matching and other techniques. However, makefile is a DSL after all and the beauty of any DSL is that you can apply it to your needs in a way which is convenient for you.</p>
<p>Makefiles sometimes feel like something from last century, and they technically are! Nothing stops you from exploring other alternatives if you want to get away from this non-obvious makefile-shell syntax mixup and functions that look more like macros.</p>
<p>Have a look at <a href="http://en.wikipedia.org/wiki/Rake_%28software%29">Rake</a> then. Basically it’s <code class="highlighter-rouge">make</code> for Ruby, but you can use it for any kind of projects. You get all the benefits of using Ruby as your DSL, which is way more flexible than makefiles. A minor tradeoff is that you need to have Ruby and Bundler installed, but Ruby is part of Mac OS X release, so that’s not a big deal.</p>
<p>Yet another option is <a href="http://en.wikipedia.org/wiki/Gradle">Gradle</a>. The DSL for Gradle is <a href="http://en.wikipedia.org/wiki/Groovy_(programming_language)">Groovy</a> a powerful and flexible language as well. With Gradle you’ll need some basic Java setup.</p>
<p>If you want to take your iOS or Mac OS X build automation to the next level, just pick one of the many DSLs available and move all your configuration to the code. It does require certain efforts in the beginning, but pays off in the end.</p>
https://mgrebenets.github.io/mobile%20ci/2015/02/08/mobile-ci-makefiles
https://mgrebenets.github.io/mobile%20ci/2015/02/08/mobile-ci---makefiles2015-02-08T00:00:00+00:00Code Coverage for iOS (gcov)
<p>Create code coverage reports for iOS unit tests using <code class="highlighter-rouge">gcov</code> tool.</p>
<p><em>Note that this approach may not work with Xcode 7 and future Xcode updates. For information on how to generate test coverage reports using new Profdata format, <a href="/mobile%20ci/2015/09/21/code-coverage-for-ios-xcode-7">check this article</a>).</em></p>
<!--more-->
<p>Calculating <a href="http://en.wikipedia.org/wiki/Code_coverage">Code Coverage</a> is a way to get more out of your unit tests, given that you have those and run on regular basis. With minor changes you can get coverage reports that include stats for</p>
<ul>
<li>Packages</li>
<li>Files</li>
<li>Classes</li>
<li>Lines</li>
<li>Conditionals</li>
</ul>
<h1 id="enable">Enable</h1>
<p>Good staring point is <a href="https://developer.apple.com/library/ios/qa/qa1514/_index.html">documentation from Apple</a>. Important takeaway from that article is that you need 2 sets of files to generate coverage reports. The <code class="highlighter-rouge">.gcno</code> files contain information to reconstruct the basic block graphs and assign source line numbers to blocks. The <code class="highlighter-rouge">.gcda</code> files are generated when the tests are executed and contain transition counts and some summary information. Check <a href="http://gcc.gnu.org/onlinedocs/gcc-4.24/gcc/Gcov-Data-Files.html">this link</a> for more details.</p>
<p>The Apple’s article recommends to create a separate configuration and set the following LLVM 5.0 Code Generation options to <code class="highlighter-rouge">YES</code>.</p>
<ul>
<li>Generate Debug Symbols (<code class="highlighter-rouge">GCC_GENERATE_DEBUGGING_SYMBOLS</code>)</li>
<li>Generate Test Coverage Files (<code class="highlighter-rouge">GCC_GENERATE_TEST_COVERAGE_FILES</code>)
<ul>
<li>This is required to generate <code class="highlighter-rouge">.gcno</code> files.</li>
</ul>
</li>
<li>Instrument Program Flow (<code class="highlighter-rouge">GCC_INSTRUMENT_PROGRAM_FLOW_ARCS</code>)
<ul>
<li>This is required to get <code class="highlighter-rouge">.gcda</code> files.</li>
</ul>
</li>
</ul>
<p>I have also specified the GCC settings names so you’d know how to enable these flags when building from command line or when using <em>xcconfigs</em>. The benefit of building from command line is that you don’t have to create new configuration in the project, instead you can customize existing <em>Debug</em> configuration.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Make sure tests are run against latest OS at all times.</span>
<span class="nb">export </span><span class="nv">OS</span><span class="o">=</span><span class="k">$(</span>xcrun <span class="nt">--sdk</span> iphonesimulator <span class="nt">--show-sdk-platform-version</span><span class="k">)</span>
xcodebuild <span class="nb">test</span> <span class="nt">-project</span> MyProject.xcodeproj <span class="nt">-scheme</span> MyScheme <span class="se">\</span>
<span class="nt">-configuration</span> Debug <span class="se">\</span>
<span class="nt">-sdk</span> iphonesimulator<span class="k">${</span><span class="nv">OS</span><span class="k">}</span> <span class="se">\</span>
<span class="nt">-destination</span> <span class="nv">OS</span><span class="o">=</span><span class="k">${</span><span class="nv">OS</span><span class="k">}</span>,name<span class="o">=</span><span class="s2">"iPad Retina"</span> <span class="se">\</span>
<span class="nv">GCC_GENERATE_DEBUGGING_SYMBOLS</span><span class="o">=</span>YES <span class="se">\</span>
<span class="nv">GCC_GENERATE_TEST_COVERAGE_FILES</span><span class="o">=</span>YES <span class="se">\</span>
<span class="nv">GCC_INSTRUMENT_PROGRAM_FLOW_ARCS</span><span class="o">=</span>YES
</code></pre></div></div>
<p>If you’ve just ran this command you will be surprised to find no <code class="highlighter-rouge">.gcda</code> files anywhere. Apparently, writing these files to disk is a costly operation so this data needs to be flushed with explicit command. The way to do that is to call <code class="highlighter-rouge">__gcov_flush</code> in your app’s code. Apple recommends to do that when the app is sent to background, here’s the quote</p>
<blockquote>
<p>Set the UIApplicationExitsOnSuspend key to YES in your Info.plist file and send your running application to the background by pressing the home button.</p>
</blockquote>
<p>This is very un-automatic and very un-CI, Apple. <a href="https://github.com/leroymattingly/XCode5gcovPatch">This readme</a> provides a list of other options. Well, the first one is reacting to the event of app entering background, which is not good. The second option uses method swizzling and swizzles <code class="highlighter-rouge">tearDown</code> method of <code class="highlighter-rouge">XCTest</code> class. This way <code class="highlighter-rouge">GCOV</code> data will be flushed when <em>all</em> the test cases are completed.</p>
<p>I am using swizzling as well, but swizzle <code class="highlighter-rouge">tearDown</code> method of <code class="highlighter-rouge">XCTestCase</code>. This way data is flushed every time a test case finishes.</p>
<pre><code class="language-objective-c">#ifdef ENABLE_GCOV_FLUSH
@import XCTest;
@import ObjectiveC.runtime;
// If you have to build for versions below iOS 7.0, use this code instead
// #import <XCTest/XCTest.h>
// #import <objc/runtime.h>
extern void __gcov_flush();
@implementation XCTestCase (GCovFlush)
+ (void)load {
Method original, swizzled;
original = class_getClassMethod(self, @selector(tearDown));
swizzled = class_getClassMethod(self, @selector(_swizzledTearDown));
method_exchangeImplementations(original, swizzled);
}
+ (void)_swizzledTearDown {
if (__gcov_flush) {
__gcov_flush();
}
[self _swizzledTearDown];
}
@end
#endif
</code></pre>
<p>Note that I don’t have a header file. There’s no need for it since you are not going to include it anywhere. Another notable difference is the use of <code class="highlighter-rouge">ifdef</code> guard <code class="highlighter-rouge">ENABLE_GCOV_FLUSH</code> which needs to be defined when building from command line, this is just me being over paranoid about including any kind of non-production code in the app. Save this file and name it <code class="highlighter-rouge">XCTestCase+GCovFlush.m</code> Before you add it to your project, one very important note</p>
<blockquote>
<p>The file must be added to the main app target, also called “Test Host”, <em>not</em> to the unit tests target. <a href="http://stackoverflow.com/questions/19136767/generate-gcda-files-with-xcode5-ios7-simulator-and-xctest">More details</a>.</p>
</blockquote>
<p>OK, so now you can add this file to your Xcode project. There are ways to automate this injection as well, e.g. using <a href="https://github.com/CocoaPods/Xcodeproj">xcodeproj Ruby gem</a>. I plan to have a write up about it some time later. Anyway, you can now run your tests and have <code class="highlighter-rouge">.gcno</code> and <code class="highlighter-rouge">.gcda</code> files at your disposal.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">export </span><span class="nv">OS</span><span class="o">=</span><span class="k">$(</span>xcrun <span class="nt">--sdk</span> iphonesimulator <span class="nt">--show-sdk-platform-version</span><span class="k">)</span>
xcodebuild <span class="nb">test</span> <span class="nt">-project</span> MyProject.xcodeproj <span class="nt">-scheme</span> MyScheme <span class="se">\</span>
<span class="nt">-configuration</span> Debug <span class="se">\</span>
<span class="nv">CONFIGURATION_BUILD_DIR</span><span class="o">=</span>build <span class="se">\</span>
<span class="nt">-sdk</span> iphonesimulator<span class="k">${</span><span class="nv">OS</span><span class="k">}</span> <span class="se">\</span>
<span class="nt">-destination</span> <span class="s2">"OS=</span><span class="k">${</span><span class="nv">OS</span><span class="k">}</span><span class="s2">,name=iPad Retina"</span> <span class="se">\</span>
<span class="nv">GCC_GENERATE_DEBUGGING_SYMBOLS</span><span class="o">=</span>YES <span class="se">\</span>
<span class="nv">GCC_GENERATE_TEST_COVERAGE_FILES</span><span class="o">=</span>YES <span class="se">\</span>
<span class="nv">GCC_INSTRUMENT_PROGRAM_FLOW_ARCS</span><span class="o">=</span>YES <span class="se">\</span>
<span class="nv">GCC_PREPROCESSOR_DEFINITIONS</span><span class="o">=</span><span class="s2">"</span><span class="se">\$</span><span class="s2">(GCC_PREPROCESSOR_DEFINITIONS) ENABLE_GCOV_FLUSH=1"</span> <span class="se">\</span>
| tee test.log
</code></pre></div></div>
<p>Note that I’m redefining preprocessor definitions to enable <code class="highlighter-rouge">ENABLE_GCOV_FLUSH</code> and also want to reuse those already defined in Xcode project, that’s why I refer to them with help of escaping <code class="highlighter-rouge">$</code> sign. I’m also capturing logs in <code class="highlighter-rouge">test.log</code> for further processing.</p>
<p>This paragraph has nothing to do with coverage reports, but you need to capture test results in a report format that most CI servers would understand. You can use <a href="https://github.com/ciryon/OCUnit2JUnit">ocunit2junit</a> to convert OCUnit (now XCTest) report to <a href="http://junit.org/">JUnit</a> format.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># install</span>
<span class="o">[</span><span class="nb">sudo</span><span class="o">]</span> gem install ocunit2junit
<span class="c"># run</span>
<span class="nb">cat </span>test.log | ocunit2junit
</code></pre></div></div>
<p>Default output is in <code class="highlighter-rouge">test-reports</code> directory, point your CI report plugin to this location to pick up XML and generate test reports.</p>
<p>Another option is <a href="https://github.com/supermarin/xcpretty">xcpretty</a> tool, which is yet another Ruby gem.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># install</span>
<span class="o">[</span><span class="nb">sudo</span><span class="o">]</span> gem intall xcpretty
<span class="c"># generate JUnit XML reports (default location is build/reports directory)</span>
<span class="nb">cat </span>test.log | xcpretty <span class="nt">--report</span> junit <span class="nt">--color</span>
<span class="c"># generate HTML reports (default location is build/reports directory)</span>
<span class="nb">cat </span>test.log | xcpretty <span class="nt">--report</span> html <span class="nt">--color</span>
</code></pre></div></div>
<p>Note that you don’t have to re-run the tests. All that the tool needs is build log.</p>
<p>If you are OK with using something other than <code class="highlighter-rouge">xcodebuild</code>, check out <a href="https://github.com/facebook/xctool">Facebook’s <code class="highlighter-rouge">xctool</code></a>. It has few options to help you get test reports without the need of extra gems. It also supports parallel execution of tests, so definitely worth a look.</p>
<h1 id="report">Report</h1>
<p>It’s time to report the coverage results. <a href="http://gcovr.com/">gcovr</a> is the right tool for the job. Since it’s a Python utility, here’s how you install it</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo</span> <span class="nt">-E</span> easy_install pip
pip install gcovr
</code></pre></div></div>
<p>Use <code class="highlighter-rouge">-E</code> option to tell <code class="highlighter-rouge">easy_install</code> to pick up current user’s environment variables such as <code class="highlighter-rouge">HTTP_PROXY</code> while running as super user. Don’t bother with this option if you can run <code class="highlighter-rouge">easy_install</code> as a non-sudoer, e.g. when you have custom Python installation.</p>
<p>Use <code class="highlighter-rouge">-x</code> or <code class="highlighter-rouge">--xml</code> to generate XML report. <code class="highlighter-rouge">gcovr</code> has issues with generating HTML reports, we’ll have to use another tool for the job later.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">BUILD_DIR</span><span class="o">=</span>build
<span class="nv">GCOV_FILTER</span><span class="o">=</span><span class="s1">'.*/MyClasses.*'</span>
<span class="nv">GCOV_EXCLUDE</span><span class="o">=</span><span class="s1">'(.*./Developer/SDKs/.*)|(.*./Developer/Toolchains/.*)|(.*Tests\.m)|(.*Tests/.*)'</span>
<span class="nv">COVERAGE_REPORT</span><span class="o">=</span>coverage.xml
gcovr <span class="se">\</span>
<span class="nt">--filter</span><span class="o">=</span><span class="k">${</span><span class="nv">GCOV_FILTER</span><span class="k">}</span> <span class="se">\</span>
<span class="nt">--exclude</span><span class="o">=</span><span class="k">${</span><span class="nv">GCOV_EXCLUDE</span><span class="k">}</span> <span class="se">\</span>
<span class="nt">--object-directory</span><span class="o">=</span><span class="k">${</span><span class="nv">BUILD_DIR</span><span class="k">}</span> <span class="nt">-x</span> <span class="o">></span> <span class="k">${</span><span class="nv">COVERAGE_REPORT</span><span class="k">}</span>
</code></pre></div></div>
<p>This example also demonstrates the use of filter and exclude options to filter unwanted files from reports. <code class="highlighter-rouge">BUILD_DIR</code> points to the directory you defined with help of <code class="highlighter-rouge">CONFIGURATION_BUILD_DIR</code> when running the tests.</p>
<p>The XML output is enough for CI tasks, but to have a sneak peek at readable HTML results on your computer you’ll end up nowhere with <code class="highlighter-rouge">gcovr</code>, the tool has a bug (unless it got fixed already). The tool to help at this time is <a href="http://ltp.sourceforge.net/coverage/lcov.php">lcov</a>.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Install.</span>
brew install lcov
<span class="c"># Use.</span>
<span class="nv">BUILD_DIR</span><span class="o">=</span>build
<span class="nv">LCOV_INFO</span><span class="o">=</span>lcov.info
<span class="nv">LCOV_EXCLUDE</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">LCOV_INFO</span><span class="k">}</span><span class="s2"> '*/Xcode.app/Contents/Developer/*' '*Tests.m' '</span><span class="k">$(</span>BUILD_DIR<span class="k">)</span><span class="s2">/*'"</span>
<span class="nv">LCOV_REPORTS_DIR</span><span class="o">=</span>lcov-reports
lcov <span class="nt">--capture</span> <span class="nt">--directory</span> <span class="k">${</span><span class="nv">BUILD_DIR</span><span class="k">}</span> <span class="nt">--output-file</span> <span class="k">${</span><span class="nv">LCOV_INFO</span><span class="k">}</span>
lcov <span class="nt">--remove</span> <span class="k">${</span><span class="nv">LCOV_EXCLUDE</span><span class="k">}</span> <span class="nt">--output-file</span> <span class="k">${</span><span class="nv">LCOV_INFO</span><span class="k">}</span>
genhtml <span class="k">${</span><span class="nv">LCOV_INFO</span><span class="k">}</span> <span class="nt">--output-directory</span> <span class="k">${</span><span class="nv">LCOV_REPORTS_DIR</span><span class="k">}</span>
</code></pre></div></div>
<p>Here you can see another use of exclude option to filter out unwanted results. <code class="highlighter-rouge">genhtml</code> is bundled with <code class="highlighter-rouge">lcov</code> installation. More documentation on <code class="highlighter-rouge">lcov</code> can be <a href="https://wiki.documentfoundation.org/Development/Lcov">found here</a>. You now have browsable coverage report in <code class="highlighter-rouge">lcov-reports</code> directory.</p>
<h1 id="summary">Summary</h1>
<p>The real point of calculating code coverage reports is to use them as part of CI process to keep track of overall project health and mark it as unstable or failed if coverage is less than required. Check out <a href="/mobile%20ci/2015/01/29/bamboo-vs-jenkins">Jenkins vs Bamboo article</a> for more details.</p>
https://mgrebenets.github.io/mobile%20ci/2015/02/08/code-coverage-for-ios
https://mgrebenets.github.io/mobile%20ci/2015/02/08/code-coverage-for-ios2015-02-08T00:00:00+00:00Clang Static Analyzer
<p>A brief post about <a href="http://clang-analyzer.llvm.org/">Clang Static Analyzer</a> and <a href="http://clang-analyzer.llvm.org/scan-build.html">scan-build</a> tool.</p>
<!--more-->
<p>Clang Static Analyzer is a source code analysis tool that finds bugs in C, C++, and Objective-C programs. Yep, no Swift yet.</p>
<h1 id="xcode-and-xcodebuild">Xcode and <code class="highlighter-rouge">xcodebuild</code></h1>
<p>You may have used it already since a stable build of clang static analyzer comes bundled with Xcode. It’s <code class="highlighter-rouge">⌘⇧B</code> (Command + Shift + B) shortcut in Xcode or <code class="highlighter-rouge">analyze</code> action when building from command line.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>xcodebuild analyze <span class="se">\</span>
<span class="nt">-project</span> MyProject.xcodeproj <span class="se">\</span>
<span class="nt">-scheme</span> MyScheme <span class="se">\</span>
<span class="nt">-sdk</span> iphonesimulator <span class="se">\</span>
<span class="nt">-destination</span> <span class="s2">"name=iPhone 6s Plus,OS=9.2"</span> <span class="se">\</span>
<span class="nt">-configuration</span> Debug
</code></pre></div></div>
<p>Note the use of <code class="highlighter-rouge">-sdk</code> and <code class="highlighter-rouge">-destination</code> options. Latest Xcode versions may play dumb when used from command line and will want explicit destination specified. By default the build destination will be <code class="highlighter-rouge">Generic iOS Device</code> and will most likely require code signing.</p>
<p>When running Analyze action in Xcode you get a beautiful report with nice arrows rendered right on top of the source code.
While running from command line the analyzer errors will show up in build log.</p>
<p>The build log by itself should be enough for integration with CI servers, but you can actually get more out of standard <code class="highlighter-rouge">xcodebuild analyze</code> action. Using <code class="highlighter-rouge">CLANG_ANALYZER_OUTPUT</code> and <code class="highlighter-rouge">CLANG_ANALYZER_OUTPUT_DIR</code> you can control in which form analyzer creates report and where. Valid options for <code class="highlighter-rouge">CLANG_ANALYZER_OUTPUT</code> are <code class="highlighter-rouge">text</code>, <code class="highlighter-rouge">html</code> and <code class="highlighter-rouge">plist</code>. You can combine multiple options using dashes, e.g. <code class="highlighter-rouge">plist-html</code>.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>xcodebuild analyze <span class="se">\</span>
<span class="nt">-project</span> MyProject.xcodeproj <span class="se">\</span>
<span class="nt">-scheme</span> MyScheme <span class="se">\</span>
<span class="nt">-sdk</span> iphonesimulator <span class="se">\</span>
<span class="nt">-destination</span> <span class="s2">"name=iPhone 6s Plus,OS=9.2"</span> <span class="se">\</span>
<span class="nt">-configuration</span> Debug <span class="se">\</span>
<span class="nv">CLANG_ANALYZER_OUTPUT</span><span class="o">=</span>plist-html <span class="se">\</span>
<span class="nv">CLANG_ANALYZER_OUTPUT_DIR</span><span class="o">=</span><span class="s2">"</span><span class="k">$(</span><span class="nb">pwd</span><span class="k">)</span><span class="s2">/clang"</span>
</code></pre></div></div>
<p>There will be a lot of output files in <code class="highlighter-rouge">clang</code> directory, using <code class="highlighter-rouge">find</code> you can locate HTML report.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>find clang <span class="nt">-name</span> <span class="s2">"*.html"</span>
<span class="c"># It will find a file named like report-f27e58.html</span>
</code></pre></div></div>
<p>Open it in a browser and it looks just like the one in Xcode.</p>
<h2 id="under-the-hood">Under the Hood</h2>
<p>If you are curious what are those not-so-much-documented <code class="highlighter-rouge">CLANG_ANALYZER_</code> build settings, this section may shed some light for you.</p>
<p><code class="highlighter-rouge">CLANG_ANALYZER_OUTPUT=html</code> translates into <code class="highlighter-rouge">-Xclang -analyzer-output=html</code> when <code class="highlighter-rouge">xcodebuild</code> composes and executes <code class="highlighter-rouge">clang</code> command. Similar story for <code class="highlighter-rouge">CLANG_ANALYZER_OUTPUT_DIR</code>. You can call <code class="highlighter-rouge">clang -cc1 --help</code> yourself, there are a lot of interesting things in the help message. For example, running <code class="highlighter-rouge">clang -cc1 -analyze -analyzer-checker-help</code> will list all the available checkers. If you look at build log closely now, you will see how <code class="highlighter-rouge">xcodebuild</code> configures all those checkers using <code class="highlighter-rouge">-Xclang -analyzer-config</code> and <code class="highlighter-rouge">-Xclang -analyzer-checker</code> flags.</p>
<p>With this knowledge, you should be able to tweak default Xcode Analyze configuration by modifying Xcode build settings. To be honest, I never had to do that. If you really want more control over static analyzer, you should look at <a href="http://clang-analyzer.llvm.org/scan-build.html">scan-build</a> tool.</p>
<h1 id="scan-build">scan-build</h1>
<p><a href="http://clang-analyzer.llvm.org/scan-build.html">scan-build</a> is a command line utility that enables a user to run the static analyzer over their codebase as part of performing a regular build (from the command line).</p>
<h2 id="why-scan-build">Why scan-build?</h2>
<p><em>If Xcode comes with a static analyzer already available, why bother and use another tool?</em></p>
<p><code class="highlighter-rouge">scan-build</code> has a newer version of static analyzer with a number of experimental checks enabled. For example, using Xcode 7.2.1 I got 0 analyzer warnings when running Analyze action on a given project. For the very same project <code class="highlighter-rouge">scan-build</code> finds 6 warnings related to nullability and detects possible <code class="highlighter-rouge">nil</code> values passed to methods that don’t expect <code class="highlighter-rouge">nil</code>.</p>
<h2 id="installation">Installation</h2>
<p>Clang Static Analyzer is not available for installation via Homebrew directly. You <em>can</em> get it as part of <code class="highlighter-rouge">llvm</code> package if installed with <code class="highlighter-rouge">--with-clang</code> option, but this is not recommended, because Homebrew <code class="highlighter-rouge">llvm</code> version will not be the same as Apple LLVM version. You won’t be able to build your iOS projects with this toolchain right away.</p>
<p>So I would recommend to use the <a href="https://github.com/mgrebenets/homebrew-scan-build">custom Homebrew tap</a> instead.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew tap mgrebenets/scan-build
brew install scan-build
</code></pre></div></div>
<p>Run <code class="highlighter-rouge">scan-build</code> to make sure installation is successful.</p>
<h2 id="usage">Usage</h2>
<p>You can use it in two ways, from Xcode or from command line.</p>
<p>To learn how to use it from Xcode <a href="http://clang-analyzer.llvm.org/xcode.html">read this documentation</a>. I never actually did it. Aware that others mention <a href="http://loufranco.com/blog/xcode-better-build-and-analyze">a number of caveats</a> with this approach, some not so obvious configuration tweaks required to make it work properly.</p>
<p>I’m more interested in running it from command line and generating reports for CI tasks. <a href="http://clang-analyzer.llvm.org/scan-build.html">Here’s the original documentation</a> with some good examples.</p>
<p>The basic usage is supposed to be as simple as this</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Build a scheme</span>
scan-build <span class="nt">-k</span> <span class="nt">-v</span> <span class="nt">-v</span> xcodebuild clean build <span class="se">\</span>
<span class="nt">-project</span> MyProject.xcodeproj <span class="se">\</span>
<span class="nt">-scheme</span> MyScheme <span class="se">\</span>
<span class="nt">-destination</span> <span class="s2">"name=iPhone 6s Plus,OS=9.2"</span> <span class="se">\</span>
<span class="nt">-configuration</span> Debug
</code></pre></div></div>
<p>Note the use of <code class="highlighter-rouge">clean build</code> and not just <code class="highlighter-rouge">build</code>. I have discovered that <code class="highlighter-rouge">clean</code> action may not be necessary and for me just running <code class="highlighter-rouge">build</code> action works as well and yields the same results.</p>
<p>By default <code class="highlighter-rouge">scan-build</code> will use static analyzer version bundled with its own installation (<code class="highlighter-rouge">clang-check</code>). You may choose to specify an explicit path to static analyzer executable or fall back to using the version bundled with Xcode.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Use analyzer bundled with xcode.</span>
scan-build <span class="nt">-k</span> <span class="nt">-v</span> <span class="nt">-v</span> <span class="nt">--use-analyzer</span> Xcode <span class="se">\</span>
xcodebuild clean build <span class="se">\</span>
<span class="nt">-project</span> MyProject.xcodeproj <span class="se">\</span>
<span class="nt">-scheme</span> MyScheme <span class="se">\</span>
<span class="nt">-destination</span> <span class="s2">"name=iPhone 6s Plus,OS=9.2"</span> <span class="se">\</span>
<span class="nt">-configuration</span> Debug
<span class="c"># Use explicit path to clang-check executable.</span>
<span class="nv">CLANG_CHECK</span><span class="o">=</span><span class="k">$(</span>which clang-check<span class="k">)</span>
scan-build <span class="nt">-k</span> <span class="nt">-v</span> <span class="nt">-v</span> <span class="nt">--use-analyzer</span> <span class="k">${</span><span class="nv">CLANG_CHECK</span><span class="k">}</span> <span class="se">\</span>
xcodebuild clean build <span class="se">\</span>
<span class="nt">-project</span> MyProject.xcodeproj <span class="se">\</span>
<span class="nt">-scheme</span> MyScheme <span class="se">\</span>
<span class="nt">-destination</span> <span class="s2">"name=iPhone 6s Plus,OS=9.2"</span> <span class="se">\</span>
<span class="nt">-configuration</span> Debug
</code></pre></div></div>
<h2 id="reports">Reports</h2>
<p>Use <code class="highlighter-rouge">-o</code> (output) option to specify output directory for reports.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir <span class="nt">-p</span> clang-reports
<span class="c"># Build a target.</span>
scan-build <span class="nt">-k</span> <span class="nt">-v</span> <span class="nt">-v</span> <span class="se">\</span>
<span class="nt">--use-analyzer</span> Xcode <span class="se">\</span>
<span class="nt">-o</span> clang-reports <span class="se">\</span>
xcodebuild clean build <span class="se">\</span>
<span class="nt">-project</span> MyProject.xcodeproj <span class="se">\</span>
<span class="nt">-scheme</span> MyScheme <span class="se">\</span>
<span class="nt">-destination</span> <span class="s2">"name=iPhone 6s Plus,OS=9.2"</span> <span class="se">\</span>
<span class="nt">-configuration</span> Debug
</code></pre></div></div>
<p>There are dozens of other options you can use to customize <code class="highlighter-rouge">scan-build</code>, try <code class="highlighter-rouge">scan-build -h</code> to see all of them.</p>
<p>It is also supposed to be easier to customize checkers with <code class="highlighter-rouge">scan-build</code>. I had never had a chance to do that, you must have some compelling reason to go beyond default configuration.</p>
<h2 id="troubleshooting">Troubleshooting</h2>
<p>If you get an error like this: <code class="highlighter-rouge">clang: error: unknown argument: '-fembed-bitcode-marker'</code>, make sure you have specified both <code class="highlighter-rouge">-sdk</code> and <code class="highlighter-rouge">-destination</code> options to <code class="highlighter-rouge">xcodebuild</code>.</p>
<p>Same applies for <code class="highlighter-rouge">xcodebuild</code> failing to find imports like <code class="highlighter-rouge">#import <UIKit/UIKit.h></code>.</p>
<h1 id="ci">CI</h1>
<p>I’ve already touched this topic in my <a href="/mobile%20ci/2015/01/29/bamboo-vs-jenkins">Jenkins vs Bamboo</a> comparison. For both CI servers your best option is to publish clang static analyzer reports as HTML page. Analyzer warnings and errors will also be picked up by <a href="https://wiki.jenkins-ci.org/display/JENKINS/Warnings+Plugin">Warnings plugin</a> in case of Jenkins, and you are up to some grepping or other voodoo if you are dealing with Bamboo.</p>
<p>All in all clang static analyzer is another great tool to have at your disposal, especially if you are working on CI tasks.</p>
<h1 id="references">References</h1>
<ul>
<li><a href="https://gist.github.com/masuidrive/5231110">clang -cc1 options list</a></li>
<li><a href="http://clang.llvm.org/docs/CommandGuide/clang.html">Clang Command Guide</a></li>
<li><a href="http://stackoverflow.com/questions/14277773/getting-html-output-from-xcodes-built-in-static-analysis">SO discussion wrt xcodebuild analyze output 1</a></li>
<li><a href="http://stackoverflow.com/questions/22371789/how-to-make-the-clang-static-analyzer-output-its-working-from-command-line">SO discussion wrt xcodebuild analyze output 2</a></li>
</ul>
https://mgrebenets.github.io/mobile%20ci/2015/02/08/clang-static-analyzer
https://mgrebenets.github.io/mobile%20ci/2015/02/08/clang-static-analyzer2015-02-08T00:00:00+00:00Bitbucket Branches and Jenkins Job DSL
<p>A simple example of applying <a href="https://wiki.jenkins-ci.org/display/JENKINS/Job+DSL+Plugin">Jenkins Job DSL Plugin</a> in real life.</p>
<!--more-->
<p>For any real life application of any tool you have to start with real life problem or a goal you want to achieve. In this case, the goal is to generate Jenkins build projects for all Git branches of your project. Remote repository in this example is Bitbucket, which makes things a bit more different compared to dealing with GitHub.</p>
<p>You have probably ended up here by following the link from <a href="/mobile%20ci/2015/01/29/bamboo-vs-jenkins">this article</a>. To reiterate, there are couple of Jenkins plugins that come close to solving the original problem, but they have number of serious drawbacks. So let’s see how you can solve this problem with help of Jenkins Job DSL.</p>
<h1 id="get-bitbucket-branches">Get Bitbucket Branches</h1>
<p>First, let’s start with <a href="https://github.com/jenkinsci/job-dsl-plugin/wiki/Real-World-Examples">example for GitHub</a>.</p>
<script src="https://gist.github.com/6b2840df486613bf4b83e924e172bd71.js"> </script>
<p>The first 3 lines are hitting GitHub API and grab the list of all branches. This code is not going to work for Bitbucket, so we need to come up with something different. Another complication is that (in my case) we are dealing with private Bitbucket repository, so need to take authorization into account. So lets figure out what’s the URL to hit. The components of URL are</p>
<ul>
<li>API Base URL - by default it’s <a href="https://bitbucket.org/api">https://bitbucket.org/api</a></li>
<li>API Version - <em>1.0</em> or <em>2.0</em></li>
<li>API Endpoint Path - includes the following
<ul>
<li>“repositories” - since we want to use one of the repositories API</li>
<li>Organization Name - aka team or account name</li>
<li>Repository Name - repository slug</li>
<li>Repositories API Endpoint - <em>branches</em> since we want to get list of branches</li>
</ul>
</li>
</ul>
<p>Time to put it all together</p>
<script src="https://gist.github.com/04941cb42fb0cde4531db87574596849.js"> </script>
<p>Next we need to convert this string to <code class="highlighter-rouge">URL</code>, hit it and parse the output. But before we do that, we have to set Authorization header for HTTPS authentication with username and password. The username and password should be Base64 encoded.</p>
<script src="https://gist.github.com/8b68a43fe282c2a5c609d9c19c524514.js"> </script>
<p>This code, when put together, will return list of all branches in JSON format, or will not in case you are behind the…</p>
<h1 id="proxy">Proxy</h1>
<p>This bit of code will help you to configure proxy for JVM</p>
<script src="https://gist.github.com/8d5177201ccd5c676651b1e0573f82bf.js"> </script>
<p>Yep, <code class="highlighter-rouge">";"</code>s are a legacy thing and I put them there to demonstrate relation between Java and Groovy. In general, any Java code is a valid Groovy code, but not the other way around.</p>
<h1 id="filter-branches">Filter Branches</h1>
<p>The JSON returned by Bitbucket API is a dictionary. Each entry has branch name as a key and branch description as value. Branch description is yet another dictionary with entries such as author, last commit hash and message, timestamp for last update, etc. Here’s an example.</p>
<script src="https://gist.github.com/39adfc61580453105354ca02ec648e95.js"> </script>
<p>To experiment with Bitbucket API directly you can use this <a href="http://restbrowser.bitbucket.org/">REST Browser</a>.</p>
<p>Using this information you can filter out unwanted branches. The reason to do that is that not all developers do a proper cleanup after their branches are merged. You can end up with branches as old as 3 years or more, which you don’t want to pick up and create CI build project for. So you can use <em>timestamp</em> information to ignore branches, which haven’t been updated for a long time. This is also an opportunity to enforce correct branch naming rules and filter all branches with incorrect names.</p>
<blockquote>
<p>An answer an absolutely valid question of “Why the branches are not deleted automatically on merge?” That’s because some versions of git-flow do not use Bitbucket’s native merge feature, but use a rebase instead. Thus the branches are left hanging around after they are merged and it becomes developer’s responsibility to delete the branch.</p>
</blockquote>
<script src="https://gist.github.com/d1d9621f77bd7e3fea426a0d3ebad0f1.js"> </script>
<p>Let’s go through the code in case comments are not descriptive enough. The main part is iterating over JSON dictionary <code class="highlighter-rouge">branchesJson</code> returned by Bitbucket API. On each iteration we have branch name <code class="highlighter-rouge">branchName</code> and its details packed as <code class="highlighter-rouge">details</code> JSON dictionary. We get the last modified date <em>timestamp</em> and convert it into the <code class="highlighter-rouge">Date</code> object. Now we can check if the branch has valid name and is not too old.</p>
<p><em>Valid</em> name in this example means that branch is one of the major branches (<em>master</em>, <em>development</em> and anything that starts with <em>release</em>), or that branch name has one of the 3 valid prefixes (<em>feature</em>, <em>bugfix</em> and <em>hotfix</em>). <code class="highlighter-rouge">isValidBranch</code> method splits the branch name by <code class="highlighter-rouge">"/"</code>, gets the first element and checks if it’s one of the valid prefixes.</p>
<p>Another filter is for branches that are too old, or in other words branches that haven’t been updated for too long. This is what <code class="highlighter-rouge">isUpToDateBranch</code> method is for. Note that we consider all major branches to be always up to date. For example, <em>master</em> branch can be updated only when major releases occur and we don’t want its build project to be removed in the meantime. If Jenkins project is removed and then created again, its build number will be reset to 1, this is something we want to avoid, especially if build number is baked into the app version. Anyway, the logic is straightforward, if branch is one of the major branches, then consider it to be up to date. Otherwise, compare branch last modified date with current date and if the difference is more that expected (15 days in this example), then ignore this branch.</p>
<p>Then there’s a note, that no <code class="highlighter-rouge">def</code> keyword or type are used to declare <code class="highlighter-rouge">majorBranches</code>, <code class="highlighter-rouge">validBranchPrefixes</code> and <code class="highlighter-rouge">allValidPrefixes</code> variables. This is intentional. Omission of <code class="highlighter-rouge">def</code> makes these variables a so called <em>binding</em> variables. This is due to the fact that you are working with a Groovy script here and you have to declare variables like this to make them available for methods, e.g. to refer to them inside <code class="highlighter-rouge">isValidBranch</code> and <code class="highlighter-rouge">isUpToDateBranch</code>. I know it doesn’t sound like a solid explanation, but you have to take into account the fact that I myself should be considered as Groovy beginner, so this is the best I can come up with at the moment.</p>
<p>Final bit that needs some explanation, is the use of <code class="highlighter-rouge">job</code> construction. <code class="highlighter-rouge">job</code> is a property of the Groovy script you are running. In fact, the scrip itself is an instance of <a href="https://github.com/jenkinsci/job-dsl-plugin/blob/master/job-dsl-core/src/main/groovy/javaposse/jobdsl/dsl/DslFactory.groovy">DslFactory</a> class. Job is configured with a closure. The bare minimum it needs to create Jenkins Job (or as I refer to it in this article <em>Project</em>), is <code class="highlighter-rouge">name</code>, so I set it to current branch name replacing all <code class="highlighter-rouge">"/"</code>s with <code class="highlighter-rouge">"-"</code>s in the process.</p>
<h1 id="summary">Summary</h1>
<p>As a summary for this post, you can try to run Job DSL script on real Jenkins. First or all, you need to have an access to Jenkins server. Next, you have to have <a href="https://wiki.jenkins-ci.org/display/JENKINS/Job+DSL+Plugin">Jenkins Job DSL Plugin</a> installed. Another required plugin is <a href="https://wiki.jenkins-ci.org/display/JENKINS/Git+Plugin">Git Plugin</a>.</p>
<p>OK, so I assume you’re looking at Jenkins dashboard right now. Go ahead and create <em>New Item</em>. Choose a name for your project and select <em>Freestyle project</em> type and click “OK”.</p>
<p><img src="https://mgrebenets.github.io/assets/images/jenkins-bitbucket-branches-create-dsl.png" alt="Create DSL Project" /></p>
<p>On new project configuration page you can leave everything “as is” for this example, the only thing you need to do is to add a new build step of “Process Job DSLs” type.</p>
<p><img src="https://mgrebenets.github.io/assets/images/bitbucket-dsl-add-build-step.png" alt="Add Build Step" /></p>
<p>Now you can <a href="https://gist.github.com/mgrebenets/d3b5dcabb7606f3d7863">grab this DSL script gist</a> and copy-paste it in Jenkins. Don’t forget to select “Use the provided DSL script” option first.</p>
<p><img src="https://mgrebenets.github.io/assets/images/copy-paste-bitbucket-dsl-script.png" alt="Provide DSL Script" /></p>
<p>You should have noticed that DSL script you just copied doesn’t have the authentication and proxy bit enabled by default. I decided to make those steps optional so that you could run it in any environment. Since it points to a public repository, no authentication is required. Feel free to modify it to point to your private or public repo and to use your proxy.</p>
<p>OK, run it now and you should see something like this.</p>
<p><img src="https://mgrebenets.github.io/assets/images/bitbucket-dsl-result.png" alt="Generated Jobs" /></p>
<p>Here you have 2 Jenkins jobs generated for <em>master</em> and <em>development</em> branches.</p>
<p>This is just the beginning, from this moment on you can have numerous improvements. For example</p>
<ul>
<li>Refactor one big monolith script into packages and classes, such as
<ul>
<li>Class to work with Bitbucket API</li>
<li>Class to configure network proxy</li>
<li>etc.</li>
</ul>
</li>
<li>Put the script into repository and modify DSL job to clone repo and run the script from it</li>
<li>And much more…</li>
</ul>
https://mgrebenets.github.io/mobile%20ci/2015/02/08/bitbucket-branches-job-dsl
https://mgrebenets.github.io/mobile%20ci/2015/02/08/bitbucket-branches--job-dsl2015-02-08T00:00:00+00:00Xcode Derived Data
<p>What is Xcode Derived Data and why is it important?</p>
<!--more-->
<p>“Clean derived data”. You might have heard this phrase each time you face some extremely strange build problems.</p>
<p>DerivedData is a folder located in <code class="highlighter-rouge">~/Library/Developer/Xcode/DerivedData</code> by default. It’s the location where Xcode stores all kinds of intermediate build results, generated indexes, etc. DerivedData location can be configured in Xcode preferences (Locations tab).</p>
<p>So now and then you run into odd build problems. The more complex your project is the more chances you have to face them. Using Swift increases that probability a fair bit. DerivedData folder is also infamous for growing up to gargantuan sizes.</p>
<p>I have faced this issue when dealing with Jenkins CI server running as Launch Daemon. Special jenkins non-login user would run <code class="highlighter-rouge">xcodebuild</code> and that would create intermediate build files in DerivedData folder. But these new files would have access rights configured for non-login user. If you manually build the same project in the same folder while logged in as a “normal” login user you will mess up with files created previously by jenkins user. You will then see further build jobs failing while trying to write to DerivedData. Same applies to Bamboo or any other CI server running as Launch Daemon.</p>
<p>The lesson is - don’t mess up and run things manually in your CI server’s guts. Another lesson, <a href="/mobile%20ci/2015/02/01/mobile-ci-daemon-vs-agent">don’t run CI Xcode build jobs as non-login user</a> to avoid permissions problems. A practical advice to take home - clean Xcode Derived Data on regular basis on your CI box(es). You could create a cron job to do that, make it run some time after midnight and execute this simple shell command</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rm <span class="nt">-rf</span> /Users/username/Library/Developer/Xcode/DerivedData/<span class="k">*</span>
</code></pre></div></div>
<p>Note the use of full path in the command. That’s in case you do have multiple user accounts as part of your CI setup and the plan can run under any of those accounts.</p>
<p>If you happen to have multiple build agents running on multiple machines (either physical or virtual), then each of those agents should do it’s own cleanup.</p>
<p>Cleaning derived data might increase the time of first build for each project next day, but it’s a minor drawback. You will also claim free space back by killing DerivedData’s huge appetite.</p>
<p>For daily use on your development machine create a type alias in your bash profile.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>typealias xcode-clean-derived<span class="o">=</span><span class="s2">"rm -rf /Users/i4niac/Library/Developer/Xcode/DerivedData/*"</span>
</code></pre></div></div>
https://mgrebenets.github.io/mobile%20ci/2015/02/01/xcode-derived-data
https://mgrebenets.github.io/mobile%20ci/2015/02/01/xcode-derived-data2015-02-01T00:00:00+00:00Daemon vs Agent
<p>Comparison of Mac OS X Launch Daemon and Launch Agent in regards to Mobile CI.</p>
<!--more-->
<p><a href="https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html">Launch Daemons and Launch Agents</a> are Mac OS X mechanisms used to launch and then control processes in the background. In regards to Mobile CI launch daemons and agents are often used to run CI server and agent instances.</p>
<h1 id="compare">Compare</h1>
<p>Here’s the table with brief comparison.</p>
<style>
table:nth-of-type(1) {
display:table;
width:100%;
}
table:nth-of-type(1) th:nth-of-type(2) {
width:30%;
}
</style>
<table>
<thead>
<tr>
<th> </th>
<th style="text-align: center">Daemon</th>
<th style="text-align: center">Agent</th>
</tr>
</thead>
<tbody>
<tr>
<td>Launch Time</td>
<td style="text-align: center">System start</td>
<td style="text-align: center">User login</td>
</tr>
<tr>
<td>User Type</td>
<td style="text-align: center">Non-login</td>
<td style="text-align: center">Login</td>
</tr>
<tr>
<td>Home Folder</td>
<td style="text-align: center">No</td>
<td style="text-align: center">Yes</td>
</tr>
<tr>
<td>Login Keychain</td>
<td style="text-align: center">No</td>
<td style="text-align: center">Yes</td>
</tr>
<tr>
<td>iOS Simulator</td>
<td style="text-align: center">No</td>
<td style="text-align: center">Yes</td>
</tr>
<tr>
<td>Provisioning Profiles</td>
<td style="text-align: center">No</td>
<td style="text-align: center">Yes</td>
</tr>
</tbody>
</table>
<p><br /></p>
<p>Let’s analyze each criteria in more detail.</p>
<h2 id="launch-time">Launch Time</h2>
<p>Launch daemon starts at the time of system boot while agent starts at the time of user login. That usually means you would have to enable autologin option for the user account which is responsible to launching your CI server or agent.</p>
<h2 id="user-type">User Type</h2>
<p>To run at the time of system start launch daemon user has to be a non-login user. This means that the user can not login into OS X windows system, the only way to work with this user account is via SSH sessions. This will cause more problems when we look at next comparison criteria. Launch agent is a login user and that means she can login into windows system, install applications (if the user has enough rights) and do other things.</p>
<h2 id="home-folder">Home Folder</h2>
<p>This is really a part of being login or non-login user. Login user as all the other standard users has a home folder in <code class="highlighter-rouge">/Users</code>. Non-login user has no home and if you need a place for it to store its files you will have to create one manually.</p>
<h2 id="login-keychain">Login Keychain</h2>
<p>Keychain is important for Mobile CI, especially for iOS. Whether you build for Enterprise, App Store or AdHoc distribution you have to sign the app bundle. To be able to sign you need a private-public key pair in your keychain and you <strong>need to have access</strong> to that keychain. Public key is part of the certificate so when I reference public key I also mean certificate that contains it.</p>
<p>With login user you can install development credentials (private-public key pair) into Login keychain in a very simple way. With non-login user you have no keychain to start with. Then you have to keep it up to date and make sure you put all new keys in that keychain.</p>
<h2 id="ios-simulator">iOS Simulator</h2>
<p>Last but not least is the ability to use iOS Simulator. Unit tests are essential part of any CI and you have to run them in iOS Simulator which is a GUI app, and that means only login user can run it. Have a look <a href="http://stackoverflow.com/questions/25380365/timeout-when-running-xcodebuild-tests-under-xcode-6-via-ssh">at this discussion</a> with some comments quoting Apple who recommends to use launch agent.</p>
<h2 id="provisioning-profiles">Provisioning Profiles</h2>
<p>iOS Provisioning Profiles are normally managed by Xcode and located in <code class="highlighter-rouge">~/Library/MobileDevice/Provisioning Profiles</code> in the home folder of a <em>login</em> user who installed Xcode on the system. When you pass provisioning profile UUID to <code class="highlighter-rouge">xcodebuild</code> command it looks for the profile in that folder. So if you run <code class="highlighter-rouge">xcodebuild</code> as non-login user the lookup will fail and you will be forced to specify full path to provisioning profile.</p>
<p>One of the solutions is to create a symlink like this.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><non-login-user-home>/MobileDevice/Provisioning Profiles <span class="nt">--</span><span class="o">></span> /Users/login-user/MobileDevice/Provisioning Profiles
</code></pre></div></div>
<p>I have witnessed situations where by accident or on purpose the permissions of symlink were changed, thus changing permissions and/or ownership of <code class="highlighter-rouge">Provisioning Profile</code> folder in login user’s home. Wrong permissions were causing problems to Xcode, it wasn’t able to sync profiles because of that.</p>
<h1 id="permissions-hell">Permissions Hell</h1>
<p>Let’s assume you have CI server running as a launch daemon. As discussed above default local agents are not capable of running iOS unit tests. Essentially your whole Mac box is incapable of running a lion share of your CI jobs. The solution is to create a remote agent running on the same host and configure that agent to run as a launch agent.</p>
<p>Let’s further assume that you are dealing with some legacy setup and default non-login local agents actually run some jobs, they execute <code class="highlighter-rouge">xcodebuild</code> commands but never run unit tests. Now you add another build agent to run on the same box. Both these agents will share same Git cache, so don’t be surprised when eventually Git fails to checkout repository. I haven’t yet identified the core cause of this issue, but everything points to file permissions. Daemon and launch agent build nodes both run under different user accounts and create files with different permissions, so eventually they’ll run into the trouble when working with shared cache.</p>
<h1 id="summary">Summary</h1>
<p>Let’s summarize all the benefits and drawback of using Launch Daemon.</p>
<p>Benefits:</p>
<ul>
<li>Starts at system boot</li>
</ul>
<p>Drawbacks:</p>
<ul>
<li>No Keychain</li>
<li>Can’t run unit tests (iOS Simulator)</li>
<li>Can’t launch any GUI apps (e.g. <a href="https://www.genymotion.com/">Genymotion</a> for Android)</li>
<li>Potential file permission issues when running alongside another build agents</li>
<li>Can’t easily access Provisioning Profiles</li>
</ul>
<p>I would advise to avoid using Launch Daemons for Mobile CI servers or build agents at all costs.</p>
<p>If you really-really-really have to use Launch Daemon to fire up CI server, make sure it runs no Mobile CI jobs on it’s default local build agents, setup a remote build node instead running on the same box as a launch agent.</p>
https://mgrebenets.github.io/mobile%20ci/2015/02/01/mobile-ci-daemon-vs-agent
https://mgrebenets.github.io/mobile%20ci/2015/02/01/mobile-ci-daemon-vs-agent2015-02-01T00:00:00+00:00Jenkins Remote Node on Mac OS X
<p>A guide for setting up a remote build node for Jenkins CI server.</p>
<!--more-->
<p>If you are up to a task to setup remote build node, that means that you already have a server or need to <a href="/mobile%20ci/2015/02/01/jenkins-ci-server-on-osx">install it first</a>.</p>
<p>A good place to start is <a href="https://wiki.jenkins-ci.org/display/JENKINS/Distributed+builds">Jenkins Wiki page</a> with detailed description of all available options. Don’t forget to have a proper <a href="/mobile%20ci/2015/02/15/install-java-on-mac-os-x">JVM installation</a> first.</p>
<p>I would recommend to do first time agent installation via Jenkins UI <code class="highlighter-rouge">Jenkins -> Manage Jenkins -> Manage Nodes</code>. Select an option to create node, configure node’s properties (make sure root directory exists) and you are almost good to go. The preferred way to launch and agent is via SSH.</p>
<p>If Jenkins Wiki is such a good reference, then why bother with the post? - I bet that’s exactly what you are asking.</p>
<p>Well, again, the main focus is Mobile CI and part of any decent CI is tests, unit tests in particular. With iOS those must run in iOS Simulator which is a GUI application, which means you are facing <a href="/mobile%20ci/2015/02/01/mobile-ci-daemon-vs-agent">Daemon vs Agent</a> issue. Here’s a very good <a href="http://stackoverflow.com/questions/25380365/timeout-when-running-xcodebuild-tests-under-xcode-6-via-ssh">discussion on StackOverflow</a>.</p>
<p>So remote node launched via SSH is running as Launch Daemon and has no context to run GUI applications. If SSH session is running under non-login user, <code class="highlighter-rouge">xcodebuild test</code> will fail with error code <code class="highlighter-rouge">139</code> or alike. Running SSH session under login user will not help either, at best the simulator will launch but tests will never start. That rules out an option of running remote node via SSH. Trying all the tricks like enabling development mode, updating user’s group and security settings, didn’t work for me, probably because that answer was actual for Xcode 5, but not 6 and above.</p>
<p>Next option would be launching slave agent via Java Web Start. Option with clicking button in the browser should be ignored right away, it hardly qualifies as automated approach. Using <code class="highlighter-rouge">javaws</code> it a bit better though requires you to login to slave agent via GUI and then run the command and answer one prompt by clicking Run button. Finally, you can run it in a headless mode</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>java <span class="nt">-jar</span> slave.jar <span class="se">\</span>
<span class="nt">-jnlpUrl</span> http://yourserver:8080/jenkins/computer/parasite/slave-agent.jnlp
</code></pre></div></div>
<p>Now that’s better, this will start a slave agent that is capable of running GUI applications and thus running iOS unit tests in simulator. If you are puzzled where does <code class="highlighter-rouge">slave.jar</code> come from, the answer is that it is put there by Jenkins server when you have created slave agent via Jenkins UI. The <code class="highlighter-rouge">jnlpUrl</code> tells an agent where the server is. The order in which agent and server are fired up seems to be important. Server first, agent second, otherwise agent may fail to start. I had this issue while using GUI mode launch via <code class="highlighter-rouge">javaws</code> and yet to confirm if it’s true for headless mode. Still you have to start an agent manually if remote node machine reboots.</p>
<p>I have one solution to offer. It is not the best I can think of, but it’s the easiest and reasonably reliable to start with. You need to turn the headless slave launch command into a Launch Agent. The Launch Agent will start at the time of user’s login, so make sure the machine is configured for automatic login.</p>
<p>Setting up Launch Agent should become a usual drill for you after you deal with Mac-based CI for a while. Create a plist file in <code class="highlighter-rouge">~/Library/LaunchAgents</code>, name it what you like, for example <code class="highlighter-rouge">org.jenkins-agent-a.plist</code> and put the following content in it.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><?xml version="1.0" encoding="UTF-8"?></span>
<span class="cp"><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"></span>
<span class="nt"><plist</span> <span class="na">version=</span><span class="s">"1.0"</span><span class="nt">></span>
<span class="nt"><dict></span>
<span class="nt"><key></span>StandardOutPath<span class="nt"></key></span>
<span class="nt"><string></span>/Shared/Users/Jenkins-Agent-A/log/jenkins-agent-a-out.log<span class="nt"></string></span>
<span class="nt"><key></span>StandardErrorPath<span class="nt"></key></span>
<span class="nt"><string></span>/Shared/Users/Jenkins-Agent-A/log/jenkins-agent-a-err.log<span class="nt"></string></span>
<span class="nt"><key></span>KeepAlive<span class="nt"></key></span>
<span class="nt"><true/></span>
<span class="nt"><key></span>Label<span class="nt"></key></span>
<span class="nt"><string></span>org.jenkins-agent-a<span class="nt"></string></span>
<span class="nt"><key></span>ProgramArguments<span class="nt"></key></span>
<span class="nt"><array></span>
<span class="nt"><string></span>/usr/bin/java<span class="nt"></string></span>
<span class="c"><!--<string>-Djava.util.logging.config.file=/opt/hudson/slave/logging.properties</string>--></span>
<span class="nt"><string></span>-Duser.home=/Users/Shared/Jenkins-Agent-A<span class="nt"></string></span>
<span class="nt"><string></span>-jar<span class="nt"></string></span>
<span class="nt"><string></span>/Users/Shared/Jenkins-Agent-A/slave.jar<span class="nt"></string></span>
<span class="nt"><string></span>-jnlpUrl<span class="nt"></string></span>
<span class="nt"><string></span>http://yourserver:8080/jenkins/computer/parasite/slave-agent.jnlp<span class="nt"></string></span>
<span class="nt"></array></span>
<span class="nt"><key></span>RunAtLoad<span class="nt"></key></span>
<span class="nt"><true/></span>
<span class="nt"></dict></span>
<span class="nt"></plist></span>
</code></pre></div></div>
<p>The <code class="highlighter-rouge">/Shared/Users/Jenkins-Agent-A</code> is your agent’s home. You should have create one when setting up agent via server UI and <code class="highlighter-rouge">slave.jar</code> should be already located in this folder. Now if agent machine reboots and autologin is configured, the agent will go back online automatically. If the server reboots though, I’m not quite sure what happens, my assumption is that agent will stay alive and will keep trying to reconnect to server and finally they both happily reunite. I’m yet to test how exactly it works in reality.</p>
<p>To manually start and stop an agent use following commands (typealias if you need to use them often)</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Start.</span>
launchctl load ~/Library/LaunchAgents/org.jenkins-agent-a.plist
<span class="c"># Stop.</span>
launchctl unload ~/Library/LaunchAgents/org.jenkins-agent-a.plist
<span class="c"># list (by label)</span>
launchctl list org.jenkins-agent-a
</code></pre></div></div>
<p>One additional note. You can run a remote agent on localhost, which technically makes it not remote any more. This may be useful when for some reason Jenkins server is launched under non-login user session (Launch Daemon again) and you can’t use default master node to run unit tests.</p>
<p>That sums it up. To compare how things are in Bamboo universe <a href="/mobile%20ci/2015/02/01/bamboo-remote-agent">check out this post</a>.</p>
https://mgrebenets.github.io/mobile%20ci/2015/02/01/jenkins-remote-node
https://mgrebenets.github.io/mobile%20ci/2015/02/01/jenkins-remote-node2015-02-01T00:00:00+00:00Jenkins CI Server on Mac OS X
<p>A guide for setting up a Jenkins CI server on Mac OS X machine.</p>
<!--more-->
<p>So you want to have Continuous Integration for Mobile in your company and your final choice of CI server is Jenkins. If your company is big and you are lucky enough the Dev Support or Dev Ops team will do all the heavy-lifting and install it for you. But if it’s not the case you might’ve just landed on a page that has something to help you out.</p>
<h1 id="install">Install</h1>
<blockquote>
<p>A kind of warning first, avoid installing Jenkins as Launch Daemon. For detailed reasoning checkout out <a href="/mobile%20ci/2015/02/01/mobile-ci-daemon-vs-agent">this article</a>.</p>
</blockquote>
<p><a href="https://wiki.jenkins-ci.org/display/JENKINS/Installing+Jenkins">Jenkins Wiki</a> offers a list of options for Jenkins installation but doesn’t mention Mac OS X. It mentions <a href="https://www.docker.com/">Docker</a> though and I’ve heard nothing but good things about Docker. In this article I will stick with <a href="http://brew.sh/">Homebrew</a>.</p>
<p>You will need JDK to be <a href="/mobile%20ci/2015/02/15/install-java-on-mac-os-x">installed and configured on your Mac</a> before proceeding.</p>
<p>To install run a simple shell command.</p>
<script src="https://gist.github.com/d7fb72b9e326f20d65e3cefdfec73d3a.js"> </script>
<p>Jenkins will be installed to <code class="highlighter-rouge">usr/local</code> and Homebrew will actually tell you right away how to turn it into a Launch Agent.</p>
<script src="https://gist.github.com/4639671209d603804d295f9752e35122.js"> </script>
<p>This recommends you to symlink Jenkins launch agent plist file to <code class="highlighter-rouge">~/Library/LaunchAgents</code> but I would advise against it. As you will see next you will need to modify that file. That means if you ever upgrade Jenkins via Homebrew all your changes in plist will be lost. My recommendation is to copy it instead of making a symbolic link.</p>
<p>Even more, once installed via Homebrew I then delegate Jenkins upgrades to Jenkins itself. For this reason I pin Homebrew formula to prevent Homebrew from upgrading Jenkins files.</p>
<script src="https://gist.github.com/3b7d2ae7641b6db07a7fe0aae64eeed4.js"> </script>
<p>Now you also have manual control over Jenkins installation and can start/stop it from command line.</p>
<script src="https://gist.github.com/170152434d3789ab06c993c63c43233a.js"> </script>
<h1 id="configure">Configure</h1>
<p>To understand why you need to change plist try to run Jenkins server. Give it a go, create a couple of build projects that do some basics like checking out git repository and running simple build command. Very soon you should get an error message saying that Jenkins has ran out of memory. This seems to be a common issue with JVM and Mac OS X, <a href="/mobile%20ci/2015/02/01/bamboo-ci-server-on-osx">Bamboo installations run into same problems</a>. I’m not quite sure why default configuration doesn’t account for this, probably this is Mac specific and other operating systems are OK. Anyway, you need to modify default plist file for Launch Agent. Here’s what you need and might want to change.</p>
<h2 id="jvm-virtual-memory-and-garbage-collection">JVM Virtual Memory and Garbage Collection</h2>
<ul>
<li>Tell JVM to use a 64-bit data model if available (<code class="highlighter-rouge">-d64</code>).</li>
<li>Set minimum and maximum heap size with <code class="highlighter-rouge">-Xms</code> and <code class="highlighter-rouge">Xmx</code> flags. 512 Mb works for me most of the time.</li>
<li>Configure garbage collector, class unloading and permanent space.</li>
</ul>
<script src="https://gist.github.com/6a4b18f3452e7ab17d4a05b960fd4fcc.js"> </script>
<h2 id="http-proxy">HTTP Proxy</h2>
<p>By far the largest source of issues and frustration, company proxy. Specify it using <code class="highlighter-rouge">-D</code> option.</p>
<script src="https://gist.github.com/24bdf3afb723b8950e8ca5f98a045231.js"> </script>
<h2 id="port-and-prefix">Port and Prefix</h2>
<p>Run Jenkins on a custom port with custom prefix in url. This example uses default <code class="highlighter-rouge">8080</code> port and <code class="highlighter-rouge">/jenkins</code> prefix, so you can access your Jenkins dashboard like <code class="highlighter-rouge">http://yourhostname:8080/jenkins</code> or ever <code class="highlighter-rouge">http://youthostname/jenkins</code>. These arguments need to be passed to <code class="highlighter-rouge">jenkins.war</code> which was installed by Homebrew to <code class="highlighter-rouge">/usr/local/opt/jenkins/libexec</code>.</p>
<script src="https://gist.github.com/d50d1e3b2ba6118bfcdf8d5cca7fcee6.js"> </script>
<h2 id="run-at-load">Run at Load</h2>
<p>Enable Run at Load option to start server automatically if machine reboots.</p>
<script src="https://gist.github.com/9973d3a4f53397dbfd9f844cfdb7ec37.js"> </script>
<h2 id="environment-variables">Environment Variables</h2>
<p>If any of the commands in this plist need environment variables this is how you can define them.</p>
<script src="https://gist.github.com/a00c74ed35d5d4bc62b50f236ac6b354.js"> </script>
<h2 id="standard-output-and-error">Standard Output and Error</h2>
<p>It is up to you to redirect stdout and stderr. While sounds like a good idea for logging I would advise against redirecting stderr into a file. I once had to deal with 90 Gb log file created by Bamboo remote agent over a few months period.</p>
<script src="https://gist.github.com/c49ccb8896f0d031f4dfd6177a6fc894.js"> </script>
<p>Note that Jenkins put its files in <code class="highlighter-rouge">.jenkins</code> folder in your user’s home path. You also have to specify full paths when dealing with launch agent plists. Create <code class="highlighter-rouge">log</code> folder if it’s not there yet.</p>
<h2 id="other">Other</h2>
<p>By default Jenkins enables security protocol for email. I have also faced an issue with <a href="https://wiki.jenkins-ci.org/display/JENKINS/BitBucket+Plugin">Bitbucket Plugin</a> and had to set <code class="highlighter-rouge">preferIPv4Stack</code> flag as a workaround. These are all flags for <code class="highlighter-rouge">java</code> command.</p>
<script src="https://gist.github.com/a9a28e5a289c2ea39fa5be2ff63258cc.js"> </script>
<h2 id="full-config">Full Config</h2>
<p>Now put it all together.</p>
<script src="https://gist.github.com/56f774c72cf1d067eb3c7a0eb2ac1669.js"> </script>
<p>Now you have a reliable Jenkins server that runs 24/7 and performs stable CI tasks.</p>
<h1 id="tips">Tips</h1>
<p>To find out how exactly Jenkins was launched, grep active processes list.</p>
<script src="https://gist.github.com/6c84f352247b8bb079f1bd11f9ab3cc4.js"> </script>
<p>The output will tell you everything you need to know.</p>
<script src="https://gist.github.com/b3c46fbebc176a3ef612fd199e493d91.js"> </script>
<h1 id="other-ways">Other Ways</h1>
<h2 id="jenkins-runner">Jenkins Runner</h2>
<p>There are other ways to install and start Jenkins server, one of them is using <a href="https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+Runner">jenkins.sh</a> runner script. It is not bundled with Homebrew installation by default, you should download it manually as mentioned on the Jenkins Wiki page.</p>
<p>In this case all the configuration options are in <code class="highlighter-rouge">data/wrapper.conf</code> file, you can check <a href="https://github.com/mnadeem/JenkinsRunner/blob/master/conf/wrapper.conf">default file</a> and easily figure out where to add your custom options.</p>
<p>The runner shell script itself can be launched as Launch Agent or Launch Daemon. Overall this is just a higher level of configuration.</p>
<h2 id="legacy-runner">Legacy Runner</h2>
<p>Another approach I’ve seen is to use custom runner script. I am actually working with one right now but I suspect this is a legacy version of <code class="highlighter-rouge">jenkins.sh</code>.</p>
<p>The main difference is that all configuration is stored in Mac OS X defaults and then read by the script like this.</p>
<script src="https://gist.github.com/73b0fd09e0a03f6da110ed5c86a66961.js"> </script>
<p>Defaults are stored as plist and are read as a dictionary. An example output looks like this</p>
<script src="https://gist.github.com/d1e73d2bd021c05606a05795ef9c4788.js"> </script>
<p>Using <code class="highlighter-rouge">[sudo] defaults write</code> you can change Jenkins configuration.</p>
<p>Obviously this is less preferred way than using <code class="highlighter-rouge">wrapper.conf</code>. Using OS X defaults leads to configuration which is non-reusable on other operating systems and can’t be easily put in SCM if needed.</p>
<h1 id="summary">Summary</h1>
<p>A short summary - install with Homebrew, configure as Launch Agent. To configure Jenkins for Mobile CI tasks you can read other articles in this blog.</p>
<p>The configuration is far from being final. You will have to install plugins, configure SSH keys for git repositories and perform multitude of other administrative tasks to bring your Jenkins CI box up to speed.</p>
https://mgrebenets.github.io/mobile%20ci/2015/02/01/jenkins-ci-server-on-osx
https://mgrebenets.github.io/mobile%20ci/2015/02/01/jenkins-ci-server-on-osx2015-02-01T00:00:00+00:00Bamboo Remote Agent on Mac OS X
<p>A short guide for installing and configuring Bamboo Remote Agent on Mac OS X.</p>
<!--more-->
<p>The starting point for an agent is a server, you should either have it configured for you or <a href="/mobile%20ci/2015/02/01/bamboo-ci-server-on-osx">install yourself</a>.</p>
<p><a href="TODO:link">Atlassian documentation</a> is always a good place to start. Next important thing is to have <a href="/mobile%20ci/2015/02/15/install-java-on-mac-os-x">Java installed</a> on remote agent machine.</p>
<h1 id="configure-server">Configure Server</h1>
<p>You start by configuring server. Open Bamboo server dashboard in the browser and navigate to Bamboo Administration page (via Settings button in top right). Surely you have to be admin to get there.</p>
<p><img src="https://mgrebenets.github.io/assets/images/bamboo-settings.png" alt="Bamboo Settings" /></p>
<p>Now select Agents on the left and click “Enable remote agent support”.</p>
<p><img src="https://mgrebenets.github.io/assets/images/bamboo-enable-remote-agents.png" alt="Bamboo Enable Remote Agents" /></p>
<p>You can click “Install remote agent” now.</p>
<p><img src="https://mgrebenets.github.io/assets/images/bamboo-install-remote-agent.png" alt="Bamboo Install Remote Agent" /></p>
<h1 id="install-agent">Install Agent</h1>
<p>You are now looking at the page with further instructions. Just like <a href="/mobile%20ci/2015/02/01/jenkins-remote-node">Jenkins build agent</a> Bamboo Remote Agent is a Java JAR file that needs to be downloaded to a target agent machine and then ran there.</p>
<p><img src="https://mgrebenets.github.io/assets/images/bamboo-install-remote-agent-page.png" alt="Bamboo Install Remote Agent" /></p>
<p>Before you proceed you need to configure remote agent machine. Just like Bamboo server works well with a special user, remote agent will benefit from running under a designated user account. Create a Standard account from System Preferences, in this example we will name it <code class="highlighter-rouge">bambooagent</code> so this user’s home will be <code class="highlighter-rouge">/Users/bambooagent</code>. To make the whole process easier from now on I am assuming that you are currently logged in as bamboo-agent user.</p>
<p><img src="https://mgrebenets.github.io/assets/images/create-bamboo-agent-user.png" alt="Bamboo Create Bamboo Agent User" /></p>
<p>Just like <a href="/mobile%20ci/2015/02/01/jenkins-remote-node">Jenkins remote agent</a>, Bamboo remote agent needs an <em>installation</em> and <em>home</em> directories. So let’s create these two.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd</span> /Users/bambooagent
<span class="c"># Create installation directory.</span>
mkdir bamboo-agent
<span class="c"># Create home directory.</span>
mkdir bamboo-agent-home
</code></pre></div></div>
<p>Installation directory is where you need to put agent JAR file and then this JAR will download other required files and keep them in installation directory. Updates will occur in this directory as well.</p>
<p>Home directory is the location for all the build jobs metadata, intermediate build files, artifacts and so on.</p>
<p>Now it’s time to install, first get the JAR and put it into installation directory.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd</span> /Users/bambooagent/bamboo-agent
wget http://your-server-host:8085/agentServer/agentInstaller/atlassian-bamboo-agent-installer-5.7.2.jar
</code></pre></div></div>
<p>Or simply manually download it and put in the directory.</p>
<p>It is time to run the JAR and let Bamboo complete installation process.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>java <span class="nt">-Dbamboo</span>.home<span class="o">=</span>/Users/bambooagent/bamboo-agent-home <span class="se">\</span>
<span class="nt">-jar</span> atlassian-bamboo-agent-installer-5.7.2.jar http://your-server-host:8085/agentServer/
</code></pre></div></div>
<p><code class="highlighter-rouge">bamboo-agent-home</code> is the default name for Bamboo home directory, but it doesn’t hurt to be more explicit and specify it.</p>
<p>If you have to take proxy into account, add more <code class="highlighter-rouge">-D</code> options, for example</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">-Dhttp</span>.proxyHost<span class="o">=</span>mycompany.proxy.host
<span class="nt">-Dhttp</span>.proxyPort<span class="o">=</span>8080
<span class="nt">-Dbamboo</span>.agent.ignoreServerCertName<span class="o">=</span><span class="nb">true</span>
</code></pre></div></div>
<p>The last one is useful when dealing with self-signed certificates.</p>
<h1 id="fix-the-broker-urls">Fix the Broker URLs</h1>
<p>As usual, nothing just works right away, as if it was designed that way…</p>
<p>For example, if you just experiment on your development machine where Bamboo server is already up and you want to run agent on the very same hardware, you would naturally use <code class="highlighter-rouge">localhost</code> as host name.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Example for localhost.</span>
java <span class="nt">-jar</span> atlassian-bamboo-agent-installer-5.7.2.jar http://localhost:8085/agentServer/
<span class="c"># Output log.</span>
INFO | jvm 1 | 2015/02/19 08:51:49 | 2015-02-19 08:51:49,438 WARN <span class="o">[</span>Thread-0] <span class="o">[</span>BambooActiveMQConnectionFactory] Broker URI: tcp://10.5.50.2:54663?wireFormat.maxInactivityDuration<span class="o">=</span>300000 is invalid: java.net.ConnectException: Network is unreachable
</code></pre></div></div>
<p>OK, so it doesn’t work. Bamboo agent tries to hit so called Broker URI, which is pointing to the server, in this example it’s “tcp://<em>10.5.50.2</em>:<strong>54663</strong>?wireFormat.maxInactivityDuration=300000”.</p>
<p>Note the highlighted parts. First the fact that Broker URI uses an IP address (<em>10.5.50.2</em> in this example). Second and more important is the port number in Broker URI (<strong>54663</strong>). Basically this means “say hello to Firewall!” and I’ll get back to that later.</p>
<p>If you change <code class="highlighter-rouge">localhost</code> to <code class="highlighter-rouge">127.0.0.1</code> the results will be the same, that’s because Broker URI is part of Bamboo server configuration and has to be set manually.</p>
<blockquote>
<p>This is where I have to add a note that I’m trying this on the train with no internet connection, so basically my laptop is offline. I also have <code class="highlighter-rouge">HTTP_PROXY</code> environment variable set, so no wonder agent can’t resolve Broker URI with an IP address (even after I unset <code class="highlighter-rouge">HTTP_PROXY</code> variable).</p>
</blockquote>
<p>Anyway, let’s figure out what is that Broker URI and where it can be changed. For that open Bamboo server dashboard, navigate to Administration page and find “General configuration” menu on the left in “SYSTEM” category.</p>
<p><img src="https://mgrebenets.github.io/assets/images/bamboo-general-configuration.png" alt="Bamboo General Configuration" /></p>
<p>Here it is, the question remains how to set it correctly. Here are the rules I learned the hard way.</p>
<h2 id="local-server">Local Server</h2>
<p>This is the case when both the server and agent are on the same local area network. Have a look at <a href="https://answers.atlassian.com/questions/196438/bamboo-5-remote-agent-not-registering">this discussion</a> and <a href="https://answers.atlassian.com/questions/246687/unable-to-validate-jms-broker-client-uri-when-running-remote-bamboo-agent">this one too</a>.</p>
<p>Ultimately in LAN configuration you have to use your server’s hostname with <code class="highlighter-rouge">.local</code> suffix. To get the hostname run <code class="highlighter-rouge">hostname</code> on the server machine.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hostname
<span class="c"># Example output.</span>
R5003398.local
</code></pre></div></div>
<h2 id="remote-server">Remote Server</h2>
<p>In this setup your server is remote from the agent’s point of view. For example your company uses Bamboo OnDemand and hosts server and elastic agents in EC2 cloud. But Mac agent is not an option for the cloud, so you end up hosting it in-house, meaning it’s sitting behind company firewall.</p>
<p>Another thing learned the hard way is to configure Broker client URL using <em>IP address</em> and <em>not</em> the host name. Don’t ask me why, I don’t have an exact answer. Probably this is specific for Mac agents. Most likely I missed something important, but here I give you the solution that works. This means the Bamboo server IP address needs to be static, which isn’t usually a problem and is preferred configuration anyway.</p>
<h2 id="apply-changes">Apply Changes</h2>
<p>You can change Broker URI using Bamboo UI, but you can also configure it with text editor. Bamboo server keeps it’s configuration in home folder (<code class="highlighter-rouge">/Users/bamboo/bamboo-home</code> if you followed <a href="/mobile%20ci/2015/02/01/bamboo-ci-server-on-osx">this guide</a>). This is how properties look like.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><property</span> <span class="na">name=</span><span class="s">"bamboo.artifacts.directory"</span><span class="nt">></span>${bambooHome}/artifacts<span class="nt"></property></span>
<span class="nt"><property</span> <span class="na">name=</span><span class="s">"bamboo.config.directory"</span><span class="nt">></span>${bambooHome}/xml-data/configuration<span class="nt"></property></span>
<span class="nt"><property</span> <span class="na">name=</span><span class="s">"bamboo.jms.broker.client.uri"</span><span class="nt">></span>failover:(tcp://R5003398.local:54663?wireFormat.maxInactivityDuration=300000)?initialReconnectDelay=15000<span class="ni">&amp;</span>maxReconnectAttempts=10<span class="nt"></property></span>
<span class="nt"><property</span> <span class="na">name=</span><span class="s">"bamboo.jms.broker.uri"</span><span class="nt">></span>tcp://0.0.0.0:54663?wireFormat.maxInactivityDuration=300000<span class="nt"></property></span>
</code></pre></div></div>
<p>If you are making changes via UI you will see a message saying that you need to restart all remote agents. Guess what, that’s not true. You can give it a go and restart an agent and observe no changes in failover URI. The truth is that you have to restart the server for changes to take effect.</p>
<h2 id="try-it-out">Try It Out</h2>
<p>So in my example I change the Broker client URL to use local hostname.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>failover:(tcp://R5003398.local:54663?wireFormat.maxInactivityDuration=300000)?initialReconnectDelay=15000<span class="err">&</span>maxReconnectAttempts=10
</code></pre></div></div>
<p>Now I start an agent and this time it works.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>INFO | jvm 1 | 2015/02/19 10:56:57 | 2015-02-19 10:56:57,794 INFO <span class="o">[</span>Thread-0] <span class="o">[</span>RemoteAgent] <span class="k">*</span> Bamboo agent <span class="s1">'172.28.82.121'</span> ready to receive builds.
INFO | jvm 1 | 2015/02/19 10:56:57 | 2015-02-19 10:56:57,794 INFO <span class="o">[</span>Thread-0] <span class="o">[</span>RemoteAgent] <span class="k">*</span> Remote Agent Home: /Users/bambooagent/bamboo-agent-home
INFO | jvm 1 | 2015/02/19 10:56:57 | 2015-02-19 10:56:57,794 INFO <span class="o">[</span>Thread-0] <span class="o">[</span>RemoteAgent] <span class="k">*</span> Broker URL: failover:<span class="o">(</span>tcp://R5003398.local:54663?wireFormat.maxInactivityDuration<span class="o">=</span>300000<span class="o">)</span>?initialReconnectDelay<span class="o">=</span>15000&maxReconnectAttempts<span class="o">=</span>10
</code></pre></div></div>
<p>If I navigate to Bamboo server Agents page, I can see remote agent being online and ready to pick up builds.</p>
<p><img src="https://mgrebenets.github.io/assets/images/bamboo-remote-agent-online.png" alt="Bamboo Remote Agent Online" /></p>
<h1 id="launch-agent">Launch Agent</h1>
<p>Next step is to make sure that remote agent starts automatically in case Mac box restarts. Start by enabling autologin for <code class="highlighter-rouge">babmooagent</code> user, this way system will login into the user’s account and fire up all of its launch agents.</p>
<p>To make the best use of Bamboo remote agent, it should be started as a launch agent, see <a href="/mobile%20ci/2015/02/01/mobile-ci-daemon-vs-agent">Launch Daemon vs Agent</a> for more details.</p>
<p>Create <code class="highlighter-rouge">com.atlassian.bamboo-agent.plist</code> in <code class="highlighter-rouge">/Users/bambooagent/Library/LaunchAgents</code>. This is an example file.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><?xml version="1.0" encoding="UTF-8"?></span>
<span class="cp"><!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"></span>
<span class="nt"><plist</span> <span class="na">version=</span><span class="s">"1.0"</span><span class="nt">></span>
<span class="nt"><dict></span>
<span class="nt"><key></span>Label<span class="nt"></key></span>
<span class="nt"><string></span>com.atlassian.bamboo-agent<span class="nt"></string></span>
<span class="nt"><key></span>ProgramArguments<span class="nt"></key></span>
<span class="nt"><array></span>
<span class="nt"><string></span>/Users/bambooagent/bamboo-agent-home/bin/bamboo-agent.sh<span class="nt"></string></span>
<span class="nt"><string></span>console<span class="nt"></string></span>
<span class="nt"></array></span>
<span class="nt"><key></span>RunAtLoad<span class="nt"></key></span>
<span class="nt"><true/></span>
<span class="nt"><key></span>ServiceDescription<span class="nt"></key></span>
<span class="nt"><string></span>Atlassian Bamboo Mac OS X Build Agent<span class="nt"></string></span>
<span class="nt"><key></span>StandardErrorPath<span class="nt"></key></span>
<span class="nt"><string></span>/Users/bambooagent/bamboo-agent-home/logs/bamboo-agent.err<span class="nt"></string></span>
<span class="c"><!--
<key>StandardOutPath</key>
<string>/Users/bambooagent/bamboo-agent-home/logs/bamboo-agent.out</string>
--></span>
<span class="nt"><key></span>KeepAlive<span class="nt"></key></span>
<span class="nt"><true/></span>
<span class="nt"><key></span>UserName<span class="nt"></key></span>
<span class="nt"><string></span>bambooagent<span class="nt"></string></span>
<span class="nt"></dict></span>
<span class="nt"></plist></span>
</code></pre></div></div>
<p>As you can see it’s all standard stuff. Specify a label (<code class="highlighter-rouge">Label</code>), run agent at load (<code class="highlighter-rouge">RunAtLoad</code>), keep it alive and run the session as <code class="highlighter-rouge">bambooagent</code> user. There’s a detailed description provided and error output redirected into a file. You can see that I’m reluctant to save standard output to a file, that’s because the size of this file can become really big over time. Note that this is standard error and output for the agent runner, it may not necessary contain actual agent logs.</p>
<p>Finally, to start the agent a <code class="highlighter-rouge">bamboo-agent.sh</code> runner script is used from Bamboo agent home directory.</p>
<p>A usual practice is to have type aliases in your favorite shell to start and stop the agent from command line if needed. In this example I’m using launch agent label to control it. The same can be done by using <code class="highlighter-rouge">launchctl [load|unload] plist-file</code>.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">alias </span>start-bamboo-agent<span class="o">=</span><span class="s2">"launchctl start com.atlassian.bamboo-agent"</span>
<span class="nb">alias </span>stop-bamboo-agent<span class="o">=</span><span class="s2">"launchctl stop com.atlassian.bamboo-agent"</span>
<span class="nb">alias </span>restart-bamboo-agent<span class="o">=</span><span class="s2">"stop-bamboo-agent & start-bamboo-agent"</span>
</code></pre></div></div>
<p>You may have noticed that there are no arguments for proxy, Java home and other settings. That’s because all these settings can be set in <code class="highlighter-rouge">/Users/bambooagent/bamboo-agent-home/conf/wrapper.conf</code>.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">#</span> <span class="n">The</span> <span class="n">Bamboo</span> <span class="n">Agent</span> <span class="n">home</span> <span class="n">configuration</span> <span class="n">file</span>
<span class="n">wrapper</span><span class="o">.</span><span class="na">java</span><span class="o">.</span><span class="na">additional</span><span class="o">.</span><span class="mi">1</span><span class="o">=-</span><span class="n">Dbamboo</span><span class="o">.</span><span class="na">home</span><span class="o">=/</span><span class="n">Users</span><span class="o">/</span><span class="n">bambooagent</span><span class="o">/</span><span class="n">bamboo</span><span class="o">-</span><span class="n">agent</span><span class="o">-</span><span class="n">home</span>
<span class="n">wrapper</span><span class="o">.</span><span class="na">java</span><span class="o">.</span><span class="na">additional</span><span class="o">.</span><span class="mi">2</span><span class="o">=-</span><span class="n">Dbamboo</span><span class="o">.</span><span class="na">agent</span><span class="o">.</span><span class="na">ignoreServerCertName</span><span class="o">=</span><span class="kc">false</span>
<span class="err">#</span><span class="n">wrapper</span><span class="o">.</span><span class="na">java</span><span class="o">.</span><span class="na">additional</span><span class="o">.</span><span class="mi">3</span><span class="o">=-</span><span class="nl">agentlib:</span><span class="n">yjpagent</span>
<span class="err">#</span> <span class="n">Application</span> <span class="n">parameters</span><span class="o">.</span> <span class="n">Add</span> <span class="n">parameters</span> <span class="n">as</span> <span class="n">needed</span> <span class="n">starting</span> <span class="n">from</span> <span class="mi">1</span>
<span class="n">wrapper</span><span class="o">.</span><span class="na">app</span><span class="o">.</span><span class="na">parameter</span><span class="o">.</span><span class="mi">1</span><span class="o">=</span><span class="n">com</span><span class="o">.</span><span class="na">atlassian</span><span class="o">.</span><span class="na">bamboo</span><span class="o">.</span><span class="na">agent</span><span class="o">.</span><span class="na">bootstrap</span><span class="o">.</span><span class="na">AgentBootstrap</span>
<span class="n">wrapper</span><span class="o">.</span><span class="na">app</span><span class="o">.</span><span class="na">parameter</span><span class="o">.</span><span class="mi">2</span><span class="o">=</span><span class="nl">http:</span><span class="c1">//localhost:8085/agentServer/</span>
</code></pre></div></div>
<p>In this example you can see how Bamboo agent home directory is set, as well as other settings including server URL (in this case it runs on localhost). To add proxy put more additional Java arguments</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">#</span> <span class="n">The</span> <span class="n">Bamboo</span> <span class="n">Agent</span> <span class="n">home</span> <span class="n">configuration</span> <span class="n">file</span>
<span class="n">wrapper</span><span class="o">.</span><span class="na">java</span><span class="o">.</span><span class="na">additional</span><span class="o">.</span><span class="mi">1</span><span class="o">=-</span><span class="n">Dbamboo</span><span class="o">.</span><span class="na">home</span><span class="o">=/</span><span class="n">Users</span><span class="o">/</span><span class="n">bambooagent</span><span class="o">/</span><span class="n">bamboo</span><span class="o">-</span><span class="n">agent</span><span class="o">-</span><span class="n">home</span>
<span class="n">wrapper</span><span class="o">.</span><span class="na">java</span><span class="o">.</span><span class="na">additional</span><span class="o">.</span><span class="mi">2</span><span class="o">=-</span><span class="n">Dbamboo</span><span class="o">.</span><span class="na">agent</span><span class="o">.</span><span class="na">ignoreServerCertName</span><span class="o">=</span><span class="kc">false</span>
<span class="n">wrapper</span><span class="o">.</span><span class="na">java</span><span class="o">.</span><span class="na">additional</span><span class="o">.</span><span class="mi">3</span><span class="o">=-</span><span class="n">Dhttp</span><span class="o">.</span><span class="na">proxyHost</span><span class="o">=</span><span class="n">mycompany</span><span class="o">.</span><span class="na">proxy</span><span class="o">.</span><span class="na">com</span><span class="o">.</span><span class="na">au</span>
<span class="n">wrapper</span><span class="o">.</span><span class="na">java</span><span class="o">.</span><span class="na">additional</span><span class="o">.</span><span class="mi">4</span><span class="o">=-</span><span class="n">Dhttp</span><span class="o">.</span><span class="na">proxyPort</span><span class="o">=</span><span class="mi">8080</span>
<span class="err">#</span> <span class="n">and</span> <span class="n">so</span> <span class="n">on</span><span class="o">...</span>
</code></pre></div></div>
<p>Using <code class="highlighter-rouge">wrapper.conf</code> is preferred over jamming these arguments in launch agent plist.</p>
<h1 id="firewall">Firewall</h1>
<p>If you agent sits in corporate network and server is in the outer world (e.g. EC2 cloud), you will face some nasty firewall issues. Have a look at official <a href="https://confluence.atlassian.com/display/BAMBOO021/Running+Bamboo+behind+a+firewall+with+Remote+Agents+outside+the+firewall">Atlassian documentation</a>. Ports number <strong>8085</strong> and <strong>54663</strong> (unless you specified different numbers) are used for bi-directional communication between agent and the server. Best practice is to open these ports in both directions. While lower port numbers are usually open, ports like 54663 need an exclusion rules configured in your company firewall. From experience this task can be either hard or impossible. Did you ever have that feeling that Network team is an extra layer or red tape and are there not to help you but to do the opposite? Welcome to the club then :).</p>
<p>To answer your question why Mac agent cannot be in the Cloud as well, see bits of my rant in <a href="/mobile%20ci/2015/01/29/bamboo-vs-jenkins">Bamboo vs Jenkins</a> and <a href="https://answers.atlassian.com/questions/22655/bamboo-mac-agent">this discussion</a>.</p>
<h1 id="summary">Summary</h1>
<p>From this moment on you need to configure your remote agent’s Mac to be able to run Xcode builds and tests, as well as other CI tasks.</p>
<p>This is <em>one of</em> the ways to configure and run Bamboo remote agent.</p>
<p>If you are into <a href="https://www.docker.com/">Docker</a>, check out <a href="https://registry.hub.docker.com/u/atlassian/bamboo-java-agent/">this link</a>. I’m only planning to give a try to this apparently awesome tool.</p>
https://mgrebenets.github.io/mobile%20ci/2015/02/01/bamboo-remote-agent
https://mgrebenets.github.io/mobile%20ci/2015/02/01/bamboo-remote-agent2015-02-01T00:00:00+00:00Bamboo Group Agent
<p>Bamboo Group Agent plugin for Mac agents.</p>
<!--more-->
<p><a href="https://marketplace.atlassian.com/plugins/com.edwardawebb.bamboo-group-agent">Bamboo Group Agent</a> is a free plugin for Atlassian’s Bamboo CI server. Like most plugins Bamboo Group Agent plugin is designed to solve a particular problem.</p>
<h1 id="problem">Problem</h1>
<p>Consider a distributed CI setup, for example <a href="https://confluence.atlassian.com/display/Cloud/Bamboo+Cloud">Bamboo Cloud</a>. The server runs in EC2 Amazon together with a number of <a href="https://confluence.atlassian.com/display/BAMBOO/About+Elastic+Bamboo">Elastic Agents</a>. Your goal is to add <a href="/mobile%20ci/2015/02/01/bamboo-remote-agent">Mac remote build agents</a> to this CI setup.</p>
<p>First of all, there’s no way to have a virtual Mac agent in the cloud, not with Amazon at least. You either have to choose one of the Mac colocation providers or have a self-hosted Mac box for an agent. This is only half of the problem though. The other half is the way CI is usually configured.</p>
<p>Due to the nature of CI server and elastic agents setup, all elastic agents are usually identical clones of each other. With a few clicks of a mouse you can go from 1 to 25 agents, all of them initializing from the same image and having same specs from the start. As part of agents initialization, tools and software packages are installed as well, e.g. Git, RVM, npm, and so on. Those are normally called <em>capabilities</em> in Bamboo terms. The purpose of capabilities is to have more granular control over build jobs. The job specifies capability it needs to run, agents declare capabilities they have, and then Bamboo matches jobs to agents. The real issue is that such a powerful mechanism is usually <strong>not</strong> used. Since all the agents are identical, developers create their build plans with that in mind and thus they specify <strong>no capabilities</strong> in their build plans, because all the agents are capable of running their build jobs. This means the jobs can start on <strong>any</strong> agent.</p>
<p>This setup works until the moment you need to have a special agent with special capabilities, e.g. Mac agent with <code class="highlighter-rouge">xcodebuild</code> capability. You will usually have just one of those and it will be a very valuable resource used to build all the iOS projects in your team or even company. As you might have guessed, as soon as you add Mac agent to the agents pool <em>all</em> the other plans will start jumping on this agent and bear in mind that there are dozens if not hundreds of those plans. That’s the drawback of ignoring capabilities.</p>
<p>The problem is identified, so what’s with the solution? Going though the agents and declaring capabilities will not help, because all the plans need to specify capabilities as well.</p>
<h1 id="fix-the-plans">Fix The Plans</h1>
<p>Fixing the plans by specifying capabilities is the right solution. Unfortunately it is often a hard solution. Depending on your company you may have dozens if not hundreds of build plans, created by different developers in different periods of time. It’s a hell of a task just to track responsible people if you ever find anyone. Then you’d have to explain why it is important to specify capabilities and so on. It may take months before changes are applied and you don’t have months, you need Mac agents up and running right now.</p>
<p>This leads you to using a workaround which is…</p>
<h1 id="bamboo-group-agent">Bamboo Group Agent</h1>
<p>Allow me some copy-paste here.</p>
<blockquote>
<p>Marking an agent as a “Group Agent” will prevent any Build Plans from using it, regardless of capabilities. Plans must request agent specifically.</p>
</blockquote>
<p>Let’s see how this applies to our Mac agent. Start by installing Group Agent plugin from Marketplace. You will have to restart Bamboo server to apply changes.</p>
<h2 id="configure-group-agent">Configure Group Agent</h2>
<p>Next you need to configure the agent. In this example I will use remote agent running on the same machine. Navigate to Bamboo Administration, then select Agents and select remote agent from the list.</p>
<p><img src="https://mgrebenets.github.io/assets/images/bamboo-configure-group-agent-list-agents.png" alt="Select Remote Agent" /></p>
<p>Then click “Add capability”.</p>
<p><img src="https://mgrebenets.github.io/assets/images/bamboo-group-agent-add-capability.png" alt="Select Add Capability" /></p>
<p>Select “Group Agent” capability from drop-down list. Ignore “Allow Deployments” option for now, I will give more details on it later. Now you can click “Add”.</p>
<p><img src="https://mgrebenets.github.io/assets/images/bamboo-select-group-agent-capability.png" alt="Select Group Agent Capability" /></p>
<p>To verify results, find Group Agent capability in the list and click “Edit” (this option will give you a bit more info than just “View”).</p>
<p><img src="https://mgrebenets.github.io/assets/images/bamboo-group-agent-duty.png" alt="Group Agent Duty" /></p>
<p><img src="https://mgrebenets.github.io/assets/images/babmoo-edit-group-agent-capability.png" alt="Edit Group Agent Capability" /></p>
<p>Everything looks fine except for one thing, the agent name. Right now it’s the IP address, which makes it a bit tedious to remember and use in settings. It’s a good time to change this now. Click on the agent name link, then click “Edit details” button.</p>
<p><img src="https://mgrebenets.github.io/assets/images/bamboo-rename-remote-agent.png" alt="Rename Agent" /></p>
<h2 id="use-group-agent">Use Group Agent</h2>
<p>Now create or select a build plan you want to assign to the Group Agent. Then select <code class="highlighter-rouge">Actions > Configure plan</code>.</p>
<p><img src="https://mgrebenets.github.io/assets/images/bamboo-actions-configure-plan.png" alt="Configure Plan" /></p>
<p>Next select “Miscellaneous” tab and tick “This plan requires a Group Agent” checkbox.</p>
<p><img src="https://mgrebenets.github.io/assets/images/bamboo-specify-group-agent.png" alt="Specify Group Agent" /></p>
<p>Note, that you are using agent name here and you can specify more than one agent, by providing a comma separated list of agent names, for example “Mac Agent 1, Mac Agent 2, Mac Agent 3”.</p>
<p>That’s it, this plan will now run <em>only</em> on <em>Mac Agent 1</em> and <strong>no other plans</strong> will run on this agent or any group agents you configure in the future.</p>
<h1 id="drawbacks">Drawbacks</h1>
<p>The benefit of using Bamboo Group Agent is that it solves original problem described in this article. However, this approach has a number of drawbacks you need to know about.</p>
<h2 id="lock-entire-plan">Lock Entire Plan</h2>
<p>First drawback is that by using Group Agent you lock the <em>entire</em> plan to be executed on certain group of agents only. <em>Entire</em> means the plan and all of its jobs will run on a single agent at a time, that means jobs can’t run in parallel and you can’t take advantage of this awesome feature. Another issue is that your typical iOS build plan will have only few jobs that actually need Mac OS X (<code class="highlighter-rouge">xcodebuild</code>), the rest will be tasks to upload builds for distribution, to generate reports, to update issue trackers and so on. Ideally all those tasks could be ran on other agents thus freeing up Mac agent for next <code class="highlighter-rouge">xcodebuild</code> job, but that’s something that can’t be done with Group Agent.</p>
<p>The reason for this is not plugin developer’s fault. Actual reason is the lack of flexibility of APIs provided by Atlassian in their plugin development SDK. Group Agent uses <a href="https://docs.atlassian.com/atlassian-bamboo/latest/com/atlassian/bamboo/v2/build/agent/BuildAgentRequirementFilter.html">BuildAgentRequirementFilter</a> class which allows to filter list of Bamboo agents capable of running the plan. There’s no API to apply similar filter for Build Jobs at the moment.</p>
<h2 id="deployment-projects">Deployment Projects</h2>
<p>Another drawback is related to <a href="https://confluence.atlassian.com/display/BAMBOO/Deployment+projects">Deployment Projects</a>. By enabling Group Agent for remote or local agent you exclude it from the pool of agents that can run Deployment Projects. I bet you’ve just recalled that “Allow Deployments” checkbox I have recommended to leave unchecked. Well this option does exactly what it says, but it opens up the group agent for <strong>all</strong> deployment projects. Once again you will have dozens of unwanted deployment projects starting on a group agent, most of those will fail since Mac agent does not necessarily have all the required capabilities to deploy.</p>
<p>Why would you need a Mac deployment agent? - you’d ask. Well, there’s quite a few deployment tasks that can be done on Mac OS X only. One example - uploading app binaries to iTunes Connect. For that you can use <a href="https://wmiphone.files.wordpress.com/2013/07/itunes_store_transporter_quick_start_guide_v2.pdf">iTMSTransporter</a> or an amazing <a href="https://github.com/KrauseFx/deliver">deliver</a> utility.</p>
<p>One of the solutions for this problem is to have a <a href="https://confluence.atlassian.com/display/BAMBOO/Agents+for+deployment+environments">dedicated deployment agent</a>. This is part of Bamboo’s “out of the box” functionality. While configuring deployment projects you can assign agents to run those deployment projects. Deployment agents automatically become excluded from build agents pool though. You can use this solution if you have a spare Mac box to do just that. Given the iTunes Connect deployments are usually rare (unless you upload to new TestFlight very often), this may result in a valuable resource being idle most of the time.</p>
<p>Another solution would be to support group agent feature for deployment projects. Since deployment project is always linked to a build plan, it would be nice for deployment project to inherit group agent settings from it’s “parent” plan. As a matter of fact, there’s an already merged <a href="https://bitbucket.org/eddiewebb/bamboo-group-agent/pull-request/1/advanced-support-for-deployment-projects/diff">pull request</a> addressing this issue, though the changes didn’t make it into release yet.</p>
<h1 id="summary">Summary</h1>
<p>If you have a good opportunity then do your best to promote proper use of capabilities in your CI setup. Otherwise give Bamboo Group Agent a shot.</p>
https://mgrebenets.github.io/mobile%20ci/2015/02/01/bamboo-group-agent
https://mgrebenets.github.io/mobile%20ci/2015/02/01/bamboo-group-agent2015-02-01T00:00:00+00:00Bamboo CI Server on Mac OS X
<p>This article covers the details of installing a <a href="https://www.atlassian.com/software/bamboo">Bamboo</a> CI Server on Mac OS X.</p>
<!--more-->
<h1 id="install">Install</h1>
<p>The preferred way to install Bamboo is using official <a href="https://www.atlassian.com/software/bamboo/download?os=mac">Mac OS X installer</a>. Starting point for documentation is <a href="https://confluence.atlassian.com/display/BAMBOO/Installing+Bamboo+on+Mac+OS+X">official install guide</a>. Follow installer steps using default values.</p>
<blockquote>
<p>This article assumes you are dealing with Bamboo version 5.2 and above. All examples are for version 5.7.2.</p>
</blockquote>
<p>To download tar-ball using command line run this command</p>
<script src="https://gist.github.com/f04d73c9aebd8411dec2d54a087857b4.js"> </script>
<p>Bamboo needs Java to be <a href="/mobile%20ci/2015/02/15/install-java-on-mac-os-x">installed</a>, recommended versions are 1.6 or 1.7, I would advise to go with 1.7.</p>
<p>Make a new home for Bamboo. It could be <code class="highlighter-rouge">/Applications/Bamboo</code> or <code class="highlighter-rouge">~/bamboo/bamboo-home</code> or whatever you want. For this post I’ll stick with second option. It is often recommended to create a special <code class="highlighter-rouge">bamboo</code> user and put all things in their home directory. To create a new user use System Preferences and create Standard user.</p>
<script src="https://gist.github.com/fdf193c3b67abf0fd2670b78ecc255f9.js"> </script>
<p>Note that I switch user (<code class="highlighter-rouge">su</code>) to work with Bamboo user’s files and folders. This way I stay away from possible permissions conflicts. You could login as bamboo user instead. In any case, the rest of the article <strong>assumes you are operating as bamboo user</strong>.</p>
<p>Once downloaded unzip the tar-ball and copy <code class="highlighter-rouge">atlassian-bamboo-5.7.2</code> to bamboo user’s home folder. Rename it to just <code class="highlighter-rouge">bamboo</code> to make it version agnostic.</p>
<p>Then go inside that folder. This is referred as <em>installation directory</em> and this is where you will install and run Bamboo from. Edit the file in <code class="highlighter-rouge">atlassian-bamboo/WEB-INF/classes/bamboo-init.properties</code>. Uncomment the line with <code class="highlighter-rouge">bamboo.home</code> and put the following.</p>
<script src="https://gist.github.com/16fb6751fe5d1cd0e41ec72cb223facb.js"> </script>
<p>This is where Bamboo will put all the customizations and build plan details.</p>
<p>Now you should run <code class="highlighter-rouge">bin/start-bamboo.sh</code>.</p>
<script src="https://gist.github.com/1081eda39ae7739873ae42625c5c739d.js"> </script>
<p>Bamboo is now running on <a href="http://localhost:8085/">http://localhost:8085/</a>.</p>
<h1 id="configure">Configure</h1>
<p>Next step is to configure Bamboo, heres <a href="https://confluence.atlassian.com/display/BAMBOO/Running+the+Setup+Wizard">official documentation</a>. Recommended way is to use Setup Wizard which presents itself when you open <a href="http://localhost:8085/">http://localhost:8085/</a> in the browser.</p>
<p>Start by getting a license. You can always get a 30 days free evaluation license from Atlassian.</p>
<p>Next select Custom Installation option. Have a look at Base URL, make sure the IP address is correct. Also this is a good moment to pause and double check that your future Bamboo server has a static IP address allocated. This will become really important when dealing with remote agents. Leave the rest unchanged and click Continue.</p>
<p>Select Embedded database option. It is recommended to use other DB setup for production system. I might refine the article later to include setup details for PostgreSQL database.</p>
<p>Next, choose to create a new Bamboo home, configure your username. Give it some time and you will be able to create your first build plan.</p>
<h1 id="launch-agent">Launch Agent</h1>
<p>Now it’s time to make sure Bamboo start automatically when build box restarts. As mentioned in <a href="/mobile%20ci/2015/02/01/mobile-ci-daemon-vs-agent">this article</a> recommended way is to use Launch Agent. Start by enabling automatic login for bamboo user in System Preferences.</p>
<p>Next create <code class="highlighter-rouge">com.atlassian.bamboo.plist</code> in <code class="highlighter-rouge">/Users/bamboo/Library/LaunchAgents</code>.</p>
<script src="https://gist.github.com/8747a688835383c750cc80401aacd6fc.js"> </script>
<p>Make sure you create few aliases to start and stop Bamboo server from command line.</p>
<script src="https://gist.github.com/00bcbc2a74b52ed1f7ead7a8b1ec3a97.js"> </script>
<h1 id="troubleshooting">Troubleshooting</h1>
<p>This section provides an example of issues you may run into while trying to fire up Bamboo.</p>
<p>For example, you start Bamboo and see this instead of dashboard.</p>
<p><img src="https://mgrebenets.github.io/assets/images/bamboo-bootstrap-failed.png" alt="Bamboo Bootstrap Failed" /></p>
<p>To find out the reason look into Bamboo logs, specifically in <code class="highlighter-rouge">/Users/bamboo/bamboo/logs/catalina.out</code>.</p>
<script src="https://gist.github.com/76ccf24592410f3915eca77337e87c5c.js"> </script>
<p>OK, so database is presumably locked by another process. In my case it meant there was another Bamboo running already. Double check it then by running <code class="highlighter-rouge">ps</code>.</p>
<script src="https://gist.github.com/fdab9eae1f635ad3d997fc5ca61f6635.js"> </script>
<p>Indeed it is. I have another terminal tab open running bamboo user session and Bamboo server.</p>
<p>After I stop or kill all the instances I run it again and this time it works.</p>
<p>This is just one example of troubles, all of them will pretty much present themselves via the same starting error page. Another common case is database upgrade, you can run into this issue if using PostgreSQL and upgrade it via Homebrew, so it’s recommended to pin PostgreSQL instead.</p>
<h1 id="summary">Summary</h1>
<p>This will get you going with basic Bamboo CI server. There’s a number of additional administrative tasks yet to be done. Like configuring user access, integration with other Atlassian products, network configuration, plugins, capabilities and much more. I wouldn’t envy anyone who would have to deal with all those tasks. Companies that take CI seriously normally have Dev Support team keeping whole infrastructure running, not just Bamboo.</p>
https://mgrebenets.github.io/mobile%20ci/2015/02/01/bamboo-ci-server-on-osx
https://mgrebenets.github.io/mobile%20ci/2015/02/01/bamboo-ci-server-on-osx2015-02-01T00:00:00+00:00Bamboo vs Jenkins
<p>A <em>biased and subjective</em> (and by now a bit outdated) comparison of Bamboo and Jenkins as CI servers for mobile development, based on practical experience with both.</p>
<!--more-->
<p>Continuous Integration and Continuous Deployment (Delivery, Distribution) has been around for quite a while. But surprisingly enough on a global scale it pretty much just got into its teen years in regards to mobile development. Well, subjectively, of course.</p>
<p>You can see all levels of mobile CI these days. Some would still install builds from Xcode, others would have a quickly patched up build server under their desk. Xcode Bots meet the needs of yet another group of people. Travis CI is good and for open source projects it’s probably the best option. And guess what, I know few <strong>successful</strong> iOS development companies that develop apps for <em>enterprise</em> clients, and have <strong>no CI</strong> at all.</p>
<p>The advanced level of CI would include distributed build systems with multiple build nodes, support for automated unit and UI tests, running tests on simulator and physical devices, automatic deployment to TestFlight, Hockey App, Over the Air, and much more. It becomes not just mobile development, but spans into areas like DevOps and others. <a href="https://codeascraft.com/2014/02/28/etsys-journey-to-continuous-integration-for-mobile-apps/">Etsy’s blog post</a> is somewhat outdated but still a very good example of where this path can take you.</p>
<p>If you decide to take mobile CI under your total control, you have to pick a build server to start with.</p>
<p>I personally have worked with Bamboo for 1.5 years and I’m dealing with Jenkins right now, so I have few insights and can give some comparison of the two.</p>
<h1 id="setup--configuration">Setup & Configuration</h1>
<p><a href="/mobile%20ci/2015/02/01/bamboo-ci-server-on-osx">Bamboo installation</a> and <a href="/mobile%20ci/2015/02/01/jenkins-ci-server-on-osx">Jenkins installation</a> tasks are about the same in terms of time and knowledge required. While installing one of the two you’ll climb a certain learning curve which will help you heaps if you ever have to deal with second option.</p>
<p>Both are built using Java. Being Java applications, both will require similar JVM configuration. Default configuration won’t really serve you well. You’ll experience out of memory issues as soon as you add a couple of basic build plans/projects.</p>
<p>And lot of other things are similar: configuration behind proxy, login vs non-login user (<a href="/mobile%20ci/2015/02/01/mobile-ci-daemon-vs-agent">Launch Agent vs Daemon</a>), OS X Keychain, iOS Simulator, etc.</p>
<h1 id="gui">GUI</h1>
<p>Obviously, this is not a comparison criteria at all. This criteria is as subjective as it could possibly be!</p>
<p>Out of the box Bamboo UI looks much better than Jenkins version.</p>
<p>With Jenkins there are ways to improve your day to day user experience. You can customize theme and even make your custom UI improvements, like adding “Build Now” button where you like it.</p>
<p>You should start by installing <a href="https://wiki.jenkins-ci.org/display/JENKINS/Simple+Theme+Plugin">Simple Theme Plugin</a> and then configure it with one of the available themes. Not all the themes will look good, it all depends on the Jenkins version you have and browser you use, etc. I tried a bunch of them and ironically enough the only theme that looks good on our production CI box is called <a href="https://github.com/djonsson/jenkins-atlassian-theme">“Atlassian”</a>. But I’m dealing with slightly outdated Jenkins version, you could get better results with up to date Jenkins.</p>
<p>There’s multitude of <a href="https://wiki.jenkins-ci.org/display/JENKINS/Plugins">UI, List View and Page Decorator plugins</a> available for Jenkins. Some of them must be good and help you customize you Jenkins look & feel and functionality.</p>
<h1 id="plugins">Plugins</h1>
<p>This is where the large community plays its role. Subjectively or not, Jenkins has a larger choice of plugins of all kinds, starting from management and organization of build jobs and ending up with reporting.</p>
<p>Via a fancy pie chart diagram we are told that Bamboo has <strong>151</strong> plugins on <a href="https://marketplace.atlassian.com/home/jira">Atlassian Marketplace</a>.</p>
<p><img src="https://mgrebenets.github.io/assets/images/atlassian-marketplace-plugins.png" alt="Plugins Pie Chart" /></p>
<p>A quick check on <a href="https://wiki.jenkins-ci.org/display/JENKINS/Plugins?showChildren=true#children">Jenkins Wiki</a> and we get a count of <strong>1,071</strong> plugins.</p>
<p>Reporting is one of the most important plugin categories in my opinion. For example, I prefer to have full control over Xcode build tasks and use <a href="/mobile%20ci/2015/02/08/mobile-ci-makefiles">makefiles</a> combined with shell commands wrapping <code class="highlighter-rouge">xcodebuild</code> rather than use Xcode plugin. Part of the reason is to be able to migrate to another build server with less effort and to be able to run CI tasks on my development laptop. Same goes for other things like uploading to / downloading from S3 bucket, transferring files with <code class="highlighter-rouge">rsync</code> or <code class="highlighter-rouge">scp</code>, and so on. But in no way I can come up with scripts that will produce good looking reports including HTML formatting, diagrams and images, plus integration into Bamboo or Jenkins UI. For this task I prefer to use plugins.</p>
<p>Jenkins features <strong>127</strong> plugins just for reporting, that’s almost as much as Bamboo can offer in total. Of course, quality of all those plugins deserves a detailed research. Just numbers don’t tell much. But this post <em>is</em> based on some hands on experience, so I’ll compare some reporting plugins I have used over time.</p>
<h2 id="publish-html">Publish HTML</h2>
<p>If you ever used <a href="/mobile%20ci/2015/02/08/clang-static-analyzer">Clang Static Analyzer</a> for your iOS projects, you know then that there’s no proper reporting plugin for this task. You end up with HTML report that needs to be published and made available in build project/plan summary page.</p>
<p>With Bamboo you create a new <a href="https://confluence.atlassian.com/display/BAMBOO/Sharing+artifacts">Shared Artifact</a>, with Jenkins you use <a href="https://wiki.jenkins-ci.org/display/JENKINS/HTML+Publisher+Plugin">HTML Publisher plugin</a>.</p>
<h2 id="unit-tests">Unit Tests</h2>
<p>Of course you run unit tests as part of your CI, don’t you? In that case you are well covered by reporting plugin on both Bamboo and Jenkins. Jenkins plugin also includes trending graphs, which is nice.</p>
<h2 id="cobertura-code-coverage">Cobertura Code Coverage</h2>
<p>Of course you don’t just run unit tests, but also <a href="/mobile%20ci/2015/02/08/code-coverage-for-ios">gather code coverage data</a>, don’t you?</p>
<p>This is the first time Bamboo falls one plugin short. You can <a href="https://jira.atlassian.com/browse/BAM-13180">check related discussion</a> for more details.</p>
<p>Jenkins has your back on this one with <a href="https://wiki.jenkins-ci.org/display/JENKINS/Cobertura+Plugin">Cobertura Plugin</a>. You can configure custom threshold values to mark builds as failed if you tests don’t provide enough coverage.</p>
<h2 id="static-analyzers-reports">Static Analyzers Reports</h2>
<p><a href="/mobile%20ci/2015/02/08/oclint">OCLint</a> is amazing tool to run another round of static analysis on your code and detect vast number of issues as well as to enforce coding guidelines. OCLint can produce output compatible with <a href="http://pmd.sourceforge.net/">PMD</a> output format. So it can then be processed by <a href="https://wiki.jenkins-ci.org/display/JENKINS/PMD+Plugin">Jenkins PMD Plugin</a>. You end up with browsable report with issues grouped by priority, category and other criteria. You can navigate all the way down to the line of code causing the warning. Once again, you can configure threshold values to mark builds with lots of warnings as failed.</p>
<p>In fact, the same reporting plugin should be able to pick up output of Clang Static Analyzer which I mentioned before. However I couldn’t figure out the way to make Clang Static Analyzer to spit out correct XML file.</p>
<p>With Bamboo, unfortunately, all you have is publishing HTML report via shared artifact.</p>
<p>P.S. I’m a big fan of Swift programming language, but one thing makes me a bit sad. It will take some time before we get tools like OCLint available for Swift.</p>
<h2 id="warnings">Warnings</h2>
<p>If you run CI tasks such as build, test, analyze and lint, often you don’t want your build project/plan to stop immediately if it encounters an error, for example test error. You still want your reporting tasks to run and pick up those errors and generate reports for them. This often leads to a problem where you have compilation error but the build is marked as passing. Preferred way to avoid this issue is to have a reporting task which will pick up all the errors and mark build as failed if needed.</p>
<p>Jenkins has <a href="https://wiki.jenkins-ci.org/display/JENKINS/Warnings+Plugin">Warnings plugin</a> for that. It will scan build logs and detect warnings and errors generated by compiler, and it includes support for clang so <code class="highlighter-rouge">xcodebuild</code> is well covered. All you need is to configure thresholds and fail builds if it has compile errors.</p>
<p>I don’t know about Bamboo plugin to do the same job. I remember myself few months ago grepping test logs for errors and then marking builds as failed by doing something like <code class="highlighter-rouge">exit 1</code>.</p>
<h2 id="functional-tests">Functional Tests</h2>
<p>If you happen to use frameworks like <a href="http://calaba.sh/">Calabash</a> that produce <a href="https://cukes.info/">Cucumber</a> test reports, then Both CI servers have plugins to provide nice reports.</p>
<h2 id="higher-order-plugins">Higher-Order Plugins</h2>
<p>Forgive me this injection of so popular these days functional slang, but this is how I want to introduce The Mother and The Father of all Jenkins plugins - <a href="https://wiki.jenkins-ci.org/display/JENKINS/Job+DSL+Plugin">Jenkins Job DSL Plugin</a>. In short, it allows you to manage your configuration as a code and to generate and update build projects from code. What could be better for a developer?</p>
<p>Check out these resources to find out more.</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=FeSKrBvT72c">Netflix Talk Video</a></li>
<li><a href="http://www.slideshare.net/quidryan/configuration-as-code">Netflix Talk Slides</a></li>
<li><a href="https://wiki.jenkins-ci.org/display/JENKINS/Job+DSL+Plugin">Jenkins Wiki</a></li>
<li><a href="https://github.com/jenkinsci/job-dsl-plugin/wiki/Job-reference">Job DSL Job Reference</a></li>
<li><a href="https://github.com/jenkinsci/job-dsl-plugin/wiki/Job-DSL-Commands">Job DSL Commands</a></li>
<li><a href="https://github.com/jenkinsci/job-dsl-plugin/wiki/User-Power-Moves">User Power Moves</a></li>
<li><a href="https://github.com/jenkinsci/job-dsl-plugin/wiki/Real-World-Examples">Real World Examples</a></li>
</ul>
<p>I plan to write a post about my personal experience with Job DSL plugin.</p>
<p>Jenkins Job DSL plugin was a game changer for me personally. When I started working at new place a while ago, I had year and a half experience with Bamboo and acted as a strong Bamboo advocate initially. Until the moment I discovered unlimited power of Job DSL plugin. I personally can’t imagine going back to Bamboo and dealing with UI to update dozens of similar plans by hand.</p>
<p>That said, I still like Bamboo very much, particularly the way it integrates with the rest of Atlassian products. I hope Atlassian will implement Build Plan DSL plugin or provide API to make it happen. <a href="https://marketplace.atlassian.com/plugins/com.carolynvs.trade_depot">Bamboo Trade Depot Plugin</a> is the only thing that <em>could</em> match Job DSL plugin, but unfortunately it’s not even close.</p>
<h1 id="build-planproject-structure">Build Plan/Project Structure</h1>
<p>There is a bit of confusion caused by terminology used by Bamboo and Jenkins.</p>
<h2 id="bamboo">Bamboo</h2>
<p>With Bamboo you start by creating Build <em>Plan</em>.</p>
<p>Each plan consists of one ore more Build <em>Stages</em>. Stages run in <strong>sequential</strong> order. If one stage fails next stages are never executed. Stages can be configured as manual to be triggered by hand.</p>
<p>Stages contain Build <em>Jobs</em>. Build jobs in one stage can run in <strong>parallel</strong> if there’s enough build agents for that. Each job can require different capabilities and can be dispatched to run on some designated build agent. Build jobs may produce Build <em>Artifacts</em> and share them with other jobs in consequent stages. Since jobs are parallelized, if one of them fails other jobs will still keep running until they finish on their own. This feature can significantly reduce build time, instead of sequential <code class="highlighter-rouge">Build ⟼ Test ⟼ Analyze ⟼ Lint</code> running 10 minutes, you get parallel <code class="highlighter-rouge">Build || Test || Analyze || Lint</code> running for about 3 minutes (given that longest job takes around 3 minutes).</p>
<p>Finally each job is made of Build <em>Tasks</em>. Tasks run in order from top to bottom. A task may be a basic shell script or one of the many tasks provided via plugins. Here’s a generalized example of a job and it’s tasks. One large and important group of tasks is reporting tasks.</p>
<ul>
<li>Checkout git repository</li>
<li>Build</li>
<li>Test</li>
<li>Deploy</li>
<li>Generate test report</li>
</ul>
<p>A summary of a Build Plan structure</p>
<pre>
.
└── Build Stage
│ ├── Build Job
│ │ ├── Task
│ │ ├── Task
│ │ └── [more tasks]
│ └── [more jobs]
└── [more stages]
</pre>
<h2 id="not-so-parallel">Not So Parallel</h2>
<p>Bamboo deserves a special side-note in regards to parallel job execution and iOS build plans.</p>
<p>As I mentioned before, the way you assign build jobs to local or remote agents is via capabilities. An agent defines capabilities it has, a job declares capabilities it wants, and then Bamboo matches the two.</p>
<p>If you are in total control of your CI setup and mobile team is the only one using your particular Bamboo server and all agents, you have all the power to set all the agents’ capabilities and then enforce a requirement that all build jobs created by you or your teammates must explicitly specify which capabilities they need. This way you’ll harness the full power of distributed configuration, all build jobs will run only on the agents they really should run on.</p>
<p>Another situation is when mobile CI is a new addition to company CI setup. There is already a CI server and few dozens of build agents and a lot of other teams using this CI setup. Lots of teams with lots of plans created over the years.</p>
<p>Now imagine that you are adding your specialized Mac build agent to be used for Xcode builds only. You setup and configure remote Mac agent, connect it to the server and… all the other build plans start jumping on your Mac agent! That’s because 99% of those plans declare no capabilities they require, they simply expect that all the agents are identical in terms of capabilities. And that works because all the agents are indeed identical clones. Well <em>were</em> identical clones until a new Mac agent was added.</p>
<p>There’s no easy fix to this problem and you can tackle it in one of 2 ways.</p>
<h3 id="ideal-solution">Ideal Solution</h3>
<p>Ideally, CI must be done right. All the build plans must be maintained, updated and removed if no longer needed. As a requirement, all build plans must explicitly declare capabilities they require to be able to run. This is something to be enforced at team management level. Company has to have guidelines for creating and managing build plans and there must be a person or even a team (Dev Support team) responsible for keeping guidelines up to date and enforcing them.</p>
<h3 id="down-to-earth-solution">Down to Earth Solution</h3>
<p>The reality is rough. The number of existing plans is overwhelming, it will take months to chase people responsible for each build plan and communicate the importance of declaring capabilities to them. The whole change has to be made in a safe way so it doesn’t break existing workflows and production deployments.</p>
<p>You don’t have months of waiting allocated in your schedule, you need mobile CI running ASAP. One thing you could do is to setup your own CI server just for mobile and essentially move to “under the desk” setup. This way you get no support from Dev Support team (given that you have one) and all the trouble of setting up, configuring and supporting the server and agents is now yours.</p>
<p>However, you still can do mobile CI as part of company wide CI. There is a plugin that will help you - <a href="/mobile%20ci/2015/02/01/bamboo-group-agent">Bamboo Group Agent plugin</a>. Have a read if you interested, Group Agent plugin offers a solution which is not fully flexible, but will help with original problem.</p>
<h2 id="jenkins">Jenkins</h2>
<p>With Jenkins you start by creating Build Project, which is on occasions called <em>Build Job</em> causing certain confusion. In this post I’ll stick with Project term.</p>
<p>By default all you get is a basic Freestyle project that includes</p>
<ul>
<li>Description</li>
<li>Parameters</li>
<li>Build Triggers</li>
<li>Build Environment</li>
<li><em>Build Steps</em></li>
<li><em>Post-build Actions</em></li>
</ul>
<p>If you draw an analogy to Bamboo, then all you get is a build <em>plan</em> with single <em>stage</em> containing single <em>job</em> and list of <em>tasks</em> (Build Steps and Post-build Actions are nothing but tasks). That’s it. There are no stages and no way to run anything in parallel.</p>
<p>This is where plugins get into play. <a href="https://wiki.jenkins-ci.org/display/JENKINS/Multijob+Plugin">Mutlijob Plugin</a> does exactly the same thing as Bamboo. Stages are called <em>Phases</em>, phases include <em>Jobs</em>. Jobs run in <strong>parallel</strong> when possible, while phases execution order is sequential.</p>
<p>One very important distinction is that jobs in multi job project are actually references to existing build projects.</p>
<pre>
.
└── Multi Job Build Project
└── Build Phase
├── Build Job 1 ⇢ Build Project 1
└── Build Job 2 ⇢ Build Project 2
</pre>
<p>In theory you can have a multi job project that includes a job which is a multi job project… You could even unintentionally create build job retain cycles and an infinite build loop.</p>
<p>To satisfy your craving for code Multijob Plugin support is added to <a href="https://github.com/jenkinsci/job-dsl-plugin/wiki/Job-reference#multijob-phase">Job DSL Plugin</a>.</p>
<p>Once again with a fair bit of work Jenkins can match Bamboo’s default functionality and then with another fair bit of work can surpass it.</p>
<p>I mentioned artifact sharing briefly for Bamboo. For Multijob plugin there is no proper artifact sharing support yet. There’s a number of open tickets (<a href="https://issues.jenkins-ci.org/browse/JENKINS-20241">JENKINS-20241</a>, <a href="https://issues.jenkins-ci.org/browse/JENKINS-25111">JENKINS-25111</a>, <a href="https://issues.jenkins-ci.org/browse/JENKINS-16847">JENKINS-16847</a>, <a href="https://issues.jenkins-ci.org/browse/JENKINS-16847">JENKINS-16847</a>) with workarounds available. So the problem can be solved but it’s not part of official Jenkins release yet.</p>
<h3 id="not-so-parallel-either">Not So Parallel Either</h3>
<p>Jenkins is still prone to the same problem Bamboo is when it comes to adding iOS build nodes to existing infrastructure. Chances are high your Mac build node will be used by all the other build projects if capabilities are not configured properly.</p>
<p>Actually, in Jenkins world there are no capabilities as such, instead labels are used. Semantics are a bit different, but they serve the same purpose after all. Each build node can be labeled with multiple labels and build jobs can use flexible logical expressions to specify target nodes they want to run on. But then, if labels were not used in your corporate CI from day one, the amount of work required for labelling existing build projects can be too big.</p>
<p>At this moment I am not aware of a Jenkins analogue of Bamboo Group Agent.</p>
<h1 id="branch-management">Branch Management</h1>
<p>Branches are an essential part of any source code management workflow. By supporting branches in CI workflow you get a number of benefits.</p>
<h2 id="timely-feedback">Timely Feedback</h2>
<p>By running CI for each branch you provide developer with earlier feedback on their changes. They will know right away if changes they made are breaking the build, unit or functional tests, introduce static analyzer or linter warnings, etc. Developers can then fix these problems before they create pull request and involve the rest of the team in review process.</p>
<h2 id="earlier-tests">Earlier Tests</h2>
<p>If you have testable build for each branch, you can make it available to your test team automatically as part of continuous delivery process. This way important and critical changes can be tested before they are merged to upstream branch (doesn’t mean you don’t do integration testing after the merge though). Bugs can be caught earlier and you end up with faster develop-and-test iterations.</p>
<p>Finally, some branches are never destined to be merged upstream. They may contain some experimental feature code, something you still need to build and make available to testers or internal stakeholders. For example have a special build to demo crazy design idea to your UI/UX people.</p>
<h2 id="branch-naming">Branch Naming</h2>
<p>I had to mention branch naming in a separate paragraph. For some reason, yet unknown to me, when it comes to naming a branch developers get completely wild. What I mean is that within the same team you can see branch names with and without prefix, using dashes or camel case, dashes <em>and</em> camel case combined, underscores… just anything. Sometimes the same developer would be very inconsistent when naming their branches. The very same developers are very disciplined when it comes to coding, i.e. class, variable and method names, and following coding style guide in general.</p>
<p>The upshot is that you have to have branch naming guidelines in your team, e.g. as a part of Git (other SCM) workflow. If the whole “issue” doesn’t look like an issue to you, wait until you have to manage this branchy havoc in regards to CI.</p>
<h2 id="bamboo--branches">Bamboo & Branches</h2>
<p>Bamboo does a great job with branches. With a single tick of a checkbox you can create branches of a build plan. By the way, you did understand it correctly, you <em>create a <strong>branch of a</strong> build plan</em>. Essentially, Bamboo clones the original build plan and changes its source repository configuration to point to a different branch. These plans still share same build phases, jobs and tasks, but you can configure some of the branch plan settings differently, that includes notifications, branch merging strategies, etc.</p>
<p>With a standard <a href="http://docs.oracle.com/javase/tutorial/essential/regex/">Java regular expression</a> you can filter branches by their name and instruct Bamboo to ignore branch names that don’t follow guidelines. For example, the regex below will accept only <code class="highlighter-rouge">master</code> and <code class="highlighter-rouge">development</code> branches, and branches that are prefixed with <code class="highlighter-rouge">bugfix/</code>, <code class="highlighter-rouge">hotfix/</code> or <code class="highlighter-rouge">feature/</code> followed by JIRA issue ID and lowercase-with-dashes description.</p>
<script src="https://gist.github.com/3385e8dc64792d6fbd8e5695e2de43ee.js?file=branch-regex.java"> </script>
<p>A good Java regex test website is <a href="http://www.regexplanet.com/advanced/java/index.html">RegexPlanet</a>.</p>
<p>This is a perfect way to indirectly enforce correct branch naming. After missing couple of builds developers will figure out what’s wrong and change their habits. In certain situations you can always add a branch manually via Bamboo UI or <a href="/atlassian/2014/05/29/atlassian-cli">CLI tools</a>.</p>
<p>With another simple configuration field you can control aging of the branches. If branch hasn’t been updated for a long time, Bamboo will remove its build plan. Of course you’d want to preserve certain branches forever and there’s yet another checkbox to do that.</p>
<p>I’ve mentioned branch merging strategies and that’s one more feature that Bamboo provides out of the box. Using <a href="https://confluence.atlassian.com/display/BAMBOO/Using+plan+branches#Usingplanbranches-Branchupdater">Branch Updater</a> or <a href="https://confluence.atlassian.com/display/BAMBOO/Using+plan+branches#Usingplanbranches-Gatekeeper">Gatekeeper</a> you can configure build plan to do upstream merge before or downstream merge after running the build, and even push merged changes back to the repository. This is a very good way to detect merge conflicts earlier and to keep your git workflow in order.</p>
<p>Bamboo’s branches support also shines when it comes to CI pipelines, more on that later in the post.</p>
<h2 id="jenkins--branches">Jenkins & Branches</h2>
<p>Surprisingly, plugins initially do more harm than good in this case.</p>
<p>On fresh setup Jenkins has no Git support (SCM I get to work with and thus choosing it as an example). You need to install plugin to work with Git and you will most likely install <a href="https://wiki.jenkins-ci.org/display/JENKINS/Git+Plugin">the most popular Git plugin</a>.
This plugin is very powerful but of all the things it does not create branches for build projects. Well to be honest it shouldn’t.</p>
<p>When you look for a solution you will think of trying some other plugins first. Thre are a few: <a href="https://wiki.jenkins-ci.org/display/JENKINS/Multi-Branch+Project+Plugin">Multi-Branch Project</a>, <a href="https://wiki.jenkins-ci.org/display/JENKINS/Feature+Branch+Notifier+Plugin">Feature Branch Notifier</a> and others. The common problem with all of them is that they have their own support for SCMs including Git, that means you don’t get to use the Git Plugin and all of its powerful features, instead you end up with a very limited version of it.</p>
<p>I tried Multi-Branch Project plugin, it was OK, but not good enough. I couldn’t get branch filtering to work, it kept picking up all the branches ignoring filters. There’s no option to configure branch aging, no branch merging strategies and so on. Finally, no simple and easy support for branched CI pipelines.</p>
<p>This is what I meant by <em>harm</em> in this case. You spend time trying different plugins and none of them would match Bamboo default functionality.</p>
<p>But all is not lost. Once again you will be saved by Job DSL plugin. Paired with Git Plugin it can work miracles. While Git Plugin can’t branch build projects it can work with branches as such. With one line of Groovy code you can fetch all the branches for your repository including information on their last update. Then with simple string regex match and date comparison you can filter branches just like Bamboo does, and then you can generate build project for each branch, organize them into folders and views to match Bamboo’s UI. Code a bit to generate branch pipelines, same for merging strategies and much more.</p>
<p><a href="https://github.com/jenkinsci/job-dsl-plugin/wiki/Real-World-Examples">Follow this link</a> to find an example of getting branches for GitHub repository.</p>
<p>If you are using Stash there is no direct support for it via Jenkins plugins afaik. But as long as you have API access you can follow <a href="/mobile%20ci/2015/02/08/bitbucket-branches-job-dsl">Bitbucket example</a> to have basic support for working with branches. If you don’t feel like coding too much, you can wrap <a href="/atlassian/2014/05/29/atlassian-cli">some shell scripts</a> in thin layer of Groovy code to get same results.</p>
<p>Yes, it takes time and learning to get used to Job DSL plugin, but the benefits are huge.</p>
<h1 id="pipelines">Pipelines</h1>
<p>Pipelines is another name for CI/CD workflows. In certain cases single build plan/project is not enough, and that’s when you can create pipelines. Creating a pipeline means you chain build plans together, if first plan (aka <em>parent</em>) is successful it triggers its <em>child</em> plans. Child plans can have children of their own, and so on.</p>
<pre>
.
└── Parent Plan
├── Child Plan 1
│ ├── Grandchild Plan 1.1
│ └── Grandchild Plan 1.2
├── Child Plan 2
└── [more children]
</pre>
<p>A real world example of pipelines for mobile space is UI automation tests, often called Functional or Acceptance tests. UI automation is usually a heavyweight task compared to unit tests. If you run UI automation tests as part of a single build plan it can take too long to complete.</p>
<p>You can create a separate plan for UI automation only, but then you don’t want to trigger it every time there is a commit to SCM. There’s no point running UI automation tests if the build fails. So you add UI automation tests plan as a child plan to the main build plan thus creating pipeline.</p>
<p>This is just one example.</p>
<h2 id="bamboo-pipelines">Bamboo Pipelines</h2>
<p>Bamboo has support for pipelines out of the box. In parent plan configuration you simply add child plans and configure the way those are triggered, e.g. only when parent is successful.</p>
<p>Child plans don’t have to be configured in any special way, they are completely unaware of being some other plan’s children by default. The very same plan can be included in multiple pipelines acting in a different role.</p>
<p>The real power of Bamboo pipelines is in its support for branches. Child plan will only be triggered if it has the same branch as the parent plan. This means you have to configure branching for both plans to make it work. Normally this also means that both plans are using same repository, but it is not a mandatory requirement. If 2 different repositories have the same branch the feature will work all the same.</p>
<p>When child plan starts it can get artifacts from the parent via Artifact Downloader task. Yet again, the branch of the child plan gets artifacts from the matching branch of the parent plan, all is handled by Bamboo.</p>
<h2 id="jenkins-pipelines">Jenkins Pipelines</h2>
<p>Jenkins has no pipelines support by default. As usual plugins should be used.</p>
<p>This is something I’m only starting to work with, so this paragraph doesn’t have lots of details.</p>
<p>In general, Jenkins plugins let you match Bamboo functionality with a certain amount of work.</p>
<p>Most popular plugins used for pipelines are</p>
<ul>
<li><a href="https://wiki.jenkins-ci.org/display/JENKINS/Join+Plugin">Join Plugin</a></li>
<li><a href="https://wiki.jenkins-ci.org/display/JENKINS/Promoted+Builds+Plugin">Promoted Build Plugin</a></li>
</ul>
<p>Both are supported by Job DSL allowing you to script complex pipelines in code and change them easily.</p>
<h1 id="distributed-builds">Distributed Builds</h1>
<p>Both Bamboo and Jenkins have support for distributed builds. Bamboo is using <a href="https://confluence.atlassian.com/display/BAMBOO/Bamboo+remote+agent+installation+guide">Remote Agents</a> while Jenkins calls them <a href="https://wiki.jenkins-ci.org/display/JENKINS/Distributed+builds">Remote Nodes</a>, sometimes referred as slave nodes or agents.</p>
<p>A side note - both servers support local build agents/nodes as well. Those are running locally (as the name suggests) on the same hardware as the build server.</p>
<p>Back to remote agents/nodes. Complexity of setting them up and configuring doesn’t vary much between the two CI servers.</p>
<p>Both will suffer from issues caused by sitting behind the company proxy, specifically if the server is located somewhere outside your company network (e.g. in AWS cloud).</p>
<p>Why the server is in the cloud and the agent/node is not? - you’d ask. Well, that takes us to next topic.</p>
<h1 id="mac-support">Mac Support</h1>
<p>Right, this whole comparison is focusing on mobile CI after all, meaning you have to deal with one of the most popular mobile platforms these days - that is iOS.</p>
<p>To build an iOS app you must have Xcode, which can run only on OS X (unless you want to follow the path of certain insanity and make it work on other OS).</p>
<h2 id="hackintosh">Hackintosh</h2>
<p>Not a very good idea I’d say. The company does iOS development and wants to go with Hackintosh to setup OS X build server. Really?</p>
<h2 id="cloud-aka-ondemand">Cloud (aka OnDemand)</h2>
<p>Could be a really good option, but not with industry giants like AWS. AWS or alike is where you’d go if using Bamboo OnDemand feature. I can find posts as old as 2011 discussing this issue: <a href="https://answers.atlassian.com/questions/22655/bamboo-mac-agent">one</a>, <a href="https://jira.atlassian.com/browse/BAM-11870">two</a>. Apple doesn’t make it easy to run virtual OS X instances to the extent that none of the big cloud providers are brave enough to provide official support for this feature. These days you can go with one of the many Mac Mini colocation services. You either rent a Mac hardware or even provide your own.</p>
<h2 id="self-hosted">Self-Hosted</h2>
<p>This is also an option. If your company has security concerns about those Mac hosting providers, or doesn’t want to spend money for that, or for any other reason, you can always purchase Mac hardware and host it in your data center.</p>
<p>Whenever you are using self-hosting or remote hosting, you end up dealing with native hardware. I find that Mac Minis with maximized CPU, RAM, and SSD storage are perfect candidates for iOS CI box. The more you have the better.</p>
<p>Next step is to install remote agent/node and get it running. As I mentioned already, installing <a href="/mobile%20ci/2015/02/01/bamboo-remote-agent">remote agent for Bamboo</a> is around the same complexity as installing <a href="/mobile%20ci/2015/02/01/jenkins-remote-node">remote node for Jenkins</a>. The problems start popping up when you begin using them.</p>
<h2 id="bamboo-remote-agent">Bamboo Remote Agent</h2>
<p>Things you definitely need to know in regards to Bamboo remote agent.</p>
<p>[The rumor has it that] Atlassian are using Mac OS X to develop their products, including Bamboo, but OS X is never ever listed as <em>officially</em> supported. Indeed, why would you choose to run your JIRA, Stash, Bamboo, whatever, on OS X server? Hopefully with increasing demand for iOS CI Atlassian will put a bit higher priority on fixing Bamboo issues for OS X, and there’s plenty, btw.</p>
<p>Before you even start using remote agent on OS X, you have to experience a bit of pain <a href="/mobile%20ci/2015/02/01/bamboo-remote-agent">when trying to set it up</a>.</p>
<p>Major and the most important group of issues is related to <strong>Artifacts Sharing</strong>.</p>
<p>Whenever your remote agent finishes a build stage it is most often producing build artifacts. It <em>doesn’t matter</em> if those artifacts are shared or not, they must be copied to the server anyway. That is part of distributed build system. Your remote agent can go offline any time, your build plan jobs can run on different agents with different capabilities and artifacts must be passed from one agent to another. All in all, the reality is - the artifacts must be copied to the server.</p>
<h3 id="problem-proxy">Problem Proxy</h3>
<p>Is your remote agent behind proxy? May I introduce you to <a href="http://en.wikipedia.org/wiki/Chunked_transfer_encoding">HTTP 1.1 Chunked Transfer Encoding</a> then? Well, not to the feature itself, but how it relates to Bamboo: <a href="https://jira.atlassian.com/browse/BAM-5182">BAM-5182</a>, <a href="https://confluence.atlassian.com/pages/viewpage.action?pageId=420971598">more</a>.</p>
<p>Bamboo server requires support of HTTP chunked transfer feature of 1.1 protocol version to pick up artifacts. If your proxy doesn’t support this feature, you are in trouble. Strictly speaking, this is not Bamboo’s problem, this is the problem of your company network team. HTTP 1.1 standard was released in <a href="http://www.w3.org/Protocols/rfc2616/rfc2616.html">1999</a>! There is a lot of HTTP proxy implementations that support it, <a href="http://nginx.org/en/">nginx</a> for example. However, things move really slow in most of big companies when it comes to changing network infrastructure. If you are so unlucky and you company is still stuck around 1999 in terms of network infrastructure, you will most likely have to find a work-around rather than waiting months and months before you get any progress on proxy upgrade.</p>
<h3 id="problem-atlassian">Problem Atlassian</h3>
<p>But wait then! Too early to take all the blame off the Atlassian’s shoulders!</p>
<p>First of all, Bamboo remote agent JAR <a href="https://answers.atlassian.com/questions/75941/remote-agent-not-honoring-the-dhttp-nonproxyhosts-parameter">totally disrespects JVM flags for HTTP proxy whitelist (nonProxyHosts)</a>, <a href="https://jira.atlassian.com/browse/BAM-12041">upvote!</a> You can find ways around this issue, for example re-routing network calls using tools like <a href="http://squidman.net/squidman/">SquidMan</a>, but then you will face <em>The Final Blocker</em>: <a href="https://jira.atlassian.com/browse/BAM-8111">BAM!</a>, <a href="https://jira.atlassian.com/browse/BAM-8226">BAM!</a>.</p>
<p>Yes, Bamboo remote agent <a href="https://jira.atlassian.com/browse/BAM-8111?focusedCommentId=622466&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-622466">is 27 (<em>twenty seven!</em>) times slower than plain scp</a> (<a href="http://en.wikipedia.org/wiki/Secure_copy">secure copy over ssh</a>) command when it comes to copying a single <code class="highlighter-rouge">.zip</code> file which is around few hundred Mb in size.</p>
<p>Imagine that after spending all the time trying to figure out issues around your proxy and enable the agent to share artifacts with the server, you end up facing this beast? It renders all your distributed build setup useless, it takes way more time to copy build artifacts than to produce them. From reports it looks like this issue is specific for Mac OS build agents only.</p>
<p>When I faced this problem I ended up sharing artifacts via Amazon S3 bucket. This is extra work, extra shell scripts to upload and download artifacts, additional expenses for S3 bucket. You become responsible for managing outdated artifacts, you are the one who has to account for multiple build plan branches, and much more. This is really a bit too much of overhead and it is extra annoying when you know this is a core Bamboo functionality and it’s <strong>supposed to work right out of the box</strong>.</p>
<h2 id="jenkins-remote-node">Jenkins Remote Node</h2>
<p>Read the <a href="/mobile%20ci/2015/02/01/jenkins-remote-node">Jenkins Remote Node installation post</a> to get initial overview.</p>
<p>As you can see, there are common problems related to running SSH sessions as non-login user and others. I personally ended up running remote node as OS X Launch Daemon. This works, but is not ideal.</p>
<p>I have nothing yet to say about artifact copy speed from slave to master in regards to Jenkins setup, but stay tuned and/or post a comment if you have any knowledge on the matter.</p>
<h1 id="android">Android</h1>
<p>I wanted to mention Android in this last section, after all it’s mobile too.</p>
<p>I wrote one post about building Android - <a href="/android/2014/05/29/build-android-in-the-cloud">Build Android in The Cloud</a> which already provides some details.</p>
<p>In regards to Bamboo vs Jenkins comparison, almost everything I mentioned for iOS applies to Android, except the very big and troublesome Mac OS X part. You can, and you should build Android on Linux systems, and that’s exactly what AWS instances are running on! It means that if you have 25 build agents/nodes in the cloud, all 25 of them can be used to build Android projects.</p>
<p>I had experience with building Android projects using Bamboo OnDemand setup hosted in AWS cloud. It worked (and what I was last told it still works) flawless and scalability of AWS really pays back. Despite the fact that building Android project was way more slower than building similar iOS project, that wasn’t really a concern given the number of resources available to do the job. I still had to run Android UI Automation tests (using <a href="https://calaba.sh/">Calabash</a>) on Mac OS X box, because Linux agents in the cloud didn’t have enough horsepower to run <a href="https://www.genymotion.com/">Genymotion</a> or Android Emulator reliably.</p>
<h1 id="summary">Summary</h1>
<p>Despite my excitement with Jenkins Job DSL plugin there’s no clear winner for me.</p>
<p>Both solutions can be used for enterprise level mobile CI. Both can be used in pure UI-driven way while Jenkins also offers a code-driven approach with certain trade-offs.</p>
<p>I’d say, whichever server you use, whatever your CI requirements are, just make sure you take it seriously. In some way I’m calling out to all of you to help mobile CI to get out of its teen years.</p>
https://mgrebenets.github.io/mobile%20ci/2015/01/29/bamboo-vs-jenkins
https://mgrebenets.github.io/mobile%20ci/2015/01/29/bamboo-vs-jenkins2015-01-29T00:00:00+00:00Swift Dictionary Literal Convertible
<p>[<font color="red">OUTDATED</font>]</p>
<p>A practical example of Swift’s <code class="highlighter-rouge">DictionaryLiteralConvertible</code> protocol application.</p>
<!--more-->
<blockquote>
<p>Note. This article content refers to Swift version 2.0 or earlier and is now outdated.</p>
</blockquote>
<p>If “Literal Convertibles” sounds strange to you then a good place to start is an excellent <a href="http://nshipster.com/swift-literal-convertible/">NSHipster’s post</a>.</p>
<p>OK, let’s say we have some struct in Swift.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">struct</span> <span class="kt">Options</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">timeout</span><span class="p">:</span> <span class="kt">Double</span> <span class="o">=</span> <span class="mi">1</span>
<span class="k">let</span> <span class="nv">message</span> <span class="o">=</span> <span class="s">"Timeout failed."</span>
<span class="p">}</span>
</code></pre></div></div>
<p>This is a structure holding timeout options for some abstract waiting function. If waiting takes longer that <code class="highlighter-rouge">timeout</code> then waiting is terminated and the <code class="highlighter-rouge">message</code> is displayed. For convenience default values are provided.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">func</span> <span class="nf">wait</span><span class="p">(</span><span class="nv">options</span><span class="p">:</span> <span class="kt">Options</span><span class="p">)</span> <span class="p">{</span>
<span class="nf">println</span><span class="p">(</span><span class="s">"Waiting for </span><span class="se">\(</span><span class="n">options</span><span class="o">.</span><span class="n">timeout</span><span class="se">)</span><span class="s">. Message: </span><span class="se">\(</span><span class="n">options</span><span class="o">.</span><span class="n">message</span><span class="se">)</span><span class="s">"</span><span class="p">)</span>
<span class="c1">// TODO: wait for some condition and fail after timeout</span>
<span class="p">}</span>
<span class="nf">wait</span><span class="p">(</span><span class="kt">Options</span><span class="p">(</span><span class="nv">timeout</span><span class="p">:</span> <span class="mf">0.1</span><span class="p">,</span> <span class="nv">message</span><span class="p">:</span> <span class="s">"Custom timeout failed."</span><span class="p">))</span>
</code></pre></div></div>
<p>Now, wouldn’t it be nice to add some syntactic sugar and pass a dictionary with key-value pairs for waiting options, instead of calling <code class="highlighter-rouge">Options</code> initializer?</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">wait</span><span class="p">([</span><span class="s">"timeout"</span><span class="p">:</span> <span class="mf">0.1</span><span class="p">])</span>
</code></pre></div></div>
<p>Of course compiler doesn’t like this code, though it fails to tell us exactly why.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s1">'Options'</span> does not have a member named <span class="s1">'Value'</span>
</code></pre></div></div>
<p>Let’s experiment a bit.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">wait</span><span class="p">(</span><span class="s">"SomeString"</span><span class="p">)</span>
</code></pre></div></div>
<p>Doesn’t make much sense but this time compiler complains with more sane error message.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Type <span class="s1">'Options'</span> does not conform to protocol <span class="s1">'StringLiteralConvertible'</span>
</code></pre></div></div>
<p>Basically it doesn’t know how to construct and instance of <code class="highlighter-rouge">Options</code> type from <code class="highlighter-rouge">String</code>.</p>
<p>So when we used dictionary before, compiler had no idea how to create an instance of <code class="highlighter-rouge">Options</code> from a dictionary, but sadly couldn’t communicate it back to us in a human-friendly form.</p>
<p>To be able to create <code class="highlighter-rouge">Options</code> objects from dictionaries <code class="highlighter-rouge">Options</code> has to conform to <code class="highlighter-rouge">DictionaryLiteralConvertible</code> protocol.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">/// Conforming types can be initialized with dictionary literals</span>
<span class="kd">protocol</span> <span class="kt">DictionaryLiteralConvertible</span> <span class="p">{</span>
<span class="kd">typealias</span> <span class="kt">Key</span>
<span class="kd">typealias</span> <span class="kt">Value</span>
<span class="c1">/// Create an instance initialized with `elements`.</span>
<span class="nf">init</span><span class="p">(</span><span class="n">dictionaryLiteral</span> <span class="nv">elements</span><span class="p">:</span> <span class="p">(</span><span class="kt">Key</span><span class="p">,</span> <span class="kt">Value</span><span class="p">)</span><span class="o">...</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<p>To conform to this protocol we need to implement <code class="highlighter-rouge">init</code> and define type aliases for <code class="highlighter-rouge">Key</code> and <code class="highlighter-rouge">Value</code>. This was somewhat of a surprise for me, even when reading NSHipster’s post for the first time I didn’t realize that typealias are part of the protocol and had to be “implemented” (declared) too. I must have confused <code class="highlighter-rouge">typealias</code> with C’s <code class="highlighter-rouge">typedef</code> for a while, hence misunderstanding of <code class="highlighter-rouge">typealias</code>.</p>
<p>OK, first attempt in conforming to the protocol.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">extension</span> <span class="kt">Options</span><span class="p">:</span> <span class="kt">DictionaryLiteralConvertible</span> <span class="p">{</span>
<span class="kd">typealias</span> <span class="kt">Key</span> <span class="o">=</span> <span class="kt">String</span>
<span class="kd">typealias</span> <span class="kt">Value</span> <span class="o">=</span> <span class="kt">AnyObject</span>
<span class="nf">init</span><span class="p">(</span><span class="n">dictionaryLiteral</span> <span class="nv">elements</span><span class="p">:</span> <span class="p">(</span><span class="kt">Key</span><span class="p">,</span> <span class="kt">Value</span><span class="p">)</span><span class="o">...</span><span class="p">)</span> <span class="p">{</span>
<span class="k">for</span> <span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span> <span class="k">in</span> <span class="n">elements</span> <span class="p">{</span>
<span class="k">switch</span> <span class="n">key</span> <span class="p">{</span>
<span class="k">case</span> <span class="s">"timeout"</span><span class="p">:</span> <span class="k">self</span><span class="o">.</span><span class="n">timeout</span> <span class="o">=</span> <span class="n">value</span> <span class="k">as</span> <span class="kt">Double</span>
<span class="k">case</span> <span class="s">"message"</span><span class="p">:</span> <span class="k">self</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">value</span> <span class="k">as</span> <span class="kt">String</span>
<span class="k">default</span><span class="p">:</span>
<span class="nf">fatalError</span><span class="p">(</span><span class="s">"Unknown key: </span><span class="se">\(</span><span class="n">key</span><span class="se">)</span><span class="s">"</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>For dictionary keys the <code class="highlighter-rouge">String</code> type is used, and for values use <code class="highlighter-rouge">AnyObject</code> since we can pass either <code class="highlighter-rouge">Double</code> or <code class="highlighter-rouge">String</code> as a value.</p>
<p>I’m sure there’s a better more type-safe way to type alias <code class="highlighter-rouge">Value</code> to make it more “functional”. Probably using enums. I’m still learning though.</p>
<p>The <code class="highlighter-rouge">init</code> iterates over the contents of the dictionary and initializes struct’s members with values from the dictionary. The <code class="highlighter-rouge">as</code> is used to type cast <code class="highlighter-rouge">AnyObject</code> to <code class="highlighter-rouge">Double</code> or <code class="highlighter-rouge">String</code>.</p>
<p>I’m aware that use of <code class="highlighter-rouge">self</code> is not strictly required in this case and <code class="highlighter-rouge">self.timeout =</code> works same as just <code class="highlighter-rouge">timeout =</code>, but I tend to explicitly use <code class="highlighter-rouge">self.</code> syntax in initializers, kind of rule of thumb.</p>
<p>Let’s try it again.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">wait</span><span class="p">([</span><span class="s">"timeout"</span><span class="p">:</span> <span class="mf">0.1</span><span class="p">])</span>
</code></pre></div></div>
<p>It works. Also notice that we can now provide partial arguments, like only timeout but no message in this case, something we couldn’t with default struct initializer (would have to implement additional initializers).</p>
<p>Yet there are few things that smell in this code (apart from <code class="highlighter-rouge">AnyObject</code> I suppose).</p>
<ul>
<li>Use of hard-coded string literals like “timeout” is not good, typos happen all the time and it’s quite painful to debug this type of errors.</li>
<li>Default <code class="highlighter-rouge">case</code> statement with <code class="highlighter-rouge">fatalError</code> plug.</li>
</ul>
<p>Let’s now fix both these issues. First we will use a custom enum type for keys.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">enum</span> <span class="kt">OptionKey</span> <span class="p">{</span>
<span class="k">case</span> <span class="kt">Timeout</span><span class="p">,</span> <span class="kt">Message</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Note that’s it not even backed up by a raw <code class="highlighter-rouge">String</code> type, there’s no need for that at the moment.</p>
<p>Now can rewrite the <code class="highlighter-rouge">Options</code> extension.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">extension</span> <span class="kt">Options</span><span class="p">:</span> <span class="kt">DictionaryLiteralConvertible</span> <span class="p">{</span>
<span class="kd">typealias</span> <span class="kt">Key</span> <span class="o">=</span> <span class="kt">OptionKey</span>
<span class="kd">typealias</span> <span class="kt">Value</span> <span class="o">=</span> <span class="kt">AnyObject</span>
<span class="nf">init</span><span class="p">(</span><span class="n">dictionaryLiteral</span> <span class="nv">elements</span><span class="p">:</span> <span class="p">(</span><span class="kt">Key</span><span class="p">,</span> <span class="kt">Value</span><span class="p">)</span><span class="o">...</span><span class="p">)</span> <span class="p">{</span>
<span class="k">for</span> <span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span> <span class="k">in</span> <span class="n">elements</span> <span class="p">{</span>
<span class="k">switch</span> <span class="n">key</span> <span class="p">{</span>
<span class="k">case</span> <span class="o">.</span><span class="kt">Timeout</span><span class="p">:</span> <span class="n">timeout</span> <span class="o">=</span> <span class="n">value</span> <span class="k">as</span> <span class="kt">Double</span>
<span class="k">case</span> <span class="o">.</span><span class="kt">Message</span><span class="p">:</span> <span class="n">message</span> <span class="o">=</span> <span class="n">value</span> <span class="k">as</span> <span class="kt">String</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Main changes are</p>
<ul>
<li>Use <code class="highlighter-rouge">OptionKey</code> for <code class="highlighter-rouge">Key</code> type alias.</li>
<li>Get rid of <code class="highlighter-rouge">default:</code> case, wrong key errors are now handled at compile time, not at run time.</li>
</ul>
<p>Using the <code class="highlighter-rouge">wait</code> function is now as simple as</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">wait</span><span class="p">([</span><span class="o">.</span><span class="kt">Timeout</span><span class="p">:</span> <span class="mf">0.1</span><span class="p">])</span>
<span class="nf">wait</span><span class="p">([</span><span class="o">.</span><span class="kt">Timeout</span><span class="p">:</span> <span class="mf">0.1</span><span class="p">,</span> <span class="o">.</span><span class="kt">Message</span><span class="p">:</span> <span class="s">"Custom timeout failed."</span><span class="p">])</span>
</code></pre></div></div>
<p>You can <a href="https://gist.github.com/mgrebenets/ae93a434f3b15026c150">grab the swift code</a> and try it yourself in playground or just by running from command line with <code class="highlighter-rouge">xcrun swift</code>.</p>
https://mgrebenets.github.io/swift/2015/01/27/swift-dictionary-literal-convertible
https://mgrebenets.github.io/swift/2015/01/27/swift-dictionary-literal-convertible2015-01-27T00:00:00+00:00Swift and Objective-C Interoperability
<p>[<font color="red">OUTDATED</font>]</p>
<p>I’ve stumbled on an issue while working on my hobby project. One of the few related to Swift and Objective-C interoperability.</p>
<!--more-->
<blockquote>
<p>Note. This article content refers to Swift version 2.0 or earlier and is now outdated.</p>
</blockquote>
<p>Let’s setup a simple code base.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">import</span> <span class="kt">AppKit</span>
<span class="kd">typealias</span> <span class="kt">BaseObjCClass</span> <span class="o">=</span> <span class="kt">NSObject</span>
<span class="kd">enum</span> <span class="kt">PureSwiftEnum</span> <span class="p">{</span>
<span class="k">case</span> <span class="kt">Value</span><span class="p">,</span> <span class="kt">AnotherValue</span>
<span class="p">}</span>
<span class="kd">protocol</span> <span class="kt">PureSwiftProtocol</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">value</span><span class="p">:</span> <span class="kt">PureSwiftEnum</span> <span class="p">{</span> <span class="k">get</span> <span class="p">}</span>
<span class="k">var</span> <span class="nv">size</span><span class="p">:</span> <span class="kt">CGSize</span> <span class="p">{</span> <span class="k">get</span> <span class="p">}</span>
<span class="p">}</span>
<span class="kd">class</span> <span class="kt">ObjCSubclass</span><span class="p">:</span> <span class="kt">BaseObjCClass</span><span class="p">,</span> <span class="kt">PureSwiftProtocol</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">value</span><span class="p">:</span> <span class="kt">PureSwiftEnum</span> <span class="o">=</span> <span class="o">.</span><span class="kt">Value</span>
<span class="k">var</span> <span class="nv">size</span><span class="p">:</span> <span class="kt">CGSize</span> <span class="o">=</span> <span class="kt">CGSizeZero</span>
<span class="p">}</span>
<span class="kd">class</span> <span class="kt">GenericClass</span><span class="o"><</span><span class="kt">T</span> <span class="k">where</span> <span class="kt">T</span><span class="p">:</span> <span class="kt">PureSwiftProtocol</span><span class="o">></span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">embeddedInstance</span><span class="p">:</span> <span class="kt">T</span>
<span class="nf">init</span><span class="p">(</span><span class="nv">embeddedInstance</span><span class="p">:</span> <span class="kt">T</span><span class="p">)</span> <span class="p">{</span>
<span class="k">self</span><span class="o">.</span><span class="n">instance</span> <span class="o">=</span> <span class="n">instance</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">accessValue</span><span class="p">()</span> <span class="o">-></span> <span class="kt">PureSwiftEnum</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">instance</span><span class="o">.</span><span class="n">value</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">accessSize</span><span class="p">()</span> <span class="o">-></span> <span class="kt">CGSize</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">instance</span><span class="o">.</span><span class="n">size</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">let</span> <span class="nv">objectGeneric</span> <span class="o">=</span> <span class="kt">GenericClass</span><span class="p">(</span><span class="nv">embeddedInstance</span><span class="p">:</span> <span class="kt">ObjCSubclass</span><span class="p">())</span>
<span class="nf">println</span><span class="p">(</span><span class="n">objectGeneric</span><span class="o">.</span><span class="nf">accessValue</span><span class="p">())</span>
<span class="nf">println</span><span class="p">(</span><span class="n">objectGeneric</span><span class="o">.</span><span class="nf">accessSize</span><span class="p">())</span>
</code></pre></div></div>
<p>There’s pure Swift enum, protocol and a subclass of Objective-C class that adopts pure Swift protocol. By the way, have you ever tried declaring Swift enum with just one case?</p>
<p>Further on, I declare a generic class with type conforming to pure Swift protocol.</p>
<p>So what happens if I pass an Objective-C subclass to this generic class initializer?</p>
<p>To be honest, nothing happens most away. For reasons unknown to me my project compiled and ran. And it was running OK for a while until at some moment it started crashing consistently.</p>
<p>So the problem in this case is that I’m implicitly checking the conformance of Objective-C object <code class="highlighter-rouge">ObjCSubclass</code> to a non Objective-C (pure Swift) protocol <code class="highlighter-rouge">PureSwiftProtocol</code>. This check occurs when calling <code class="highlighter-rouge">return embeddedInstance.value</code> where <code class="highlighter-rouge">embeddedInstance</code> is an instance of <code class="highlighter-rouge">ObjCSubclass</code> but the access to it’s property happens by converting it to <code class="highlighter-rouge">PureSwiftProtocol</code>.</p>
<p>Apparently, this is a known issue. There’s a couple of discussions on StackOverflow (<a href="http://stackoverflow.com/questions/24132738/swift-set-delegate-to-self-gives-exc-bad-access">one</a>, <a href="http://stackoverflow.com/questions/24174348/calling-method-using-optional-chaining-on-weak-variable-causes-exc-bad-access">two</a>).</p>
<h1 id="solution-a-back-to-roots">Solution A: Back to Roots</h1>
<p>The first solution is to turn <code class="highlighter-rouge">PureSwiftProtocol</code> into Objective-C protocol by using <code class="highlighter-rouge">@objc</code> notation.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">@objc</span> <span class="kd">protocol</span> <span class="kt">PureSwiftProtocol</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">value</span><span class="p">:</span> <span class="kt">PureSwiftEnum</span> <span class="p">{</span> <span class="k">get</span> <span class="p">}</span>
<span class="k">var</span> <span class="nv">size</span><span class="p">:</span> <span class="kt">CGSize</span> <span class="p">{</span> <span class="k">get</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>But that won’t make compiler happy because it has no idea how to map <code class="highlighter-rouge">PureSwiftEnum</code> into Objective-C. So you have to take it one step further. You have to declare <code class="highlighter-rouge">PureSwiftEnum</code> as Objective-C enum (with <code class="highlighter-rouge">NS_ENUM</code>), obviously you have to do it in Objective-C header file and properly setup bridging header in your project.</p>
<pre><code class="language-objective-c">typedef NS_ENUM(NSInteger, PureSwiftEnum) {
PureSwiftEnumValue,
PureSwiftEnumAnotherValue,
};
</code></pre>
<h1 id="solution-b-wrap-it-up">Solution B: Wrap it Up</h1>
<p>If you don’t want to revert back to adding Objective-C code with the hope that Apple eventually fixes this issue in the future, you can try another ugly trick - wrap your Objective-C class with pure Swift class that conforms to the same protocol.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="kt">PureSwiftWrapper</span><span class="p">:</span> <span class="kt">PureSwiftProtocol</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">objcInstance</span><span class="p">:</span> <span class="kt">ObjCSubclass</span>
<span class="nf">init</span><span class="p">(</span><span class="nv">objcInstance</span><span class="p">:</span> <span class="kt">ObjcSubclass</span><span class="p">)</span> <span class="p">{</span>
<span class="k">self</span><span class="o">.</span><span class="n">objcInstance</span> <span class="o">=</span> <span class="n">objcInstance</span>
<span class="p">}</span>
<span class="k">var</span> <span class="nv">value</span><span class="p">:</span> <span class="kt">PureSwiftEnum</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">objcInstance</span><span class="o">.</span><span class="n">value</span>
<span class="p">}</span>
<span class="k">var</span> <span class="nv">size</span><span class="p">:</span> <span class="kt">CGSize</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">objcInstance</span><span class="o">.</span><span class="n">size</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Now you can pass an instance of <code class="highlighter-rouge">PureSwiftWrapper</code> to <code class="highlighter-rouge">GenericClass</code></p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">wrapper</span> <span class="o">=</span> <span class="kt">PureSwiftWrapper</span><span class="p">(</span><span class="nv">objcInstance</span><span class="p">:</span> <span class="kt">ObjCSubclass</span><span class="p">())</span>
<span class="k">let</span> <span class="nv">generic</span> <span class="o">=</span> <span class="kt">GenericClass</span><span class="p">(</span><span class="nv">embeddedInstance</span><span class="p">:</span> <span class="n">wrapper</span><span class="p">)</span>
<span class="nf">println</span><span class="p">(</span><span class="n">generic</span><span class="o">.</span><span class="nf">accessValue</span><span class="p">())</span>
</code></pre></div></div>
<p>With this setup my crash went away and hadn’t reappeared since then.</p>
<h1 id="summary">Summary</h1>
<p>Reference to <a href="https://gist.github.com/mgrebenets/96a0f3f26512ffba5ab1">objc-interop.swift</a> to experiment and run it from command line or in Playground</p>
https://mgrebenets.github.io/swift/2015/01/22/swift-objective-c-interoperability
https://mgrebenets.github.io/swift/2015/01/22/swift--objective-c-interoperability2015-01-22T00:00:00+00:00Flappy Swift
<p>Yet another clone of <a href="https://bitbucket.org/i4niac/flappy-swift">Flappy Bird</a>. Once again written in Swift.
Accompanied by <a href="https://bitbucket.org/i4niac/flappy-boo">Flappy Boo</a> written in Objective-C.</p>
<!--more-->
<p><img src="https://bitbucket.org/i4niac/flappy-swift/raw/master/Assets/FlappySwift.png" alt="Flappy Swift" />
<img src="https://bitbucket.org/i4niac/flappy-boo/raw/master/Assets/FlappyBoo.png" alt="Flappy Boo" /></p>
https://mgrebenets.github.io/swift/2015/01/12/flappy-swift
https://mgrebenets.github.io/swift/2015/01/12/flappy-swift2015-01-12T00:00:00+00:00Shark 2 for iOS/OS X
<p>SHARK provides libraries for the design of adaptive systems, including methods for linear and nonlinear optimization (e.g., evolutionary and gradient-based algorithms), kernel-based algorithms and neural networks, and other machine learning techniques.</p>
<p>This script is created to build framework for Shark version 2.3.4.</p>
<!--more-->
<p>To read the full article please <a href="https://mgrebenets.github.io/shark2-iosx/">follow the link</a>.</p>
https://mgrebenets.github.io/references/2014/06/05/shark-2-for-ios
https://mgrebenets.github.io/references/2014/06/05/shark-2-for-ios2014-06-05T00:00:00+00:00Install Atlassian CLI with RPM
<p>Another follow up to <a href="/atlassian/2014/05/29/atlassian-cli">introduction to Atlassian CLI</a>.</p>
<p>This post describes how to create an RPM package for Atlassian CLI to install it on <a href="http://en.wikipedia.org/wiki/Category:RPM-based_Linux_distributions">RMP-based Linux distributions</a>.</p>
<!--more-->
<p>Jump directly to <a href="#tldr">Summary</a> if just want to grab the end result.</p>
<h1 id="why-bother">Why Bother?</h1>
<p>Same question as one would as for using <a href="/atlassian/2014/05/30/atlassian-cli-homebrew">Homebrew on OS X</a>. And same answer again - Automation.</p>
<p>Let’s assume you already use Atlassian CLI Client for number of build tasks, like automatically updating JIRA tickets, Confluence pages, Stash pull requests, etc.</p>
<p>Let’s further assume that your company has a proper CI environment, for example RPM-based Linux instances running in <a href="http://aws.amazon.com/">AWS cloud</a>. Each instance runs one build agent (slave, node or whatever you call it).</p>
<p>One of the reasons going into the cloud is scalability, you can go from one to few dozens of identically cloned agents with literally one click of a mouse.</p>
<p>Normal practice is to refresh those instances repeatedly, e.g. on a 2 weeks schedule, and <em>refresh</em> in this context means recreating them from scratch. This is when an updated OS image is used for new instances, you can put new updates and packages into this new image to make it available to all build tasks by default without additional installation. For example, you could not just have <a href="https://rvm.io/">RVM</a> installed, but also install few most used rubies for 2.0 and 2.1.</p>
<p>Preparing new image has a funny name, that is <em>Baking</em> (remember <em>Brewing</em>?). What’s amusing, the whole baking process is done by the very same CI setup it will be applied to. Keeping an eye on the whole infrastructure is actually quite a challenge and you would most likely have DevOps or DevSupport team to look after it.</p>
<p>In any case, to conclude this long passage, one of the reasons to have an RPM package for Atlassian CLI is to be able to bake it into your build agent.</p>
<h1 id="create-rpm-spec">Create RPM Spec</h1>
<p>Creating and RPM package is very similar to creating Homebrew tap, only in this case instead of Formula you need to create <a href="http://www.rpm.org/max-rpm/ch-rpm-inside.html">RPM Spec</a>.</p>
<script src="https://gist.github.com/37158fe1783032cec7b1829a76dbc240.js"> </script>
<p>Let’s put first lines into the spec</p>
<script src="https://gist.github.com/504997f5009f938327926df111f912e1.js"> </script>
<p>First three lines are a result of googling as well ans trial and error process. I’m not an experienced RPM package builder, so there are things that I will have to leave unexplained.</p>
<p>Next lines are self descriptive. The <code class="highlighter-rouge">%{varname}</code> syntax is the way you can pass variables into RPM spec when using it with <code class="highlighter-rouge">rpmbuild</code>, for example</p>
<script src="https://gist.github.com/8e5d06ec235d0ca5e1a60e693eef5767.js"> </script>
<p>Some of the header attributes worth mentioning separately. For starters the <em>Source:</em> attribute should point to your source tarball. But it doesn’t have to be a local file, it can be a URL just like Homebrew’s <code class="highlighter-rouge">url</code> attribute. You can then download and unzip it with one call to <a href="http://www.rpm.org/max-rpm-snapshot/s1-rpm-inside-macros.html"><code class="highlighter-rouge">%setup</code> macro</a>.</p>
<script src="https://gist.github.com/873d31a55578c410a552e8fa3985c012.js"> </script>
<p>I myself just found out about it recently and didn’t try it yet. So in this article I’ll do the job of setup macro with shell commands, but this is definitely where improvements should be made.</p>
<p>Then there’s <code class="highlighter-rouge">_tmppath</code> variable. You will notice later that it’s not passed to RPM script directly anywhere, instead, it’s picked up from a special <code class="highlighter-rouge">.rpmmacros</code> file. You’ll see how it’s used later on.</p>
<h2 id="install">Install</h2>
<p>Now it’s time to define install command. It’s again very similar to Homebrew’s install. So I will give here brief description of the steps with the code and for more details you can always get back to <a href="/atlassian/2014/05/30/atlassian-cli-homebrew">Homebrew post</a>.</p>
<h3 id="prepare-and-setup">Prepare and Setup</h3>
<p>Since we don’t use <code class="highlighter-rouge">%setup</code> macro, we have to some of the work here.
Remove old build directory, unzip the source tarball and cleanup Windows stuff right away.</p>
<script src="https://gist.github.com/21692bd8238e74939aec81317c519a63.js"> </script>
<h3 id="patch-and-move">Patch and Move</h3>
<p>Next is patching time and once patching is over move the files to a proper location (<code class="highlighter-rouge">bin</code> folder). I’ve explained why this is required in the post related to Homebrew formula, so have a peek there.</p>
<p>When patching we’ll update all the <code class="highlighter-rouge">.sh</code> scripts and put new relative path to JAR files, we’ll also insert proper <code class="highlighter-rouge">JAVA_HOME</code> export in each.</p>
<script src="https://gist.github.com/13111f661d07725e30a433d894f548ef.js"> </script>
<p>Then it’s time to customize all the Atlassian product URLs as well as put a proper service account username and password if you plan to save keystrokes in the future.</p>
<script src="https://gist.github.com/8c80740d01d926132493ed9cef49ba1b.js"> </script>
<p>Finally rename ambiguous <code class="highlighter-rouge">all.sh</code> to <code class="highlighter-rouge">atlassian-all.sh</code> and move all <code class="highlighter-rouge">.sh</code> files to <code class="highlighter-rouge">bin</code> folder. I personally prefer to drop <code class="highlighter-rouge">.sh</code> part from the filename in the process.</p>
<script src="https://gist.github.com/418da258254c406d9476b19cde49bdf0.js"> </script>
<h2 id="files-and-symlinks">Files and Symlinks</h2>
<p>Now it’s time to tell RPM spec which files are part of final installation.</p>
<script src="https://gist.github.com/c3701f13053b57eb77e7ce137c995186.js"> </script>
<p>In post-install stage we want to symlink all the shell scripts and JAR files to a corresponding directory in <code class="highlighter-rouge">/usr/local</code>. The reason behind that is because <code class="highlighter-rouge">/usr/local/bin</code> is already on our <code class="highlighter-rouge">PATH</code> (if not, then add it as described in Homebrew post).</p>
<p>We also add info for post-uninstall process so it can remove all these symlinks for us.</p>
<script src="https://gist.github.com/008732370134446dcaa6f8568644b8ff.js"> </script>
<h3 id="clean">Clean</h3>
<p>No comments on this one.</p>
<script src="https://gist.github.com/14d974a7204f20f8318ce178563b0f62.js"> </script>
<h2 id="changelog">Changelog</h2>
<p>Add some change log and you are done with the spec.</p>
<script src="https://gist.github.com/ac34d4f9ff5308434465976383168d72.js"> </script>
<h1 id="build-rpm">Build RPM</h1>
<p>It’s time to build an RPM based on the spec we have just came up with.
In this example I’ll use Makefile which helps to present material in more simple and organized way than just shell scripts.</p>
<script src="https://gist.github.com/445d211053a1c2aa49db4dda336cb3af.js"> </script>
<p>Define all the basic configuration, like version, release, Java version, etc.
Note the use of <code class="highlighter-rouge">noarch</code> here for architecture. We are working with collection of JARs and shell scripts, there are no sources files that need any compilation at all, so we specify that we are not building for any particular architecture.</p>
<script src="https://gist.github.com/c074982634b4c1b9e29b68dca39b2bc3.js"> </script>
<p>Now define step by step what needs to be done using Makefile targets (aka recepies).</p>
<p>Download the package if it doesn’t exist yet.</p>
<script src="https://gist.github.com/4566e82deb6299e157b27202d2ca9dcb.js"> </script>
<p>Then unzip. This place partially explains why I avoided <code class="highlighter-rouge">%setup</code> macro. Setup macro assumes source is a tarball and uses <code class="highlighter-rouge">tar</code> utility to unpack it. But with Atlassian CLI the source is just a <code class="highlighter-rouge">.zip</code> file, so setup macro generates commands that don’t work.</p>
<script src="https://gist.github.com/50de3c1a8fff91b520ae037ec3d3a5b1.js"> </script>
<p>Once unzipped, we also link symbolically versioned folder to <code class="highlighter-rouge">${PACKAGE}</code> file. This makes it easier to write next steps.</p>
<p>Now pack unzipped file into a tarball. This is all due to specifics of <code class="highlighter-rouge">rpmbuild</code>, it want’s tarball and we have to comply. Put the tarball into distributive directory.</p>
<script src="https://gist.github.com/bf611dcc0a72d697ed3b32c3124542cb.js"> </script>
<p>Finally we can build RPM.</p>
<p>Still we end up doing some additional work here. <code class="highlighter-rouge">rpmbuild</code> expects a certain directory structure in it’s root build folder. Once again, we’re pretty much doing the <code class="highlighter-rouge">%setup</code> job here.</p>
<ul>
<li>We will build an RPM in <code class="highlighter-rouge">~/rpmbuild</code> directory, so we create one with number of required subdirectories (all those names in caps and tmp).</li>
<li>Then move tarball to <code class="highlighter-rouge">SOURCES</code> directory</li>
<li>Copy our RPM spec to <code class="highlighter-rouge">SPECS</code></li>
<li>Then add <code class="highlighter-rouge">%_topdir</code> and <code class="highlighter-rouge">%_tmppath</code> to a special <code class="highlighter-rouge">~/.rpmmacros</code> file. <code class="highlighter-rouge">rpmbuild</code> will scan <code class="highlighter-rouge">~/.rpmmacros</code> and pass all picked up values to RPM spec when building it.</li>
<li>Finally call rpmbuild passing version, release and all the other vars.
<ul>
<li>The <a href="http://www.rpm.org/max-rpm-snapshot/ch-rpm-b-command.html"><code class="highlighter-rouge">-bb</code> option</a> tells <code class="highlighter-rouge">rpmbuild</code> which steps to execute.</li>
</ul>
</li>
<li>Once <code class="highlighter-rouge">rpmbuild</code> is done, copy RPM package to distributive directory.</li>
</ul>
<script src="https://gist.github.com/1bb863edad11b9f4c3edd1c9c316f0e5.js"> </script>
<p>So, are you ready to try it?</p>
<script src="https://gist.github.com/3a5479c438e97fbf76c966643698349b.js"> </script>
<p>I ran it on Fedora 20 as well on a custom Linux distribution running in AWS cloud. Since the package does not depend on architecture, you could in theory build it on OS X machine, but it’s not what I would recommend, getting proper <code class="highlighter-rouge">rpmbuild</code> port configured is not something you enjoy very much.</p>
<h1 id="install-rpm">Install RPM</h1>
<p>To test your installation, use these commands</p>
<script src="https://gist.github.com/487921b8066cb6cd5cad0feb1d4e07cb.js"> </script>
<p>Now you can hand RPM package over to your Dev Support guys, they’ll put it into local repo and make RPM install a part of bake or post-bake process.</p>
<p>Yet nothing stops you from creating a CI plan (job) for the Atlassian CLI RPM package itself. You can run <code class="highlighter-rouge">make rpm</code> and test rpm install on the very same build agent this package is targeted for, thus creating yet another “CI Loop”, which is good.</p>
<p><a name="tldr"></a></p>
<h1 id="summary">Summary</h1>
<ul>
<li>Create <a href="b40ad2077172db9cdb2d">RPM spec</a></li>
<li>Run <code class="highlighter-rouge">make rpm -f RPMMakefile</code> using this <a href="b1b9d52e135561362666">RPMMakefile</a></li>
</ul>
https://mgrebenets.github.io/atlassian/2014/05/30/atlassian-cli-rpm
https://mgrebenets.github.io/atlassian/2014/05/30/atlassian-cli-rpm2014-05-30T00:00:00+00:00Install Atlassian CLI with Homebrew
<p>This is a follow up to <a href="/atlassian/2014/05/29/atlassian-cli">introduction to Atlassian CLI</a>.</p>
<p>In this post you will learn how to create custom <a href="http://brew.sh/">Homebrew</a> formula, install Atlassian CLI via Homebrew tap and customize tools for you company environment.</p>
<!--more-->
<p>If you don’t care about all the details and steps involved, you can jump right to <a href="#tldr">Summary</a> section.</p>
<h1 id="brew">Brew</h1>
<p><a href="http://brew.sh/">Homebrew</a> (aka “brew”) is a missing package manager for OS X.
After you install it, you need to update your <code class="highlighter-rouge">PATH</code>. By default <code class="highlighter-rouge">/usr/local/bin</code> is not in the system path, so modify your <code class="highlighter-rouge">~/.bash_profile</code> before you continue.</p>
<script src="https://gist.github.com/a17bef39eee3fe70cdbd626989144569.js"> </script>
<h2 id="why-brew">Why Brew?</h2>
<p>A perfectly valid question. Why would you go into all the trouble of creating formula, when you could just unzip, copy and update <code class="highlighter-rouge">PATH</code>, or even write a simple shell script to do that.</p>
<p>Well, Homebrew does all that and then much more. After initial installation upgrading the tools is as easy as <code class="highlighter-rouge">brew update && brew upgrade</code>. It also makes installation and upgrade process easier to other people in your organization. And finally, it’s just cool.</p>
<h2 id="ok-lets-brew">OK, Let’s Brew!</h2>
<h3 id="create-formula">Create Formula</h3>
<p>You could use <code class="highlighter-rouge">brew create <link></code> command, but that will create formula in <code class="highlighter-rouge">/usr/local/Library/Formula</code>. Instead let’s create it manually.</p>
<p>Let’s say our company is called i4nApps (I know, it’s a weird name…), so create new Ruby file</p>
<script src="https://gist.github.com/4cb315bccf887a3b825d4ee0cfce2b25.js"> </script>
<p>With contents like this</p>
<script src="https://gist.github.com/842f6d6d003886729e74ed787be353a1.js"> </script>
<p>These are the basics of brewing.</p>
<ul>
<li>Your custom formula class needs to subclass <code class="highlighter-rouge">Formula</code> class.</li>
<li><code class="highlighter-rouge">version</code> in our case is “3.9.0”, that’s the latest Atlassian CLI Client version at the moment of writing this post.</li>
<li><code class="highlighter-rouge">homepage</code> points to <a href="https://marketplace.atlassian.com/plugins/org.swift.atlassian.cli">Atlassian Marketplace page</a>.</li>
<li><code class="highlighter-rouge">url</code> is used to download source code. Note a bit of tweaking at the end of the link <code class="highlighter-rouge">#{version.to_s.delete('.')}</code>, that’s to remove dots.</li>
<li><code class="highlighter-rouge">sha1</code> obviously is SHA-1 calculated for file downloaded from <code class="highlighter-rouge">url</code>.</li>
</ul>
<script src="https://gist.github.com/9038a9b8379caa3877f7126e5e9fec2e.js"> </script>
<ul>
<li><code class="highlighter-rouge">install</code> method is where you do all the installation magic once the source is downloaded and unzipped.</li>
<li><code class="highlighter-rouge">test</code> is used to test formula after installation. Normally you just execute main program installed by the formula, in our case it can be <code class="highlighter-rouge">jira</code>.</li>
</ul>
<p>Now let’s take advantage of the fact that Homebrew formula is just a Ruby class and add few more custom lines to use later.</p>
<script src="https://gist.github.com/1e55d8777bfc4cd0a24532520f57f61e.js"> </script>
<ul>
<li><code class="highlighter-rouge">release</code> will be used for managing multiple releases for same version</li>
<li><code class="highlighter-rouge">java_version</code> will come handy for setting <code class="highlighter-rouge">JAVA_HOME</code> environment variable. Default is “1.6” but you can user <code class="highlighter-rouge">JAVA_VERSION</code> environment variable to override default settings.</li>
</ul>
<blockquote>
<p>Atlassian CLI Client <a href="https://bobswift.atlassian.net/wiki/display/ACLI/Compatibility+-+3.9">Compatibility page</a> claims that “Client requires <strong>Java 1.6</strong> (recommended) or above.” I have had problems using it with Java 1.7, so in this guide we’ll stick with 1.6.</p>
</blockquote>
<h3 id="install"><code class="highlighter-rouge">install</code></h3>
<p>Once execution enters <code class="highlighter-rouge">install</code> method, the source is already downloaded and unzipped. Things that you do in <code class="highlighter-rouge">install</code> method occur in temporary directory created by Homebrew.</p>
<p>This is the place to run things like <code class="highlighter-rouge">./configure</code> and <code class="highlighter-rouge">make</code>. However in our case we have no source code to compile. Atlassian CLI is basically a collection of JAR files with shell wrappers for them.</p>
<p>Our job is to cleanup first, then patch and rename some scripts and finally move the whole bunch to <code class="highlighter-rouge">/usr/local</code>. <code class="highlighter-rouge">/usr/local</code> is also called <em>prefix</em>, this is the location where Homebrew installs all packages, additionally there’s a special <code class="highlighter-rouge">prefix</code> variable available in the formula.</p>
<h4 id="cleanup">Cleanup</h4>
<p>So let’s cleanup. Since we are installing on OS X, we don’t need all the Windows stuff.</p>
<script src="https://gist.github.com/fcd401880dad67677bce81e1ff4dccd9.js"> </script>
<p>As an improvement, this could be a good place to remove examples.</p>
<h4 id="patch-and-move">Patch and Move</h4>
<p>Now it’s the time to mention one of the things done <em>wrong</em> in Atlassian CLI tools package. There’s a reason for having all those folders like <code class="highlighter-rouge">lib</code>, <code class="highlighter-rouge">libexec</code>, <code class="highlighter-rouge">etc</code> and so on. In Homebrew world each of those folders serves a special purpose. Yet the most important folder of all is missing, that is <code class="highlighter-rouge">bin</code>!</p>
<p>Remember that part where you added <code class="highlighter-rouge">/usr/local/bin</code> to your <code class="highlighter-rouge">PATH</code>? When Homebrew installs a package it copies things from temp folder to prefix (<code class="highlighter-rouge">/usr/local</code>), <code class="highlighter-rouge">bin</code> is copied too. Every executable in the <code class="highlighter-rouge">bin</code> becomes available system-wide because of the way you updated <code class="highlighter-rouge">PATH</code>.</p>
<p>In case of Atlassian CLI, all the shell scripts are sitting in the root folder, <code class="highlighter-rouge">bin</code> is not there at all. This needs to be fixed. We will do it in 2 steps</p>
<ul>
<li>Create <code class="highlighter-rouge">bin</code> folder and move scripts to it</li>
<li>Patch the scripts</li>
</ul>
<p>The order doesn’t really matter.
Patching is required because each shell script is a wrapper around JAR file and contains relative path to that JAR. So if you move the shell script, you have to update the relative path as well.</p>
<script src="https://gist.github.com/f38b4000518713a9465b46604436f046.js"> </script>
<p>Here we replace relative path to <code class="highlighter-rouge">lib</code> with <code class="highlighter-rouge">../lib</code>.
We also set <code class="highlighter-rouge">JAVA_HOME</code> here using <code class="highlighter-rouge">java_home</code> OS X utility and <code class="highlighter-rouge">java_version</code> method. This is to be sure Java version is as we expect it.</p>
<script src="https://gist.github.com/309c3c9dfad8f17eef6e4a7535c0e213.js"> </script>
<p>We just moved all the <code class="highlighter-rouge">.sh</code> scripts to <code class="highlighter-rouge">bin</code> folder. I also prefer to drop the <code class="highlighter-rouge">.sh</code> part. Finally <code class="highlighter-rouge">all</code> feels too ambiguous, so rename it to <code class="highlighter-rouge">atlassian-all</code>.</p>
<h4 id="install-to-prefix">Install to Prefix</h4>
<p>We can finally install everything to prefix (<code class="highlighter-rouge">/usr/local</code>), that’s where <code class="highlighter-rouge">prefix</code> variable is used</p>
<script src="https://gist.github.com/0b2c65852c749636679e72beab6be1a0.js"> </script>
<h2 id="customize">Customize</h2>
<p>This part is optional. Unless you customize the scripts you will have to use <code class="highlighter-rouge">--server</code>, <code class="highlighter-rouge">--user</code> and <code class="highlighter-rouge">--password</code> switches each time you call commands, this is to provide server, username and password.</p>
<p>Of course this can be solved with aliases, but then you’d have to configure aliases on each build box. Anyway, the developers of the CLI package offer you another solution. As I said, this part is optional, if you don’t need customization you can skip to <a href="#tap-install">next section</a>.</p>
<p>The <code class="highlighter-rouge">atlassian.sh</code> (which we renamed to <code class="highlighter-rouge">atlassian</code> and moved to <code class="highlighter-rouge">bin</code>) is there for customization. Have a look inside that file</p>
<script src="https://gist.github.com/5c62c231b016b1a6b3950f74c7ca9694.js"> </script>
<p>This is where you can customize your Atlassian products username and password, as well as additional JVM settings. That’s usual practice for organizations, you have a special user account (service account) than can access the whole range of products with single username and password.</p>
<p>And there’s another block of code like this, which is used to customize Atlassian products server urls.</p>
<script src="https://gist.github.com/e7e008ef0b2fd8f5a7d93b690c41e763.js"> </script>
<p>You will need to replace all the <code class="highlighter-rouge">https://***.example.com</code> with your company urls. If you have multiple instances of same product in your organization, you can add another <code class="highlighter-rouge">elif</code> block for that. For example you are in the middle of migration from Confluence server <code class="highlighter-rouge">https://confluence.example.com</code> to a new instance <code class="highlighter-rouge">https://confluence.ni.example.com</code>, for a while you want to be able to use both, so add another block like this</p>
<script src="https://gist.github.com/075a92a78d677b2034bef6c4b2e74ae4.js"> </script>
<p>In this example there won’t be multiple instances for same product, but it would be possible to customize scripts to handle that case as well.</p>
<p>So let’s write some Ruby again. For the company called i4nApps we will create a nested class <code class="highlighter-rouge">I4nAppsEnv</code> that will contain all the company specific environment settings.</p>
<script src="https://gist.github.com/7b998ddd43cea92886540b134503416c.js"> </script>
<p><code class="highlighter-rouge">username</code> and <code class="highlighter-rouge">password</code> methods pick up values from <code class="highlighter-rouge">ATLAS_USERNAME</code> and <code class="highlighter-rouge">ATLAS_PASSWORD</code> environment variables. Set those when running <code class="highlighter-rouge">brew install</code> or <code class="highlighter-rouge">brew upgrade</code>.</p>
<p>Next the <code class="highlighter-rouge">server</code> method returns server url for each product type.</p>
<p>Finally <code class="highlighter-rouge">patch</code> method patches the shell script the way we want it.</p>
<ul>
<li>Replace default username and password with values provided via environment variables</li>
<li>Replace all the server urls with your company urls</li>
</ul>
<p>You have to add one more line to <code class="highlighter-rouge">install</code> method in the formula</p>
<script src="https://gist.github.com/29433d8bbf5565ba81ef3c3363db12ab.js"> </script>
<p>Make sure to put this line <strong>before</strong> <code class="highlighter-rouge">atlassian.sh</code> is moved and renamed.</p>
<blockquote>
<p>The nested class is used because Homebrew only expects one formula file. If you have other files used as an external dependencies, Homebrew will not fetch them from repository when running <code class="highlighter-rouge">tap</code> command.</p>
</blockquote>
<h3 id="push-to-scm">Push to SCM</h3>
<p>We are done with the formula. It’s time now to push it to a repository. Whatever is you favorite SCM - use it. In this example we will use Git repository hosted with Stash. For example</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh://[email protected]/mobile/i4napps-atlassian-cli.git
</code></pre></div></div>
<h2 id="tap-install-and-upgrade"><a name="tap-install"></a>Tap, Install and Upgrade</h2>
<h3 id="tap">Tap</h3>
<p>One of the ways to install Homebrew packages from custom repositories is to use <a href="https://github.com/Homebrew/homebrew/wiki/brew-tap"><em>Taps</em></a>.</p>
<p>There’s a number of rules to follow when creating your taps. That mostly matters if you plan to share this formula with the rest of the world. For internal use in your organization you can neglect some of these rules.</p>
<p>But there’s a trade off as well. Since we didn’t name the tap repository properly, we won’t be able to use tap command like <code class="highlighter-rouge">brew tap username/repository</code>. Instead we will do same actions as <code class="highlighter-rouge">tap</code> does only with few lines of shell script.</p>
<p><code class="highlighter-rouge">brew tap</code> clones the repository from GitHub and puts it into the taps directory. This is how you can do it directly</p>
<script src="https://gist.github.com/b3e342fabd3b135ebbc8054de89d036d.js"> </script>
<h3 id="install-1">Install</h3>
<p>Now you can install, this part is simple</p>
<script src="https://gist.github.com/0dcccc4be0031ea03636583fe6b298b8.js"> </script>
<h3 id="upgrade">Upgrade</h3>
<p>To upgrade you need to update brew repositories, including the taps, then upgrade the specific package.</p>
<script src="https://gist.github.com/85cef3758ee1469ecd739800516a1f09.js"> </script>
<p><a name="tldr"></a></p>
<h1 id="summary">Summary</h1>
<ul>
<li>Create formula Ruby file and put it into a repository</li>
</ul>
<p><a href="https://gist.github.com/mgrebenets/39fe319a2b05d182cbfa">i4napps-atlassian-cli.rb</a></p>
<ul>
<li>Create a Homebrew tap, install and upgrade</li>
</ul>
<script src="https://gist.github.com/14070ba19be8b6af697c5226d6436538.js"> </script>
https://mgrebenets.github.io/atlassian/2014/05/30/atlassian-cli-homebrew
https://mgrebenets.github.io/atlassian/2014/05/30/atlassian-cli-homebrew2014-05-30T00:00:00+00:00Share Xcode Schemes
<p>So you are facing one of these Xcode errors where it tells you that there’s no such scheme? This post could help to explain why Xcode does it and how to solve this problem.</p>
<!--more-->
<h1 id="shared-vs-user-schemes">Shared vs User Schemes</h1>
<p>While setting up build server for iOS app I have faced this issue multitude of times. Xcode schemes can be either shared or not. By default schemes are not shared and are owned by a user that creates them.</p>
<p>Here’s how it looks in Xcode, note the last column with checkboxes.
<img src="https://mgrebenets.github.io/assets/images/schemes-list.png" alt="Manage Schemes" /></p>
<p>If you look inside <code class="highlighter-rouge">kartoteka-reloaded.xcodeproj</code> folder you will see how Xcode stores the schemes.
Here’s how it looks when <code class="highlighter-rouge">kartoteka-reloaded.xcscheme</code> is not shared</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kartoteka-reloaded.xcodeproj/
├── project.pbxproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
├── xcshareddata
│ └── xcschemes
└── xcuserdata
└── grebenetsm.xcuserdatad
└── xcschemes
├── kartoteka-reloaded.xcscheme
└── xcschememanagement.plist
</code></pre></div></div>
<p>Now let’s tick the “Shared” checkbox then list directory contents again</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kartoteka-reloaded.xcodeproj/
├── project.pbxproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
├── xcshareddata
│ └── xcschemes
│ └── kartoteka-reloaded.xcscheme
└── xcuserdata
└── grebenetsm.xcuserdatad
└── xcschemes
└── xcschememanagement.plist
</code></pre></div></div>
<p>Notice how the <code class="highlighter-rouge">kartoteka-reloaded.xcscheme</code> moved from user data folder to shared data folder. This is basically what makes scheme a shared one.</p>
<p>The general practice for Xcode projects <code class="highlighter-rouge">.gitignore</code> file is to ignore user data</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># .gitignore</span>
xcuserdata/
<span class="k">*</span>.xcuserdatad
</code></pre></div></div>
<p>So when you check out source code on a build box, there won’t be any user schemes inside <code class="highlighter-rouge">.xcodeproj</code> folder and <code class="highlighter-rouge">xcodebuild</code> won’t be able to see the schemes and will fail to build them.</p>
<h1 id="solution">Solution</h1>
<p>You can solve this problem either manually or automatically.</p>
<p>Of course you can just talk to devs and ask them to share the scheme. Done!
You can even do this change yourself and create pull request with changes.</p>
<p>But this approach will not work in some cases. For example, if you want to run UI automation tests with Calabash, the steps are</p>
<ul>
<li>Duplicate existing Xcode target and name new test target with <code class="highlighter-rouge">-cal</code> suffix</li>
<li>Add Calabash framework to test target</li>
<li>Build <code class="highlighter-rouge">-cal</code> test target and run tests</li>
</ul>
<p>The first step is done with <code class="highlighter-rouge">calabash-ios setup</code> command. When new target is created a scheme is created for it as well. This is the default setting for all Xcode projects and in this post we’ll assume that’s the way you have it configured as well.</p>
<p>Now the tricky part, it doesn’t matter if original scheme was shared, the new <code class="highlighter-rouge">-cal</code> scheme will not be shared. That means you won’t be able to build it from command line.</p>
<p>Since it all happens on a build box as part of a build plan, you can’t push anything back to the repository, you have to find a way to make this new scheme shared right now.</p>
<p>The answer to your problems comes from Ruby world. In particular the <a href="https://rubygems.org/gems/xcodeproj">xcodeproj</a> Ruby gem. This is an incredibly handy library to work with Xcode projects and workspaces. You can do pretty much anything you need, create and modify targets and schemes, add new files to targets, modify build settings and other properties, and, of course, share schemes. By the way, <code class="highlighter-rouge">xcodeproj</code> is used by <a href="https://github.com/CocoaPods/Xcodeproj">CocoaPods</a> and that says a lot.</p>
<p>Go ahead and install the gem</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span><span class="nb">sudo</span><span class="o">]</span> gem install xcodeproj
</code></pre></div></div>
<p>Now create a simple Ruby file, name it whatever you want</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/env ruby</span>
<span class="c1"># share_schemes.rb</span>
<span class="nb">require</span> <span class="s1">'xcodeproj'</span>
<span class="n">xcproj</span> <span class="o">=</span> <span class="no">Xcodeproj</span><span class="o">::</span><span class="no">Project</span><span class="p">.</span><span class="nf">open</span><span class="p">(</span><span class="s2">"MyProject.xcodeproj"</span><span class="p">)</span>
<span class="n">xcproj</span><span class="p">.</span><span class="nf">recreate_user_schemes</span>
<span class="n">xcproj</span><span class="p">.</span><span class="nf">save</span>
</code></pre></div></div>
<p>This is it! Put your Xcode project name in there, then run and the scheme will be shared.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chmod +x share_schemes.rb
./share_schemes.rb
</code></pre></div></div>
<h1 id="caveats">Caveats</h1>
<p>It sounds to good to be true, right?
There’s a number of situations where sharing a scheme via Ruby script will not work as expected.</p>
<p>If your Xcode project already has a shared scheme, then you will end up having one scheme from user’s data directory and another one form <code class="highlighter-rouge">xcshareddata</code>. Xcode IDE will pick up both and that’s the reason why you see same scheme twice with project name in parentheses.
<img src="https://mgrebenets.github.io/assets/images/duplicated-schemes-list.png" alt="Manage Schemes" /></p>
<p>That’s not very bad and doesn’t normally cause any problems. Until that moment of time when you modify one scheme and forget about another. The best way to avoid this problem is to share schemes from day 1, Xcode will not create user schemes then.</p>
<p>The real trouble begins if you didn’t have any shared schemes and the scheme that you want to recreate and share is linked to a test target. That’s the default configuration for unit tests. So the problem is that <code class="highlighter-rouge">xcodeproj</code> <a href="https://github.com/CocoaPods/Xcodeproj/issues/139">doesn’t recreate dependencies to test target</a>. If you run a <code class="highlighter-rouge">xcodebuild test</code> action you’ll be surprised to see it failing. Unfortunately there isn’t an easy workaround for this problem, so you’d better share those schemes manually and commit changes to source control system.</p>
<h1 id="summary">Summary</h1>
<p>Surely the Ruby script can be improved, you’d want to pass Xcode project name as an argument or even look it up automatically.</p>
<p>As usual, in Summary I just provide file listing with a solution ready to copy-paste. Here’s more advanced Ruby script for your use. You can just get the file directly if you’d like, <a href="https://gist.github.com/mgrebenets/041a0b61cd5e4aaa9bdd">share-schemes.rb</a></p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/env ruby</span>
<span class="c1"># share_schemes.rb</span>
<span class="nb">require</span> <span class="s1">'optparse'</span>
<span class="nb">require</span> <span class="s1">'ostruct'</span>
<span class="nb">require</span> <span class="s1">'rubygems'</span>
<span class="nb">require</span> <span class="s1">'xcodeproj'</span>
<span class="nb">require</span> <span class="s1">'colorize'</span>
<span class="nb">require</span> <span class="s1">'fileutils'</span>
<span class="c1"># Option parser</span>
<span class="k">class</span> <span class="nc">OptionParser</span>
<span class="c1"># Parse options</span>
<span class="c1"># @param [Array<String>] args command line args</span>
<span class="c1"># @return [OpenStruct] parsed options</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">parse</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
<span class="n">options</span> <span class="o">=</span> <span class="no">OpenStruct</span><span class="p">.</span><span class="nf">new</span>
<span class="n">options</span><span class="p">.</span><span class="nf">project</span> <span class="o">=</span> <span class="kp">nil</span>
<span class="n">opt_parser</span> <span class="o">=</span> <span class="no">OptionParser</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span> <span class="o">|</span><span class="n">opts</span><span class="o">|</span>
<span class="n">opts</span><span class="p">.</span><span class="nf">banner</span> <span class="o">=</span> <span class="s2">"Usage: </span><span class="si">#{</span><span class="no">File</span><span class="p">.</span><span class="nf">basename</span><span class="p">(</span><span class="vg">$0</span><span class="p">)</span><span class="si">}</span><span class="s2"> [options]"</span>
<span class="n">opts</span><span class="p">.</span><span class="nf">separator</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
<span class="n">opts</span><span class="p">.</span><span class="nf">on</span><span class="p">(</span><span class="s1">'-p [PROJECT]'</span><span class="p">,</span> <span class="s1">'--project [PROJECT]'</span><span class="p">,</span> <span class="s2">"Xcode project path. Automatically look up if not provided."</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">project</span><span class="o">|</span>
<span class="n">options</span><span class="p">.</span><span class="nf">project</span> <span class="o">=</span> <span class="n">project</span>
<span class="k">end</span>
<span class="n">opts</span><span class="p">.</span><span class="nf">separator</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
<span class="n">opts</span><span class="p">.</span><span class="nf">separator</span><span class="p">(</span><span class="s2">"Help:"</span><span class="p">)</span>
<span class="n">opts</span><span class="p">.</span><span class="nf">on_tail</span><span class="p">(</span><span class="s1">'-h'</span><span class="p">,</span> <span class="s1">'--help'</span><span class="p">,</span> <span class="s1">'Display this help'</span><span class="p">)</span> <span class="k">do</span>
<span class="nb">puts</span> <span class="n">opts</span>
<span class="nb">exit</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">opt_parser</span><span class="p">.</span><span class="nf">parse!</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
<span class="n">options</span>
<span class="k">end</span> <span class="c1"># parse()</span>
<span class="k">end</span>
<span class="n">options</span> <span class="o">=</span> <span class="no">OptionParser</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="no">ARGV</span><span class="p">)</span>
<span class="c1"># Lookup for Xcode project other than Pods</span>
<span class="c1"># @return [String] name of Xcode project or nil if not found</span>
<span class="k">def</span> <span class="nf">lookup_project</span>
<span class="nb">puts</span> <span class="s2">"Looking for Xcode project..."</span>
<span class="c1"># list all .xcodeproj files except Pods</span>
<span class="n">projects_list</span> <span class="o">=</span> <span class="no">Dir</span><span class="p">.</span><span class="nf">entries</span><span class="p">(</span><span class="s2">"."</span><span class="p">).</span><span class="nf">select</span> <span class="p">{</span> <span class="o">|</span><span class="n">f</span><span class="o">|</span> <span class="p">(</span><span class="n">f</span><span class="p">.</span><span class="nf">end_with?</span> <span class="s2">".xcodeproj"</span><span class="p">)</span> <span class="o">&&</span> <span class="p">(</span><span class="n">f</span> <span class="o">!=</span> <span class="s2">"Pods.xcodeproj"</span><span class="p">)</span> <span class="p">}</span>
<span class="n">projects_list</span><span class="p">.</span><span class="nf">empty?</span> <span class="p">?</span> <span class="kp">nil</span> <span class="p">:</span> <span class="n">projects_list</span><span class="p">.</span><span class="nf">first</span>
<span class="k">end</span>
<span class="c1"># lookup if not specificed</span>
<span class="n">options</span><span class="p">.</span><span class="nf">project</span> <span class="o">=</span> <span class="n">lookup_project</span> <span class="k">if</span> <span class="o">!</span><span class="n">options</span><span class="p">.</span><span class="nf">project</span>
<span class="k">if</span> <span class="o">!</span><span class="n">options</span><span class="p">.</span><span class="nf">project</span> <span class="k">then</span>
<span class="nb">puts</span> <span class="s2">"Error"</span><span class="p">.</span><span class="nf">red</span><span class="p">.</span><span class="nf">underline</span> <span class="o">+</span> <span class="s2">": No Xcode projects found in the working folder"</span>
<span class="nb">exit</span> <span class="mi">1</span>
<span class="k">end</span>
<span class="nb">puts</span> <span class="s2">"Using project path: "</span> <span class="o">+</span> <span class="s2">"</span><span class="si">#{</span><span class="n">options</span><span class="p">.</span><span class="nf">project</span><span class="si">}</span><span class="s2">"</span><span class="p">.</span><span class="nf">green</span>
<span class="n">xcproj</span> <span class="o">=</span> <span class="no">Xcodeproj</span><span class="o">::</span><span class="no">Project</span><span class="p">.</span><span class="nf">open</span><span class="p">(</span><span class="n">options</span><span class="p">.</span><span class="nf">project</span><span class="p">)</span>
<span class="n">xcproj</span><span class="p">.</span><span class="nf">recreate_user_schemes</span>
<span class="n">xcproj</span><span class="p">.</span><span class="nf">save</span>
</code></pre></div></div>
<p>Right, this is one of those cases where actual meaningful code is very small (just 4 lines), the rest is options parsing and error checking, but then it’s worth it in the end.</p>
<p>Finally run it</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chmod +x share_schemes.rb
./share_schemes.rb <span class="nt">-p</span> <span class="s2">"MyProject.xcodeproj"</span>
</code></pre></div></div>
<h2 id="ps">P.S.</h2>
<p><a href="http://stackoverflow.com/questions/14368938/xcodebuild-says-does-not-contain-scheme">Related thread</a> on StackOverflow.</p>
https://mgrebenets.github.io/xcode/2014/05/29/share-xcode-schemes
https://mgrebenets.github.io/xcode/2014/05/29/share-xcode-schemes2014-05-29T00:00:00+00:00Build Android in the Cloud
<p>In this example, you are given a task to build Android app on a 64-bit AWS Linux build agent running in Amazon Cloud (AWS).</p>
<!--more-->
<h1 id="install-android-sdk">Install Android SDK</h1>
<p>You have to start with installing Android SDK first.</p>
<h2 id="download">Download</h2>
<p>Start with downloading latest Linux version, found on <a href="https://developer.android.com/sdk/index.html">this page</a>. You can find direct link to tarball in “DOWNLOAD FOR OTHER PLATFORMS” section.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>wget http://dl.google.com/android/android-sdk_r22.6.2-linux.tgz
</code></pre></div></div>
<h2 id="extract-and-move">Extract and Move</h2>
<p>Extract it and put in preferred location, in this example it’s <code class="highlighter-rouge">/usr/local/opt/android-sdk</code></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Extract.</span>
<span class="nb">tar </span>xzf android-sdk_r22.6.2-linux.tgz
<span class="c"># Move.</span>
mv android-sdk-linux /usr/local/opt/android-sdk
</code></pre></div></div>
<h2 id="configure-path">Configure <code class="highlighter-rouge">PATH</code></h2>
<p>Now configure <code class="highlighter-rouge">ANDROID_HOME</code> and update the path. That is done by modifying <code class="highlighter-rouge">~/.bash_profile</code>, create the file if you don’t have it yet.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">export </span><span class="nv">ANDROID_HOME</span><span class="o">=</span>/usr/local/opt/android-sdk
<span class="nb">export </span><span class="nv">PATH</span><span class="o">=</span><span class="nv">$PATH</span>:<span class="nv">$ANDROID_HOME</span>/tools
<span class="nb">export </span><span class="nv">PATH</span><span class="o">=</span><span class="nv">$PATH</span>:<span class="nv">$ANDROID_HOME</span>/platform-tools
<span class="k">if</span> <span class="o">[[</span> <span class="nt">-d</span> <span class="nv">$ANDROID_HOME</span>/build-tools <span class="o">]]</span><span class="p">;</span> <span class="k">then
</span><span class="nv">ANDROID_BUILD_TOOLS_HOME</span><span class="o">=</span><span class="k">$(</span>dirname <span class="k">$(</span>find <span class="nv">$ANDROID_HOME</span>/build-tools <span class="nt">-name</span> aapt | tail <span class="nt">-1</span><span class="k">))</span>
<span class="nb">echo</span> <span class="s2">"Android Built Tools located: </span><span class="nv">$ANDROID_BUILD_TOOLS_HOME</span><span class="s2">"</span>
<span class="nb">export </span><span class="nv">PATH</span><span class="o">=</span><span class="nv">$ANDROID_BUILD_TOOLS_HOME</span>:<span class="nv">$PATH</span>
<span class="k">fi</span>
</code></pre></div></div>
<p>You noticed that adding Android Build Tools to the path is optional. That’s because we didn’t install Build Tools yet.</p>
<h2 id="update-android-sdk">Update Android SDK</h2>
<p>This is where you update Android SDK, install all the tools and APIs, including Build Tools and Android Support Repository and Library. Remember, this Linux instance is running in the AWS Cloud meaning it’s headless (no GUI) and you only can work with the shell.</p>
<p>If you happened to read older version of this article, you’d remember seeing a lot of shell scripts using <code class="highlighter-rouge">grep</code>.</p>
<p>This is a revised version, with much simpler and cleaner code.</p>
<p>The command that does the job is <code class="highlighter-rouge">android update sdk</code>. You need to use <code class="highlighter-rouge">--filter</code> option to specify list of packages you need to update or install. To get readable identifiers of all available packages, run the following command</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>android list sdk <span class="nt">--all</span> <span class="nt">--extended</span>
</code></pre></div></div>
<p><code class="highlighter-rouge">--extended</code> flag is used to display extended information about each package, including a human readable identifier. <code class="highlighter-rouge">--all</code> is needed to include extra packages, like build tools, by default they won’t be listed. Here’s an example output.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">----------</span>
id: 3 or <span class="s2">"build-tools-20.0.0"</span>
Type: BuildTool
Desc: Android SDK Build-tools, revision 20
<span class="nt">----------</span>
id: 4 or <span class="s2">"build-tools-19.1.0"</span>
Type: BuildTool
Desc: Android SDK Build-tools, revision 19.1
<span class="nt">----------</span>
</code></pre></div></div>
<p>You can now compose filter as a comma-separated list of all package identifiers you want to install. Since it’s a headless build box, you will have to use <code class="highlighter-rouge">--no-ui</code> option, and <code class="highlighter-rouge">--all</code> is needed to include extra packages.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">FILTER</span><span class="o">=</span>tool,platform,android-20,build-tools-20.0.0,android-19,android-19.0.1
android update sdk <span class="nt">--no-ui</span> <span class="nt">--all</span> <span class="nt">--filter</span> <span class="nv">$FILTER</span>
</code></pre></div></div>
<p>This example installs <em>Android SDK Tools</em>, <em>Platform tools</em>, <em>Build tools</em> versions <em>20.0.0</em> and <em>19.0.1</em>, as well as <em>SDK Platform 19</em> and <em>20</em>. Customize the list to your needs using proper identifiers.</p>
<h3 id="answering-the-prompts">Answering the Prompts</h3>
<p>But it’s not done yet. When installing or updating, you will have to accept license prompts. Each package can have it’s own license requiring you to answer a prompt with “y”.</p>
<p>You’d probably think of <code class="highlighter-rouge">yes</code> command line utility designed for this particular task. However it will not work. <code class="highlighter-rouge">yes</code> outputs “y” to stdout too often with no options to put delays in between. Android SDK update tool expects not just “y”, but a “y” followed by return key, in other words, it expects “y\n” string as a whole. I don’t know the exact mechanics of <code class="highlighter-rouge">yes</code> command, but if you try something like this</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">FILTER</span><span class="o">=</span>tool,platform,android-20,build-tools-20.0.0,android-19,android-19.0.1
yes | android update sdk <span class="nt">--no-ui</span> <span class="nt">--all</span> <span class="nt">--filter</span> <span class="nv">$FILTER</span>
</code></pre></div></div>
<p>you will see that the license prompt will complain about incorrect input and fail after a number of attempts.</p>
<p>The solution is to put certain delay between “y” outputs to stdout. This code I found on the web, it’s reliable and does the job.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">FILTER</span><span class="o">=</span>tool,platform,android-20,build-tools-20.0.0,android-19,android-19.0.1
<span class="o">(</span> sleep 5 <span class="o">&&</span> <span class="k">while</span> <span class="o">[</span> 1 <span class="o">]</span><span class="p">;</span> <span class="k">do </span>sleep 1<span class="p">;</span> <span class="nb">echo </span>y<span class="p">;</span> <span class="k">done</span> <span class="o">)</span> <span class="se">\</span>
| android update sdk <span class="nt">--no-ui</span> <span class="nt">--all</span> <span class="se">\</span>
<span class="nt">--filter</span> <span class="k">${</span><span class="nv">FILTER</span><span class="k">}</span>
</code></pre></div></div>
<h3 id="project-specific-sdk-update">Project Specific SDK Update</h3>
<p>If you have various Android projects, each with it’s own requirements for Android packages, it would be reasonable to add Android SDK update task to the project’s build configuration. In this example I will use Gradle, so here’s an example of Gradle task</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>task updateSDK<span class="o">(</span><span class="nb">type</span>: Exec<span class="o">)</span> <span class="o">{</span>
ext.filter <span class="o">=</span> <span class="s2">"tool,platform-tool,android-20,build-tools-20.0.0,android-19,build-tools-19.1.0,build-tools-19.0.1,extra-android-support,extra-android-m2repository,extra-google-m2repository,extra-google-google_play_services,extra-google-google_play_services_froyo"</span>
commandLine <span class="s2">"sh"</span>, <span class="s2">"-c"</span>, <span class="s2">"( sleep 5 && while [ 1 ]; do sleep 1; echo y; done ) </span><span class="se">\</span><span class="s2">
| android update sdk --no-ui --all </span><span class="se">\</span><span class="s2">
--filter </span><span class="k">${</span><span class="nv">filter</span><span class="k">}</span><span class="s2">"</span>
<span class="o">}</span>
</code></pre></div></div>
<h3 id="caveats">Caveats</h3>
<p>The last and very annoying bit, is that this script seems to update packages even if they are already installed. At the moment I have no clue what’s causing this behavior and what’s the best workaround. When it comes to running this script on one of the Bamboo agents in the cloud it doesn’t really matter, but when the script runs on one and only Mac build agent you have - this really slows down each build.</p>
<h1 id="install-32-bit-libraries">Install 32-bit Libraries</h1>
<p>Before you try to build anything, you have to do one more thing.</p>
<p>Remember, the host OS is 64-bit Linux system. Android requires a bunch of 32-bit libraries and you have to install them. The Linux system in question is RPM-based so this example uses <code class="highlighter-rouge">yum</code> command, change it to <code class="highlighter-rouge">apt-get</code> or another package manager specific for your OS.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Install 32-bit libraries.</span>
<span class="nb">sudo </span>yum install glibc.i686, zlib.i686, libstdc++.so.6 libz.so.1
</code></pre></div></div>
<p>Now you’re good to go!</p>
<h1 id="summary">Summary</h1>
<p>This is a TLDR or a summary section, that simply lists the solution “as is”.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Install 32-bit libraries.</span>
<span class="nb">sudo </span>yum install glibc.i686, zlib.i686, libstdc++.so.6 libz.so.1
</code></pre></div></div>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Update Android SDK on headless server.</span>
<span class="nv">FILTER</span><span class="o">=</span>tool,platform,android-20,build-tools-20.0.0,android-19,android-19.0.1
<span class="o">(</span> sleep 5 <span class="o">&&</span> <span class="k">while</span> <span class="o">[</span> 1 <span class="o">]</span><span class="p">;</span> <span class="k">do </span>sleep 1<span class="p">;</span> <span class="nb">echo </span>y<span class="p">;</span> <span class="k">done</span> <span class="o">)</span> <span class="se">\</span>
| android update sdk <span class="nt">--no-ui</span> <span class="nt">--all</span> <span class="se">\</span>
<span class="nt">--filter</span> <span class="k">${</span><span class="nv">FILTER</span><span class="k">}</span>
</code></pre></div></div>
https://mgrebenets.github.io/android/2014/05/29/build-android-in-the-cloud
https://mgrebenets.github.io/android/2014/05/29/build-android-in-the-cloud2014-05-29T00:00:00+00:00Atlassian CLI Client
<p>If you happen to use Atlassian products like JIRA, Bamboo, Stash, Confluence, etc., you may be surprised to know that all these products are backed by a handy command line interface, namely <a href="https://bobswift.atlassian.net/wiki/display/ACLI/Atlassian+Command+Line+Interface">Atlassian Command Line Interface</a>.</p>
<!--more-->
<p>Imagine opening, modifying and closing JIRA issues from command line. What about starting Bamboo build plans, opening and closing Stash pull requests, updating Wiki pages?</p>
<p>“Why would I do that?” you would ask. Indeed, there’s not much benefit to automate these things for you as a user, unless you are some bash addict. However, stop for a moment and think “Automation” and you’ll see how many things a basic shell script can do. All you need is Java and shell interpreter, which are present on any decent build box.</p>
<p>Atlassian CLI Client is available on <a href="https://marketplace.atlassian.com/plugins/org.swift.atlassian.cli">Atlassian Marketplace</a>. It is not developed by Atlassian though, which is very important to know if you plan to use it.</p>
<p>This is where the confusion between Atlassian CLI <em>Plugin</em> and Atlassian CLI <em>Client</em> needs to be cleared up.</p>
<p><em>Plugin</em> is <strong>not free</strong> and should be purchased for Atlassian products, e.g. there’s CLI plugin for JIRA, Bamboo, Stash. This basically a UI for command line tools.</p>
<p><em>Client</em> (command line tools) can be freely downloaded and installed. You can find a few outdated Homebrew formulas on GitHub that automate client installation. So you might easily assume that it’s free, but it’s not!</p>
<blockquote>
<p>You must purchase a license at least for one of the Atlassian CLI Plugins in order to use the Client.</p>
</blockquote>
<p>The purpose of this post is to introduce you to Atlassian CLI Plugin if you don’t know about it yet. The plugin is <a href="https://bobswift.atlassian.net/wiki/display/ACLI/Atlassian+CLI+General+Documentation">very</a> <a href="https://bobswift.atlassian.net/wiki/display/ACLI/Installation+and+Use">well</a> <a href="https://bobswift.atlassian.net/wiki/display/ACLI/How+to">documented</a> and comes with tons of <a href="https://bobswift.atlassian.net/wiki/display/ACLI/Examples">examples</a>.</p>
<p>The thing that I didn’t like about it is installation process. It’s a straightforward “download, move, update <code class="highlighter-rouge">PATH</code>” process. There’s nothing bad in the process itself, but when you need to roll out CLI tools on a dozen of build agents, you start looking for a better way.</p>
<p>So I follow up this post with 2 more</p>
<ul>
<li><a href="/atlassian/2014/05/30/atlassian-cli-homebrew">Install Atlassian CLI with Homebrew</a> (OS X)</li>
<li><a href="/atlassian/2014/05/30/atlassian-cli-rpm">Install Atlassian CLI from RPM</a> (Linux)</li>
</ul>
https://mgrebenets.github.io/atlassian/2014/05/29/atlassian-cli
https://mgrebenets.github.io/atlassian/2014/05/29/atlassian-cli2014-05-29T00:00:00+00:00