How to make Xcode "Run Script" to always run - xcode

I have a "run script" step that dynamically creates resources/files that I copy into the build dirs. Every run of this script produces different content so I want it to run on every build. The script gets run correctly on a clean build however once a build is made the step is not run again since no source has been modified.
I tried setting the input of the step to /dev/random but it does not seem to trigger a changed environment and does not re run the step.
Is there a way I can set this up so this step gets run ever time build is pressed, as opposed to only when the source is modified or clean?

You should put the Run Script build phase in a separate Aggregate Target, and make your main target dependent on the Aggregate Target. The Aggregate should be built every time.

Related

How to build to same folder each time

In TFS the Build number format usually looks something like this:
$(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.r)
However, I only want to retain 1 build and I would like it to build to the same folder each time. So I tried changing it to this:
$(BuildDefinitionName)
But the problem is that this only works one time, then gives an error that the build number already exists after that. I would like to build to the same folder so that I can write a script to zip the latest build, move it to another place, and then unzip it and it would just be much easier if I didn't have to deal with writing code to figure out what the most recent folder name is.
Is there a way to accomplish building to a folder name that doesn't change?
This is by designed, every completed build should has a unique build number/name. Otherwise you will get the error above.
$(Rev:.r)
Use $(Rev:.rr) to ensure that every completed build has a unique
name. When a build is completed, if nothing else in the build number
has changed, the Rev integer value is incremented by one.
As a workaround: For vNext build, you could use a copy Files task to copy the build output to the same folder during the build pipeline. To make sure you will always only get the latest build, you could add a powershell script before the copy task to clean/delete files in that special target folder.
For XAML build you need to customize the build template and add the default CopyDirectory activity in build template to copy the build result to the specified drop location. The detailed steps please refer to this blog. Also add a pre-build script to do the clean operation.

What is the difference between Skip_build and test_without_building on Fastlane/Scanfile

What is the difference between Skip_build and test_without_building on Fastlane/Scanfile?
I would really execute my test cases without building everytime, I have several schemes that are executed on a shell script in a loop. I don't want to build for every iteration.
Does anybody tried those parameters before?
The skip_build parameter will omit the build command from the generated xcodebuild command that ultimately gets executed by scan. This means that if there is a built product in DerivedData, it will use it instead of recompiling your app. If there is no build product in DerivedData, it will rebuild the product.
The test_without_building parameter is the equivalent of the --test-without-building flag that you can pass to xcodebuild. This allows you to pass other flags to the command to point to the product under test.
Hope this helps! 🚀

TeamCity pass codebase changes to next build

I have a TeamCity build that sometimes fails too early.
What I mean by that is that the first few steps are for "provisioning" (setting up the testing environment) and the testing of my code itself comes later.
Sometimes (for whatever reason) the build fails during one of the "provisioning" steps. This is not a problem since running the build again usually works fine.
But - the "changes" are not passed along to the next run of the build.
I am using this command as part of my build to output the "changes" that came from my codebase:
copy "%system.teamcity.build.changedFiles.file%" changelog.txt
So I need a way to tell TeamCity "hey, ignore the last run, that failure doesn't count because it didn't test my code, I want the next run to contain the same 'changes' in system.teamcity.build.changedFiles.file"
How can I do that?
Have you tried build chains with dependencies? They can be set up to only execute if the build (including tests) is successful: http://blog.jetbrains.com/teamcity/2012/04/teamcity-build-dependencies-2/

XCode 4.4 bundle version updates not picked up until subsequent build

I'm probably missing something simple here. I am trying to auto increment my build number in XCode 4.4 only when archiving my application (in preparation for a TestFlight deployment). I have a working shell script that runs on the target and successfully updates the info.plist file for each build. My build configuration for archiving is name 'Ad-Hoc'.
Here is the script:
if [ $CONFIGURATION == Ad-Hoc ]; then
echo "Ad-Hoc build. Bumping build#..."
plist=${PROJECT_DIR}/${INFOPLIST_FILE}
buildnum=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${plist}")
if [[ "${buildnum}" == "" ]]; then
echo "No build number in $plist"
exit 2
fi
buildnum=$(expr $buildnum + 1)
/usr/libexec/Plistbuddy -c "Set CFBundleVersion $buildnum" "${plist}"
echo "Bumped build number to $buildnum"
else
echo $CONFIGURATION " build - Not bumping build number."
fi
This script updates the plist file appropriately and is reflected in XCode each time I archive. The problem is that the .ipa file that comes out of the archive process is still showing the previous build number. I have tried the following solutions with no success:
Clean before build
Clean build folder before build
Move Run Script phase to directly after the Target Dependencies step in Build Phases
Adding the script as a Run Script action in my scheme as a pre-action
No matter what I do, when I look at the build log, I see that the info.plist file is being processed as one of the very first steps. It is always prior to my script running and updating the build number, which is, I assume, why the build number is never current in the .ipa file.
Is there a way to force the Run Script phase to run before the info.plist file is processed?
in Xcode 4.4.1 I create new target and add to this target build phase "Run custom script", which update main target Plist. And also, you should add this target to dependencies for main target
The reason that this happens is that by the time your "Run Script" gets run, the XCode build process has already processed the project's plist file to extract the bundle version number, etc.
You can see this (probably in more detail that you want) by going to the Log Navigator in XCode (View/Navigators/Show Log Navigator), and selecting an "Archive" build.
A detailed list of build actions should appear in your main window, and one of the things near the top should be one called Process <projectname>-Info.plist. If you expand this using the icon at the right hand side, you can see the actual build command that was run.
The way that I got around this was to update both the original plist file, and also the processed one. By doing this, you get your updated build version in the current build rather than the next one.
Here's the script that I use to do this (this is Ruby, so you would need to put "/usr/bin/ruby" in the interpreter box to use this, but the concept works the same with a shell script or any other scripting language):
def incrementBundleVersion(file)
oldVersion = `/usr/libexec/Plistbuddy -c "print :CFBundleVersion" #{file}`.strip
components = oldVersion.split('.')
newBuild = components.pop.to_i + 1
version = components.push(newBuild).join('.')
print "Updating version: #{oldVersion} -> #{version} : #{file}\n"
system("/usr/libexec/PlistBuddy -c \"Set :CFBundleVersion #{version}\" #{file}")
end
incrementBundleVersion("#{ENV['PROJECT_DIR']}/#{ENV['INFOPLIST_FILE']}")
incrementBundleVersion("#{ENV['CODESIGNING_FOLDER_PATH']}/Info.plist")
Note that the processed file #{ENV['CODESIGNING_FOLDER_PATH']}/Info.plist is a binary plist file, so you won't be able to process it with simple text tools - using plistbuddy is the easiest way to handle this, and it automatically works with both text and binary plist files.
Mark (et al), I believe I've run into the same problem you are facing, and i will try to describe it in one sentence and then explain:
I think /usr/libexec/PlistBuddy, when run from inside Xcode, works on cached versions of the Info.plist data, and thus what gets finally written for execution on device or simulator is not always what you want.
I had tried writing post Copy Resource Bundle "Run Scripts" in order to change this info in a way that wouldn't cause it to change within my local git repo, only to discover that, whereas the information would work properly when the PlistBuddy commands were executed in a terminal.app window beside Xcode, if not done, the cached values would get written.
I finally resigned myself to running the version-info generation scripts prior to the Copy Bundle Resources phase and just auto-committing the changes in another Run Script, using the same tags for the git message and for the git tag that get auto-created. for the Settings.bundle/Root.plist file, rather than commit this every time, i preferred to just run a finalization script that would perform a 'git checkout -- ${PROJECT}/Resources/Settings.bundle/Root.plist' (which is where mine exists, but may not be where everyone puts their own system settings resource file).
between the checking for changes, running parts of it at install and parts of it every time, and having the finalization scripts at the end, there are 6 scripts for some targets and 7 for another …
… but the important thing to me is that it's finally properly automated … and gets around whatever PlistBuddy is doing to my plist files when processed inside of Xcode.

Xcode: Running a script before every build that modifies source code directly

What I did:
I have a script that
Read some configuration files to generate source code snippets
Find relevant Objective-C source files and
Replace some portions of the source code with the generated code in step 1.
and a Makefile that has a special timestamp file as a make target and the configuration files as target sources:
SRC = $(shell find ../config -iname "*.txt")
STAMP = $(PROJECT_TEMP_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME).stamp
$(STAMP): $(SRC)
python inject.py
touch $(STAMP)
I added this Makefile as a "Run Script Build Phase" on top of the stack of build phases for the project target.
What happened:
The script build phase was run before compiling the source.
However, since the script modifies source code during its execution, I needed to build twice to get the most recent version of the build product. Here is what I imagine to be happening:
1st run: Xcode collects dependency information ---> no changes
1st run: Xcode runs "Run Script Build Phase" ---> source is changed behind Xcode's back
1st run: Xcode finishes build, thinking nothing needs to be updated
2nd run: Xcode collects dependency information ---> source has changed, needs rebuild!
2nd run: Xcode runs Run Script Build Phase" ---> everything is up-to-date
2nd run: Xcode proceeds to compilation
After reading Xcode documentation on Build Phases, I tried adding a source file which is known to be updated every time the script is run as the output of "Run Script Build Phases", but nothing changed. Since the number of configuration files may vary in my project, I don't want to specify every input and output file.
Question:
How do I make Xcode aware of source file changes made during "Run Script Build Phase"?
Edit:
Added that I placed the script build phase before the other build phases
Every technique mentioned so far is an overkill. Reproducing steve kim's comment for visibility:
In the build phases tab, simply drag the "Run Script" step to a higher location (e.g. before "Compile Sources").
Tested on Xcode 6
This solution is probably outdated. See the higher voted answer instead; I no longer actively use Xcode and am not qualified to vet a solution.
Use "External Target":
Select "Project" > "New Target..." from the menu
Select "Mac OS X" > "Other" > "External Target" and add it to your project
Open its settings and fill in your script setup
Open the "General" tab of the main target's settings and add the new target as it's direct dependency
Now the new "External Target" runs before the main target even starts gathering dependency information, so that any changes made during the script execution should be included in the build.
There is another, slightly simpler option that doesn't require a separate target, but it's only viable if your script tends to modify the same source files every time.
First, here's a brief explanation for anyone who's confused about why Xcode sometimes requires you to build twice (or do a clean build) to see certain changes reflected in your target app. Xcode compiles a source file if the object file it produces is missing, or if the object file's last-modified date is earlier than the source file's last-modified date was at the beginning of the first build phase. If your project runs a script that modifies a source file in a pre-compilation build phase, Xcode won't notice that the source file's last-modified date has changed, so it won't bother to recompile it. It's only when you build the project a second time that Xcode will notice the date change and recompile the file.
Here's a simple solution if your script happens to modify the same source files every time. Just add a Run Script build phase at the end of your build process like this:
touch Classes/FirstModifiedFile.m Classes/SecondModifiedFile.m
exit $?
Running touch on these source files at the end of your build process guarantees that they will always have a later last-modified date than their object files, so Xcode will recompile them every time.
As of Xcode 4, it looks like if you add the generated files to the output section of the build phase, it will respect that setting, and not generate the ... has been modified since the precompiled header was built error messages.
This is a good option if your script is only generating a handful of files each time.
I as well struggled with this for a long time. The answer is to use ento's "External Target" solution. He is WHY this problem occurs and how we use it in practice...
Xcode 4 build steps do not execute until AFTER the plist has been compiled. This is silly, of course, because it means that any pre-build steps that modify the plist won't take effect. But if you think about it, they actually DO take effect...on the NEXT build. That's why some people have talked about "caching" of plist values or "I have to do 2 builds to make it work." What happens is the plist is built, then your script runs. Next time you build, the plist builds using your modified files, hence the second build.
ento's solution is the one way I've found to actually do a true pre-build step. Unfortunately I also found that it does not cause the plist to update without a clean build and I fixed that. Here is how we have data-driven user values in the plist:
Add an External Build System project that points to a python script and passes some arguments
Add user-defined build settings to the build. These are the arguments that you pass to python (more on why we do this later)
The python script reads some input JSON files and builds a plist preprocessor header file AND touches the main app plist
The main project has "preprocess plist files" turned on and points to this preprocessor file
Using touch on the main app plist file causes the main target to generate the plist every time. The reason we pass in build settings as parameters is so our command-line build can override settings:
Add a user-defined variable "foo" to the prebuild project.
In your prebuild you can use $(foo) to pass the value into the python script.
On the command-line you can add foo=test to pass in a new value.
The python script uses base settings files and allows for user-defined settings files to override the defaults. You make a change and immediately it ends up in the plist. We only use this for settings that MUST be in the plist. For anything else it's a waste of effort....generate a json file or something similar instead and load it at run-time :)
I hope this helps...it's been a couple rough days figuring this out.
The External Target solution from #ento no longer works as of Xcode 11.5. The solution is to add all files that will be changed under Output Files in the Run Script.
Another option is to create a subproject framework with your scripts and just add it as a dependency to all targets. The phase scripts of this subproject should now be executed before all targets.

Resources