{"id":813,"date":"2017-08-24T16:39:25","date_gmt":"2017-08-24T16:39:25","guid":{"rendered":"http:\/\/bitcows.com\/?p=813"},"modified":"2017-08-24T16:39:25","modified_gmt":"2017-08-24T16:39:25","slug":"continuous-integration-and-deployment-cicd-for-mobile-apps-appcelerator","status":"publish","type":"post","link":"https:\/\/bitcows.com\/?p=813","title":{"rendered":"Continuous Integration and Deployment (CI\/CD) for mobile apps (Appcelerator)"},"content":{"rendered":"<h1><span>Introduction<\/span><\/h1>\n<p><span>The purpose of this document is to give a step by step approach for installing a continuous integration and continuous build server. This document will cover end to end instructions in getting code from a developer\u2019s environment to the application delivery server for testers to download and test against. This will also include testing the code using the Jasmine test suite and building each platforms ( ipa, .apk) files.<\/span><br \/>\n<b>What this is not<\/b><\/p>\n<ul>\n<li><span>Instructions on how to build a test suite with Jasmine<\/span><\/li>\n<li><span>Recommendation on the type of server configuration such as hardware\/VM requirements (RAM, HD). <\/span><\/li>\n<li><span>Covering unsupported versions, future or past, of the Axway Appcelerator SDK.<\/span><\/li>\n<li><span>Will only cover a basic setup of Jenkins and not a detailed approach to every aspect of the software.<\/span><\/li>\n<li><span>Details on publishing applications to Apple\u2019s App Store or Google Play Store.<\/span><\/li>\n<li><span>Details on how to use Github tokens or webhooks<\/span><\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<h1><span>Required Accounts and Prerequisites<\/span><\/h1>\n<p><span>You will need a valid Apple ID and developer license to install XCode and manage your provisioning files. You also need a valid Axway Appcelerator account to download and install the SDK.<\/span><br \/>\n<span>You will need OS 10.10.X or above running on <\/span><\/p>\n<ul>\n<li><span>Macintosh hardware <\/span><\/li>\n<li><span>Or VM of the Mac OS.<\/span><\/li>\n<\/ul>\n<h1><span>Software<\/span><\/h1>\n<p><span>The following software will be needed on the build server. It is however important that you install them in order. Not installing them in the order specified in this document may cause some issues with user permissions. All versions of the software should be the latest versions available unless specified.<\/span><\/p>\n<ul>\n<li><span>Java 6, 8<\/span><\/li>\n<li><span>Jenkins<\/span><\/li>\n<li><span>Node.js<\/span><\/li>\n<li><span>xCode <\/span><\/li>\n<\/ul>\n<h1><span>Steps<\/span><\/h1>\n<p><span>It is important that these steps are done in order. This will avoid any issues with user permissions regarding Jenkins.<\/span><\/p>\n<h4>Java<\/h4>\n<p><span>Make sure you have these versions of Java installed<\/span><br \/>\n<b>Java 6<\/b><br \/>\n<a href=\"https:\/\/support.apple.com\/kb\/dl1572?locale=en_US\"><span>https:\/\/support.apple.com\/kb\/dl1572?locale=en_US<\/span><\/a><br \/>\n<b>Java 8 se dev<\/b><br \/>\n<a href=\"http:\/\/www.oracle.com\/technetwork\/java\/javase\/downloads\/jdk8-downloads-2133151.html\"><span>http:\/\/www.oracle.com\/technetwork\/java\/javase\/downloads\/jdk8-downloads-2133151.html<\/span><\/a><br \/>\n&nbsp;<\/p>\n<h4>Jenkins setup and user promotion<\/h4>\n<p><span>Download and install, follow set up instructions<\/span><br \/>\n<a href=\"https:\/\/jenkins.io\/download\/\"><span>https:\/\/jenkins.io\/download\/<\/span><\/a><br \/>\n<span>In a command prompt do the following in order to get the initial password<\/span><br \/>\n<code>$ sudo su - Jenkins<\/code><br \/>\n<code>$ cat \/Users\/Shared\/Jenkins\/Home\/secrets\/initialAdminPassword<\/code><br \/>\n<b>Setting up the Jenkins user and promote it to an admin.<\/b><br \/>\n<span>Make the Jenkins user automatically login when the computer is restarted:<\/span><\/p>\n<ol>\n<li><span>Go to System Preferences\\Users &amp; Groups.<\/span><\/li>\n<li><span>Unlock the settings by clicking the lock in the bottom left corner of the page and entering the login password for the current user.<\/span><\/li>\n<p>   <img decoding=\"async\" src=\"http:\/\/bitcows.com\/wp-content\/uploads\/2017\/08\/Picture1-300x219.png\" alt=\"\" width=\"300\"\/><\/p>\n<li><span>Select the Jenkins user from the list of users. Note: On our install, the Jenkins user shows up as empty in the list of available users. To fix this, right-click the empty user and select Advanced Options\u2026 which will show you details on the user. Set the Full Name to Jenkins and press OK.<\/span><\/li>\n<p>   <img decoding=\"async\" src=\"http:\/\/bitcows.com\/wp-content\/uploads\/2017\/08\/Picture2-300x245.png\" alt=\"\" width=\"300\"\/>\n<\/ol>\n<p><span>Give it a full name.<\/span><\/p>\n<ol>\n   <img decoding=\"async\" src=\"http:\/\/bitcows.com\/wp-content\/uploads\/2017\/08\/Picture3-300x126.png\" alt=\"\" width=\"300\"\/><\/p>\n<li><span>Click Reset Password. Create a new password for the Jenkins user, and make sure to take note of it somewhere secure. This is just like any other Mac user login that has admin access, and should be treated as such. <\/span><\/li>\n<li><span>Select Login Options underneath the list of users.<\/span><\/li>\n<p>   <img decoding=\"async\" src=\"http:\/\/bitcows.com\/wp-content\/uploads\/2017\/08\/Picture4-300x218.png\" alt=\"\" width=\"300\"\/><\/p>\n<li><span> Select Automatic login and choose Jenkins.<\/span><\/li>\n<li><span> Enter the password you just created for the new Jenkins user.<\/span><\/li>\n<li><span> Restart your computer. Once finished, you should be automatically logged in as the OSX Jenkins user.<\/span><\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<h4>Allow Jenkins to Run GUI Applications<\/h4>\n<p><span>By default, Jenkins is unable to run GUI applications because it runs as a <\/span><a href=\"http:\/\/en.wikipedia.org\/wiki\/Daemon_(computing)\"><span>Daemon<\/span><\/a><span>. A daemon runs in the background as part of the overall system, and isn\u2019t tied to a specific user. This would be like having a butler that couldn\u2019t interact with anyone. Sure it could clean up after us, but what about answering the door or fetching my martini!<\/span><br \/>\n<span>A big part of CI is running simulators and other GUI applications, so we\u2019ll need another option. To fix this, you can change Jenkins to run as a Launch Agent. A launch agent runs in the background on behalf of a user.<\/span><br \/>\n&nbsp;<br \/>\n<span>To change how the Jenkins process is launched, you\u2019ll need to edit the settings file and change its location so it will automatically start on reboots.<\/span><br \/>\n&nbsp;<br \/>\n<span>Enter the following command to unload Jenkins as a Daemon:<\/span> <span><code>$ sudo launchctl unload \/Library\/LaunchDaemons\/org.jenkins-ci.plist<\/code><\/span><br \/>\n&nbsp;<br \/>\n<span>Next, move the. plist file, which defines how Jenkins will run, to the LaunchAgents folder:<\/span> <span><code>$ sudo mv \/Library\/LaunchDaemons\/org.jenkins-ci.plist \/Library\/LaunchAgents\/<\/code><\/span><br \/>\n&nbsp;<br \/>\n<span>The default .plist file that Jenkins creates adds a key-value pair called SessionCreate. This creates issues when running certain applications, such as iOS simulators. The reason for this? Honestly, I\u2019m not sure. In the past, a fix to many Jenkins CI issues in the iOS world was to add this key manually. It seems that with Xcode 6 things have reversed and it\u2019s now required that you remove the key which solves the issue. Open the file with the editor of your choosing, and remove them.<\/span><br \/>\n&nbsp;<br \/>\n<span><code>$ sudo vim \/Library\/LaunchAgents\/org.jenkins-ci.plist<\/code><\/span><br \/>\n&nbsp;<\/p>\n<pre class=\"prettyprint\">\/* Remove the following lines *\/\n&lt;key&gt;SessionCreate&lt;\/key\n&lt;true \/&gt;\n\/* Save the file *\/<\/pre>\n<p><span>Lastly, reload the Launch Agent to restart Jenkins.<\/span><br \/>\n<span><code>$ sudo launchctl load \/Library\/LaunchAgents\/org.jenkins-ci.plist<\/code><\/span><br \/>\n<b>Keep Those Fingers Crossed<\/b><br \/>\n<img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/bitcows.com\/wp-content\/uploads\/2017\/08\/Picture5.png\" alt=\"\" width=\"128\" height=\"128\"\/><br \/>\n<span>Now, restart your computer and make sure that Jenkins successfully starts on its own after the reboot. If working correctly, your Mac should automatically login to the Jenkins user.<\/span><\/p>\n<h4><b>Login as Jenkins user<\/b><\/h4>\n<h4><b>Install xCode from App Store <span>(* Run once after install to finalize install)<\/span><\/b><\/h4>\n<h4>Install Node.js<\/h4>\n<p><a href=\"https:\/\/nodejs.org\/en\/\"><span>https:\/\/nodejs.org\/en\/<\/span><\/a><\/p>\n<h4><b>Install Appcelerator cli<\/b><\/h4>\n<p><span><code>$ sudo npm install appcelerator -g<\/code><\/span><br \/>\n<span>&#8211; Update Appc to install latest version<\/span><br \/>\n<span><code>$ appc init <\/code><\/span><\/p>\n<h4><b>Install Titanium<\/b><\/h4>\n<p><span><code>$ npm install titanium -g<\/code><\/span><br \/>\n<span><code>$ appc ti sdk install<\/code><\/span><\/p>\n<h4><b>Install Android<\/b><\/h4>\n<p><span>Download android tools <\/span><br \/>\n<a href=\"https:\/\/developer.android.com\/studio\/index.html\"><span>https:\/\/developer.android.com\/studio\/index.html<\/span><\/a><br \/>\n<span>Download platform tools <\/span><br \/>\n<a href=\"https:\/\/developer.android.com\/studio\/releases\/platform-tools.html\"><span>https:\/\/developer.android.com\/studio\/releases\/platform-tools.html<\/span><\/a><br \/>\n<span>Download NDK <\/span><br \/>\n<a href=\"https:\/\/developer.android.com\/ndk\/downloads\/index.html\"><span>https:\/\/developer.android.com\/ndk\/downloads\/index.html<\/span><\/a><br \/>\n&nbsp;<br \/>\n<span>Create directory and unzip the tools into the android-sdk-macosx folder<\/span><br \/>\n<span><code>$ mkdir \/Users\/Shared\/Jenkins\/Library\/android-sdk-macosx<\/code><\/span><br \/>\n<span><code>$ cd \/Users\/Shared\/Jenkins\/Library\/android-sdk-macosx<\/code><\/span><br \/>\n<span>To install the latest Android SDK <\/span><br \/>\n<span><code>$ titanium setup android<\/code><\/span><br \/>\n<span>Use Paths when asked <\/span><br \/>\n<span>\/Users\/Shared\/Jenkins\/Library\/android-sdk-macosx<\/span><br \/>\n<span>\/Users\/Shared\/Jenkins\/Library\/android-sdk-macosx\/[NDK FOLDER NAME]<\/span><br \/>\n&nbsp;<br \/>\n<span>NOTE: When you do your first build, and hyperloop error, fix it by creating a new project on the build server with hyperloop to install modules then just delete it. <\/span><span><code>$ appc new<\/code><\/span><br \/>\n&nbsp;<br \/>\n<span>If you get the error file already exists symlink, delete the build folder <\/span><br \/>\n&nbsp;<br \/>\n<span>Install android SDK build tools (use latest) <\/span><br \/>\n&nbsp;<br \/>\n<span>(<\/span><b>example:<\/b> <span><code>$ .\/sdkmanager \"build-tools;26.0.1\u201d<\/code>) <\/span><br \/>\n&nbsp;<br \/>\n<span>Install platform 23<\/span><i><span> (optional but may be needed)<\/span><\/i><span><br \/>\n<\/span><span><code>$ .\/sdkmanager \"platforms;android-23\"<\/code><\/span><br \/>\n&nbsp;<\/p>\n<h4><b>Jenkins Setup<\/b><\/h4>\n<p><span>Login with your credentials<\/span><\/p>\n<ul>\n<li><span>Under <\/span><b><i>Manage Jenkins<\/i><\/b><span> set up SCM (e.x. github) hooks <\/span><\/li>\n<p>   <img decoding=\"async\" src=\"http:\/\/bitcows.com\/wp-content\/uploads\/2017\/08\/Picture6-216x300.png\" alt=\"\" width=\"216\"\/><\/p>\n<li><span>Generate a new job <\/span><i><span>(see Jenkins doc for details)<\/span><\/i><\/li>\n<li><span>Point to your build script <\/span><\/li>\n<\/ul>\n<pre class=\"prettyprint\">#!\/bin\/bash\nsource \/Users\/Shared\/Jenkins\/Documents\/jenkins.sh<\/pre>\n<p><img decoding=\"async\" src=\"http:\/\/bitcows.com\/wp-content\/uploads\/2017\/08\/Picture7-300x134.png\" alt=\"\" width=\"300\"\/><br \/>\n<span>Add build script and set permissions <\/span><span><code>$ chmod +x \/Users\/Shared\/Jenkins\/Documents\/jenkins.sh<\/code><\/span><span>  <\/span><span><\/span><\/p>\n<p><b>Example script jenkins.sh<\/b><\/p>\n<pre class=\"prettyprint\">\n#!\/bin\/bash\necho \"pulling latest\"\ngit -C \/Users\/Shared\/Jenkins\/Documents\/AutomatedBuildTest pull\nexport PATH=\"\/usr\/local\/bin:${PATH}\"\njasmine-node \/Users\/Shared\/Jenkins\/Documents\/AutomatedBuildTest\/spec\/jasmine_examples\/PlayerSpec.js\n\n#BUILDS AND DEPLOYS ANDROID .apk\n# appc run -p android -T dist-playstore [-K &lt;KEYSTORE_FILE&gt; -P &lt;KEYSTORE_PASSWORD&gt; -L &lt;KEYSTORE_ALIAS&gt; -O &lt;OUTPUT_DIRECTORY&gt;]\nappc run -d \/Users\/Shared\/Jenkins\/Documents\/AutomatedBuildTest -p android -T dist-playstore -K ~\/.android\/android.keystore -P ****** -O ~\/Desktop -b --app-preview --release-notes='Automated Build Android' --invite=dmason@axway.com --notify='Devs,QA'\n\n#BUILDS AND DEPLOYS IOS .ipa\n# NOTE RUN $ appc info to get the ids for provision file, and cert\n#appc run -p ios -T dist-adhoc [-R &lt;DISTRIBUTION_CERTIFICATE_NAME&gt; -P &lt;PROVISIONING_PROFILE_UUID&gt; -O &lt;OUTPUT_DIRECTORY&gt;]\nappc run -d \/Users\/Shared\/Jenkins\/Documents\/AutomatedBuildTest -p ios -T dist-adhoc -R \u2018Axway Software\u2019 -P \u2018c11b6587-ddc1-421d-a209-4f1893110054\u2019 -O ~\/Desktop -b --app-preview --release-notes='Automated Build iOS' --invite=dmason@axway.com --notify='Devs,QA\u2019<\/pre>\n<h4>Github<\/h4>\n<ul>\n<li><span>Generate <\/span><i><span>personal access token<\/span><\/i><span> and set up webhooks url <\/span><\/li>\n<li><span>Clone project to shared location <\/span><span><code>$ cd \/Users\/Shared\/Jenkins\/Documents\/<\/code><\/span><\/li>\n<li>Clone project <code>$ git clone [YOUR PROJECT URL]<\/code><br \/>\n      (example <code>$ git clone https:\/\/github.com\/djmason9\/AutomatedBuildTest.git<\/code>)\n   <\/li>\n<\/ul>\n<h4>Jenkins Freestyle Project Setup<\/h4>\n<p><span>Create a New Item in Jenkins<\/span><br \/>\n<span>Select Freestyle project<\/span><br \/>\n<span>Point to your project <\/span><br \/>\n<img decoding=\"async\" src=\"http:\/\/bitcows.com\/wp-content\/uploads\/2017\/08\/Picture8-300x183.png\" alt=\"\" width=\"300\"\/><br \/>\n&nbsp;<br \/>\n<span>Add your repository link <\/span><br \/>\n<img decoding=\"async\" src=\"http:\/\/bitcows.com\/wp-content\/uploads\/2017\/08\/Picture9-300x98.png\" alt=\"\" width=\"300\"\/><br \/>\n&nbsp;<br \/>\n<span>Set up your hooks <\/span><br \/>\n<img decoding=\"async\" src=\"http:\/\/bitcows.com\/wp-content\/uploads\/2017\/08\/Picture10-300x182.png\" alt=\"\" width=\"300\" \/><br \/>\n&nbsp;<\/p>\n<h4>Jasmine-node<\/h4>\n<p><span>Install Jasmin and Jasmin-node globally<\/span><br \/>\n<span><code>$ npm install -g jasmine<\/code><\/span><br \/>\n<span><code>$ npm install -g jasmine-node<\/code><\/span><\/p>\n<h4>Android adhoc setup<\/h4>\n<p><b>Create key store for Android<\/b><span><br \/>\n<code>$ mkdir ~\/.android<\/code><br \/>\n<code>$ keytool -genkeypair -v -keystore path\/file_name -alias alias_name -keyalg RSA -sigalg SHA1withRSA -validity 10000<\/code><br \/>\n(<strong>example<\/strong>: <code>$ keytool -genkeypair -v -keystore ~\/.android\/android.keystore -alias testingKey -keyalg RSA -sigalg SHA1withRSA -validity 10000<\/code>)<br \/>\ncheck key<br \/>\n<code>$ keytool -list -v -keystore path\/file_name<\/code><br \/>\n(<strong>example<\/strong>: <code>$ keytool -list -v -keystore ~\/.android\/android.keystore<\/code> )<br \/>\nBuild packages<br \/>\n<code>$ touch ~\/.android\/repositories.cfg<\/code><br \/>\n<code>$ cd ~\/Library\/android-sdk-macosx\/tools\/bin<\/code><br \/>\n<code>$ .\/sdkmanager \"system-images;android-23;google_apis;x86\"<\/code><br \/>\nBuild Android APK file (should be in script)<br \/>\n<code>$ cd \/Users\/Shared\/Jenkins\/Documents\/[YOUR PROJECT]<\/code><br \/>\n(<strong>example<\/strong>: <code>$ cd \/Users\/Shared\/Jenkins\/Documents\/AutomatedBuildTest<\/code>)<br \/>\n<code><br \/>\n   $ appc run -p android -T dist-playstore [-K &lt;KEYSTORE_FILE&gt; -P &lt;KEYSTORE_PASSWORD&gt; -L &lt;KEYSTORE_ALIAS&gt; -O<br \/>\n   <OUTPUT_DIRECTORY><br \/>\n   ]<br \/>\n<\/code><br \/>\n( <strong>example<\/strong> :  <code>$ appc run -p android -T dist-playstore -K ~\/.android\/android.keystore -P ******* -O ~\/Desktop<\/code>) <\/p>\n<h4>iOS<\/h4>\n<p><b>Create a Distribution certificate for your build machine. <\/b><br \/>\n<span>Create a CSR file.<\/span><br \/>\n<span>In the Applications folder on your Mac, open the Utilities folder and launch Keychain Access.<\/span><br \/>\n<span>Within the Keychain Access drop down menu, select<\/span><b><i> Keychain Access &gt; Certificate Assistant &gt; Request a Certificate from a Certificate Authority.<\/i><\/b><\/p>\n<ul>\n<li><span>In the Certificate Information window, enter the following information:<\/span><\/li>\n<li><span>In the User Email Address field, enter your email address.<\/span><\/li>\n<li><span>In the Common Name field, create a name for your private key (e.g., John Doe Dev Key).<\/span><\/li>\n<li><span>The CA Email Address field should be left empty.<\/span><\/li>\n<li><span>In the &#8220;Request is&#8221; group, select the &#8220;Saved to disk&#8221; option.<\/span><\/li>\n<li><span>Click Continue within Keychain Access to complete the CSR generating process.<\/span><\/li>\n<p>   <img decoding=\"async\" src=\"http:\/\/bitcows.com\/wp-content\/uploads\/2017\/08\/Picture11-300x216.png\" alt=\"\" width=\"300\"\/>\n<\/ul>\n<p>&nbsp;<br \/>\n<b>Create a new iOS Certificate<\/b><span> for the build machine using your newly created <\/span><br \/>\n<img decoding=\"async\" src=\"http:\/\/bitcows.com\/wp-content\/uploads\/2017\/08\/Picture12-300x216.png\" alt=\"\" width=\"300\" \/><br \/>\n&nbsp;<br \/>\n<span>Download and add to your keychain login <\/span><br \/>\n<img decoding=\"async\" src=\"http:\/\/bitcows.com\/wp-content\/uploads\/2017\/08\/Picture13-300x190.png\" alt=\"\" width=\"300\"\/><br \/>\n&nbsp;<br \/>\n<b>Create a new App Id<\/b><span> (if you haven\u2019t already) <\/span><br \/>\n<img decoding=\"async\" src=\"http:\/\/bitcows.com\/wp-content\/uploads\/2017\/08\/Picture14-300x262.png\" alt=\"\" width=\"300\"\/><br \/>\n&nbsp;<br \/>\n<span>Create a new adHoc Provisioning Profile (if you haven\u2019t already) <\/span><br \/>\n<img decoding=\"async\" src=\"http:\/\/bitcows.com\/wp-content\/uploads\/2017\/08\/Picture15-300x141.png\" alt=\"\" width=\"300\"\/><br \/>\n&nbsp;<\/p>\n<h4>xCode (in order to grab all your provision files)<\/h4>\n<ul>\n<li><span>Log into Xcode and download provision file. <\/span><\/li>\n<li><span>To check that they are installed run <\/span><span><code>$ appc info<\/code><\/span><\/li>\n<p>   <img decoding=\"async\" src=\"http:\/\/bitcows.com\/wp-content\/uploads\/2017\/08\/Picture16-300x221.png\" alt=\"\" width=\"300\" \/>\n<\/ul>\n<h4>First Build<\/h4>\n<p><span>Before your first build log into appc with command line <\/span><span>$ appc login<\/span><span> follow instructions <\/span><\/p>\n<h4>App Preview<\/h4>\n<p><span>The first time you run the build you might need to manually set up users to notify on subsequent builds. <\/span><\/p>\n<h1><span>Helpful Links<\/span><\/h1>\n<p><b>Command line help for adhoc builds<\/b><b><br \/>\n<\/b><a href=\"http:\/\/docs.appcelerator.com\/platform\/latest\/#!\/guide\/Appcelerator_CLI_Tasks-section-src-43306725_AppceleratorCLITasks-iOSAdHocDistribution\"><span>http:\/\/docs.appcelerator.com\/platform\/latest\/#!\/guide\/Appcelerator_CLI_Tasks-section-src-43306725_AppceleratorCLITasks-iOSAdHocDistribution<\/span><\/a><br \/>\n&nbsp;<br \/>\n<b>App Preview location and documentation<\/b><span><br \/>\n<\/span><a href=\"https:\/\/appbeta.appcelerator.com\/\"><span>https:\/\/appbeta.appcelerator.com\/<\/span><span><br \/>\n<\/span><\/a><a href=\"http:\/\/docs.appcelerator.com\/platform\/latest\/#!\/guide\/App_Preview\"><span>http:\/\/docs.appcelerator.com\/platform\/latest\/ &#8211; !\/guide\/App_Preview<\/span><\/a><br \/>\n&nbsp;<br \/>\n<b>CLI Command Tasks Documentation<\/b><span><br \/>\n<\/span><a href=\"http:\/\/docs.appcelerator.com\/platform\/latest\/#!\/guide\/Appcelerator_CLI_Tasks\"><span>http:\/\/docs.appcelerator.com\/platform\/latest\/ &#8211; !\/guide\/Appcelerator_CLI_Tasks<\/span><span><br \/>\n<\/span><\/a><a href=\"http:\/\/docs.appcelerator.com\/platform\/latest\/#!\/guide\/Appcelerator_Command-Line_Interface_Reference\"><span>http:\/\/docs.appcelerator.com\/platform\/latest\/ &#8211; !\/guide\/Appcelerator_Command-Line_Interface_Reference<\/span><span><br \/>\n<\/span><\/a><a href=\"http:\/\/docs.appcelerator.com\/platform\/latest\/#!\/guide\/Titanium_Command-Line_Interface_Reference\"><span>http:\/\/docs.appcelerator.com\/platform\/latest\/ &#8211; !\/guide\/Titanium_Command-Line_Interface_Reference<\/span><\/a><br \/>\n&nbsp;<br \/>\n<b>Distributing iOS and Android<\/b><b><br \/>\n<\/b><a href=\"http:\/\/docs.appcelerator.com\/platform\/latest\/#!\/guide\/Distributing_iOS_apps\"><span>http:\/\/docs.appcelerator.com\/platform\/latest\/ &#8211; !\/guide\/Distributing_iOS_apps<\/span><span><br \/>\n<\/span><\/a><a href=\"http:\/\/docs.appcelerator.com\/platform\/latest\/#!\/guide\/Distributing_Android_apps\"><span>http:\/\/docs.appcelerator.com\/platform\/latest\/ &#8211; !\/guide\/Distributing_Android_apps<\/span><\/a><br \/>\n&nbsp;<br \/>\n<b>Example Project<\/b><br \/>\n<a href=\"https:\/\/github.com\/djmason9\/AutomatedBuildTest\"><span>https:\/\/github.com\/djmason9\/AutomatedBuildTest<\/span><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction The purpose of this document is to give a step by step approach for installing a continuous integration and continuous build server. This document will cover end to end instructions in getting code from a developer\u2019s environment to the application delivery server for testers to download and test against. This will also include testing&hellip;<\/p>\n<p class=\"more-link\"><a href=\"https:\/\/bitcows.com\/?p=813\" class=\"themebutton\">Read More<\/a><\/p>\n","protected":false},"author":1,"featured_media":1265,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,5,15,19,21,24],"tags":[],"class_list":["post-813","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-android","category-appcelerator","category-ios","category-jasmine","category-jenkins","category-node"],"_links":{"self":[{"href":"https:\/\/bitcows.com\/index.php?rest_route=\/wp\/v2\/posts\/813","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bitcows.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bitcows.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bitcows.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bitcows.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=813"}],"version-history":[{"count":0,"href":"https:\/\/bitcows.com\/index.php?rest_route=\/wp\/v2\/posts\/813\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/bitcows.com\/index.php?rest_route=\/"}],"wp:attachment":[{"href":"https:\/\/bitcows.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=813"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bitcows.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=813"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bitcows.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=813"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}