Making a CI server build all XCode targets as .ipa's - xcode

I'm looking into TeamCity and Jenkins, for a CI server.
My goal is this: every time someone commits a change to our repo, the CI server builds all targets in the project as .ipa's - ready for downloading/installing on a device.
I got Teamcity and Jenkins up and running, using a Mac mini as a build slave. That part of it is working fine.
Using Jenkins XCode plugin, I succeeded in building all targets as .ipa's.
I havent had such luck with Teamcity. The XCode plugin doesnt allow building all targets. Rather, you have to specify which targets you want to build, in each build configuration.
I approached the makers of Teamcity, and they gave me some convoluted method involving meta runners and a lot of duplication, in order to accomplish my goal.
Instead of relying on plugins, I'd rather build the .ipa's using shell scripting. However, as I'm not a script ninja, I can't figure out how to go about this.
I can figure out how to build one target via scripting, but it illudes me how make it build them all. Everytime I create a new target in the project, I don't want to have to add it at the CI server. The server should be able to automatically build all targets in the project.
...Maybe someone has a better solution? Any help is much appreciated.

What you should do (codes are bash script snippets, ready to run on OS X, you don't need to install anything except Xcode's CLI/Command Line Tools):
if you want to do this for every Xcode project file you have in your repository you should first search for these (if you have a specific Xcode project you can skip this)
for path in $(find . -type d -name '*.xcodeproj' -or -name '*.xcworkspace')
do
after this you can query all the shared (!) schemes through Xcode's command line tool
if [[ "$project" == *".xcodeproj" ]]; then
xcodebuild_output=($(xcodebuild -list -project "$project"))
else
xcodebuild_output=($(xcodebuild -list -workspace "$project"))
fi
now you have all the schemes so you can simply xcodebuild them one-by-one
Here's a bash script we developed to search for every Xcode project and every scheme configuration in a repository: https://github.com/concretebuilder/steps-cocapods-and-repository-validator/blob/master/find_schemes.sh
Note: you need to mark you schemes as shared to get xcodebuild (the command line interface of Xcode) list them.

Related

Xcode 6 running custom shell scripts

When I build my target, in the information tab I can see the scheme building and the target building. At the end of the process it runs 2 custom shell scripts.
I can't find where the target or project is running these 2 custom shell scrips. I've looked at target > build phases and it's not being set to run there. I also looked at project > build settings but I can't locate it there.
I don't want to run these scripts but I don' know how to remove them! Any help would be great! Thanks
yup but I know the pods project or targets are not set to run scripts. I've inherited this project on our jenkins it runs 2 scripts at the end of the build. I've removed it from jenkins but not sure how to remove it from the project.
Pods run scripts. Here's the two scripts being run:
If you don't want to use pods anymore, use this pods-deintegrate plugin to remove all traces of pods.

Generate an .xcscheme file from the command line

I am working on my company's continuous integration server, and the build process is failing because the server does not have access to schemes in an xcode project.
Basically, they are using Cmake to generate xcode projects on the fly to be used for a single build, and then discarded until the next check in.
My research indicates that this problem will be fixed if there is an .xcscheme file with the .xcodeproj file, but for various reasons that can't be generated and checked in ahead of time.
Is there a way to generate this file using xcodebuild or some other command line tool so that we can work it into existing build shell scripts?
The xcodebuild documentation, google, and S.O. are surprisingly lacking on this topic.
I generate the XCode project using the -G Xcode too; I'm using the scan-build plugin ( http://blog.manbolo.com/2014/04/15/automated-static-code-analysis-with-xcode-5.1-and-jenkins ) in jenkins.
It requires the workspace files.
My script to launch & watch xcode looks like that:
($WORKSPACE is set by jenkins)
#!/bin/bash
/Applications/Xcode.app/Contents/MacOS/Xcode "${WORKSPACE}/Build/arangodb.xcodeproj" &
XCODE_PID=$!
# now we wait for xcode to build the workspace:
WAIT_FOR_XCODE=0
while test ${WAIT_FOR_XCODE} -lt 6; do
WAIT_FOR_XCODE=`find "${WORKSPACE}/Build/arangodb.xcodeproj" |wc -l`
sleep 2
COUNT=`ps -p ${XCODE_PID} |wc -l`
if test ${COUNT} -lt 2; then
echo "XCode went away unexpectedly!"
exit -1
fi
done
#ok, we believe its done. kill it, and wait until its realy dead.
kill ${XCODE_PID}
COUNT=2;
while test ${COUNT} -gt 1; do
sleep 1
COUNT=`ps -p ${XCODE_PID} |wc -l`
done
Unfortunately, as of Xcode 5.1.1 there does not exist a mechanism for auto-generating .xcodeproj or .xcworkspace build schemes from the command line as the Xcode UI does. The good news though is that an Xcode project's pbxproj markup is an order of magnitude more complex than the XML markup that describes a build scheme. If you've managed to get CMake to spin up a well-formed Xcode project on-commit, then using a very similar procedure you can build out the 100 or so lines of XML that describe the build-run-test-profile-archive actions of that Xcode project.
If you've not taken a peek at the underlying XML structure of a scheme, create a sample iOS project from the new project wizards and then go poking through the contents of the .xcodeproj or .xcworkspace file for .xcscheme files. The structure is fairly self-documenting and you might even be able to get away without actually specifying the XML markup for those actions you know that will not be run on CI.
Failing that, a less robust approach would be to looking into opening up the Xcode project/workspace file upon the completion of your CMake build process. After a handful of seconds, Xcode's indexer will have had time to identify the projects and auto-generate the schemes for the projects within the master project file itself. Obviously, as you are relying on a UI-layer operation in this approach, you are subject to Xcode's whims, and the indexer may take more than a few seconds to build its index (ex. larger projects will take longer to auto-generate schemes!) ...and there is no trigger advising command-line processes that the indexing and generation has succeeded or failed. You'd wind up having to poll for the existence of a file with an appropriate timeout which can get a bit dicey in an automated build and test environment.
I was actually able to do this by using cmake to generate the project, then using the xcode gui to make the scheme files I need. I used the terminal to extract the xcscheme files from the project and put them in another directory being tracked by source control. As part of the generation process, I just added a bit of shell script to copy the copies I made earlier into the newly generated project, then continue the build process as normal.
The latest version of cmake has added this functionality:
https://blog.kitware.com/cmake-3-9-0-rc3-is-now-ready-for-testing/
The "Xcode" generator learned to create Xcode schema files. This
is an experimental feature and can be activated by setting the
"CMAKE_XCODE_GENERATE_SCHEME" variable to a "TRUE" value.
For CMake based project use XCODE_GENERATE_SCHEME setting for your target.
Setting:
set_target_properties(<your_target> PROPERTIES
XCODE_GENERATE_SCHEME YES
)
will produce following file
your_project.xcodeproj/xcshareddata/xcschemes/your_target.xcscheme

Jenkins + Windows + CMake + multiple build types (Debug, Release)

How can I make Jenkins do the following?
Checkout trunk/ from SVN, then build configurations Debug and Release using CMake, without having duplicate jobs for the configurations.
Took me a while to figure this out. Here's how I managed to do it.
Create a free-style job "Checkout". This job is going to do all the stuff that doesn't depend on the configuration type (Debug/Release).
Under "Source Code Management" select Subversion
Fill in the Repository URL. Probably a good idea to make it point to /trunk.
Set Local module dir to "." (no quotes)
As Check-out Strategy "Emulate clean" is nice
Build trigger Poll SCM, set Schedule to "5 * * * *" to check every 5 minutes.
Now under Advanced Project Options check 'Use custom workspace' and set the dir to e.g. "c:/src". We don't want Jenkins to use its internal workspace, because we want other jobs to be able to access the source.
Under Build add the following Windows batch command, which is used to clean the build dir. For some reason, CMake doesn't provide a way to do this.
cd c:\
rmdir /S /Q build
mkdir build
cd build
cmake --version
rem optionally: svn info c:\src
cmake -G "Visual Studio 10" c:\src
Create another job "Build", this time make it a "multi-configuration" job. This job is going to run for each configuration (Debug/Release).
First, set the Build Triggers to build after job "Checkout"
Now under Configuration Matrix add an axis "configuration" with values "Debug Release" (whitespace = separator). Unfortunately, the CMake builder plugin for Jenkins doesn't work with multi-configuration jobs. We can't even use cmake --build, because it always builds the Debug configuration. To build, we have to use another batch script:
cd c:\build
call "%ProgramFiles(x86)%\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"
msbuild ALL_BUILD.vcxproj /verbosity:minimal /maxcpucount:1 /property:Configuration=%configuration%
If you want to build the entire solution, specify the .sln file instead of ALL_BUILD.vcxproj. If you only want to build a specific project, use
msbuild <solution>.sln /target:<project>
Use Jenkins Matrix job. Define one of the axes as build_mode with values Debug and Release. You then run CMake that will create both configurations for the compilation tool you'll be using (XCode, gcc, VisualStudio, etc.). You can then use build_mode as if it were an environment variable and pass it to build steps that do actual compilation.
When using the Visual Studio generator you can pass the configuration to build to the cmake --build-command:
cmake --build . --config Release
cmake --build . --config Debug
See also the CMake docs.
After using Jenkins for a while now, I found that you should use as few jobs as possible if you want to reuse the source directory.
The default setup in Jenkins is that each build uses a different directory as its workspace. Which implies that you do a complete SVN checkout every build. Which takes forever.
If you want to use the same source directory for every build, you have to worry about synchronization: Only one build at a time. As far as I know, Jenkins has no built-in means of synchronization. The only way is to only use one executor. Even then you can't control the way the executor chooses its next job.
Let's say job "SVN update" triggers job "Build". Someone starts "SVN update #33", which is supposed to trigger "Build #33". If, however, Jenkins' "Poll SCM" feature schedules "SVN update" #34 in the meantime, I haven't found a way to tell it that "Build #33" must run before "SVN update #34". So you might end up with "SVN update #34" running before "Build #33", and everything fails. Unless you manually disable the polling job. And remind yourself to re-enable it afterwards, of course.
Anyways. After using Jenkins for two years, I change my answer to: Never use multiple jobs that share resources (like the source dir), and bake all the logic into shell scripts (for loop over configurations).

Why does xcodebuild give different build results than XCode UI

I have a series of projects within a workspace, and trying to use the following type of command to build them via the command line:
"Xcodebuild -project XXX"
or
"Xcodebuild -workspace XXX -scheme YYY"
Some of my projects build fine but others give strange errors, like "'XXX' for instance message does not declare a method with selector" or "ld: library not found for -lMyLibrary"
However all these projects build fine from within the XCode UI without issues.
Based on this is seems that the command line and UI builds are using a different toolset, but that seems like a very bad idea so I'm hoping I'm wrong about this. Or possibly there are just a few different build flags being set on the command line build.
I can try to troubleshoot the issues one by one but I'm hoping I can write a script which does the exact same type of build as the UI.
Any ideas?
Without including -configuration, xcodebuild is going to use the default configuration for each project. Generally that's Release. In Xcode, the Configuration you select will be applied to every project regardless of default.
Given your errors, your most likely problem is that you've used the build pane (why I hate the build pane for large projects), and you've made the classic mistake of applying some settings for Debug rather than all configurations.

Having a shell script refer to XCode build paths

I have a shell script that runs lcov (test coverage) on an iOS project that I have Hudson. Hudson's copy of this project is derived from a Git repository. The way that I have set up now is that whenever the repo is updated or if someone manually builds the project in Hudson, Hudson would automatically run the app, and then run my shell script after the build is done. lcov can only be run after the app is not only built, but automatically run with some functional test tools. So, I cannot run the shell script as part of the build process, through XCode. It must be run after the app finishes building and running.
However, I would like to use this project in multiple Hudson jobs. Unfortunately, in each Hudson job, the iOS project is named differently. I would like to refer to the build path with some sort of environmental variable, but I don't know how to. Does anyone have any tips as to how to find that?
If I understand you correctly this is really a Hudson question. You can set "global variables" in your Hudson config and then invoke shell scripts, batch files, ant builds etc. You can also set them dynamically on each invocation of your Hudson job. Not sure exactly how to help you in your specific environment without more info.

Resources