Why is Groovy or Jenkins splitting a command into multiple lines - jenkins

Our shared library uses these two (slightly abstraced) calls. The first one works perfectly fine. The second one splits the ${UNITY_PATH} command into multiple lines split where spaces are.
A workaround is to exclude this command into a one-line-sh command - in case somebody else runs into this issue. But my question remains: Why is the `${UNITY_PATH} line split appart in the second scenario but not the first one?
First Scenario (working case):
def call() {
sh """
rm -fr '${WORKSPACE}/${RELATIVE_TARGET_DIR_PRODUCTION}/TheWagaduChronicles.Production/Build/'
${UNITY_PATH} -batchmode -projectPath ./${RELATIVE_TARGET_DIR_PRODUCTION}/TheWagaduChronicles.Production -logfile - -executeMethod TheWagaduChronicles.Build.Editor.BuildMenu.BuildMacOSClient
${UNITY_PATH} -batchmode -projectPath ./${RELATIVE_TARGET_DIR_PRODUCTION}/TheWagaduChronicles.Production -logfile - -executeMethod TheWagaduChronicles.Build.Editor.BuildMenu.BuildWindowsClient
"""
}
Second scenario (failing case):
def call(String buildVersion) {
sh """
cd ${WORKSPACE}/${RELATIVE_TARGET_DIR_PRODUCTION}/.
<more stuff happening>
jq '.Version_ = ${buildVersion}' version.json | sponge version.json
${UNITY_PATH} -batchmode -projectPath ./$RELATIVE_TARGET_DIR_PRODUCTION/GreatProject.Production -logfile - -executeMethod GreatProject.Build.Editor.BuildMenu.SetBuildVersion
git commit -m \"Bumps version to $buildVersion\"
<more stuff happening>
git push --tags --verbose
"""
}
Leads to:
11:40:54 COMMAND LINE ARGUMENTS:
11:40:54 /Applications/Unity/Hub/Editor/2021.3.12f1/Unity.app/Contents/MacOS/Unity
11:40:54 -batchmode
11:40:54 -projectPath
11:40:54 ./production/TheWagaduChronicles.Production
11:40:54 -logfile
11:40:54 -
11:40:54 -executeMethod
11:40:54 TheWagaduChronicles.Build.Editor.BuildMenu.SetBuildVersion
11:40:54 Couldn't set project path to:
11:40:54
11:40:54 Aborting batchmode due to failure:
11:40:54 Couldn't set project path to:
11:40:54
Workaround Hack:
def call(String buildVersion) {
sh """
cd ${WORKSPACE}/${RELATIVE_TARGET_DIR_PRODUCTION}/.
<more stuff happening>
jq '.Version_ = ${buildVersion}' version.json | sponge version.json
"""
sh "${UNITY_PATH} -batchmode -projectPath ./$RELATIVE_TARGET_DIR_PRODUCTION/GreatProject.Production -logfile - -executeMethod GreatProject.Build.Editor.BuildMenu.SetBuildVersion"
sh """
git commit -m \"Bumps version to $buildVersion\"
<more stuff happening>
git push --tags --verbose
"""
}
Researched and troubleshooted until I found the hack included in the question. But I couldn't find an explanation.

It might be related to the "strange" way Jenkins handles pipe subshells; see something like this stackoverflow post to get an idea of the weirdness. So my guess would be that actually jq '.Version_ = ${buildVersion}' version.json | sponge version.json throws off the following flow / commands. It might be worth a test?

Related

Enable SwiftLint only for the new files

I have a pretty huge iOS(legacy) project in which I want to add SwiftLint. All the rules I wish to enforce, I would enforce only on new created files. In that way I do not have to go back and fix all the problems that would come up because the rules have not been followed in the past (as there was no SwiftLint in use). I am not sure how to achieve this?
you can run a script like this
# Run SwiftLint
START_DATE=$(date +"%s")
SWIFT_LINT=/usr/local/bin/swiftlint
# Run SwiftLint for given filename
run_swiftlint() {
local filename="${1}"
if [[ "${filename##*.}" == "swift" ]]; then
#${SWIFT_LINT} autocorrect --path "${filename}"
${SWIFT_LINT} lint --path "${filename}"
fi
}
if [[ -e "${SWIFT_LINT}" ]]; then
echo "SwiftLint version: $(${SWIFT_LINT} version)"
# Run for both staged and unstaged files
git diff --name-only | while read filename; do run_swiftlint "${filename}"; done
git diff --cached --name-only | while read filename; do run_swiftlint "${filename}"; done
else
echo "${SWIFT_LINT} is not installed."
exit 0
fi
END_DATE=$(date +"%s")
DIFF=$(($END_DATE - $START_DATE))
echo "SwiftLint took $(($DIFF / 60)) minutes and $(($DIFF % 60)) seconds to complete."
Simply add a build phase run script to Xcode with the following
"${SRCROOT}/Scripts/swiftlint.sh"
It comes from here https://github.com/realm/SwiftLint/issues/413#issuecomment-184077062
It doesn't work on the M1 chip because you need to say something like this
if test -d "/opt/homebrew/bin/"; then
PATH="/opt/homebrew/bin/:${PATH}"
fi
export PATH
if which swiftlint >/dev/null; then
swiftlint
else
echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fine
based on this blog https://www.anotheriosdevblog.com/installing-swiftlint-on-a-m1/
If you are using feature branches you can run it as follows:
swiftlint --config PATH/TO/CONFIG/.swiftlint.yml $(git diff develop --name-only | grep .swift)

Trigger specific job on push to specific directory

We have 12 different projects inside the same repository and have a different job to run for each of these.
I want to know how I can trigger a job only when a change has happened in a specific folder, since running all 12 on every push takes too long to finish.
Well I have hacked a solution that works for us.
First, add an Execute Shell Build Step:
#!/bin/bash
export DIRS="api objects"
DIFF=`git diff --name-only develop`
echo "export RUN_TEST=0" > "$WORKSPACE/RUN_TEST"
for DIR in $DIRS; do
for LINE in $DIFF; do
# Is this file inside an interesting directory?
echo $LINE | grep -e "^$DIR/"
# Checking if it is inside
if [ $? -eq 0 ]; then
echo "export RUN_TEST=1" > "$WORKSPACE/RUN_TEST"
fi
done
done
Here:
api and objects are the 2 directories I want to trigger this Job
develop is the main branch we use, so I want to know how my directories compare to that branch in particular
I create a file $WORKSPACE/RUN_TEST to set a variable if I should or not run it
Then in the time-consuming build steps add:
#!/bin/sh
. "$WORKSPACE/RUN_TEST"
if [ $RUN_TEST -eq 1 ]; then
# Time consuming code here
fi
That way the job is triggered but runs as fast as if it wasn't triggered.
Now I modified it to:
#!/bin/bash
export DIRS="api objects"
DIFF=`git diff --name-only origin/develop`
RUN_TEST=111
for DIR in $DIRS; do
for LINE in $DIFF; do
# Is this file inside an interesting directory?
echo $LINE | grep -e "^$DIR/"
# Checking if it is inside
if [ $? -eq 0 ]; then
RUN_TEST=0
fi
done
done
echo "RUN_TEST=$RUN_TEST"
echo "return $RUN_TEST" > "$WORKSPACE/RUN_TEST"
exit $RUN_TEST
And set Exit code to set build unstable to 111 on all build steps. Then, in all following build steps I did:
#!/bin/bash
# Exit on any error
set -euo pipefail
. "$WORKSPACE/RUN_TEST"
# Rest of build step

Create symlinks instead of copy with maven-dependency-plugin : copy-dependencies

I work on a Maven project that need to copy mode than 10 GB of artifacts in a target repository from a maven local repository (after downloaded them).
In some cases (e.g. for tests), I'd like to replace this copy by a symlink creation in order to save few minutes.
My question is: Is there a way to ask to plugin maven-dependency-plugin goal copy-dependencies to create a symlink OR is there any maven plugin that can do it.
The copy-dependencies goal cannot, to my knowledge, do this out of the box. However, you can use a shell script:
#!/bin/sh
outputDir=target/dependency
mkdir -p "$outputDir"
mvn dependency:resolve |
grep ':\(compile\|runtime\)' | sed 's/\[INFO\] *//' |
while read gav
do
case "$gav" in
*:*:*:*:*:*) # G:A:P:C:V:S
g="${gav%%:*}"; remain="${gav#*:}"
a="${remain%%:*}"; remain="${remain#*:}"
p="${remain%%:*}"; remain="${remain#*:}"
c="${remain%%:*}"; remain="${remain#*:}"
v="${remain%%:*}"
s="${remain#*:}"
;;
*:*:*:*:*) # G:A:P:V:S
g="${gav%%:*}"; remain="${gav#*:}"
a="${remain%%:*}"; remain="${remain#*:}"
p="${remain%%:*}"; remain="${remain#*:}"
c=""
v="${remain%%:*}"
s="${remain#*:}"
;;
esac
g=$(echo "$g" | sed 's/\./\//g')
test -n "$c" && artName="$a-$v-$c" || artName="$a-$v"
ln -s "$HOME/.m2/repository/$g/$a/$v/$artName.$p" "$outputDir"
done

How to use cocoapods integrated project with OCLint?

I can build the project and generate OCLint report on a project without cocoapods but when integrated with cocoapods the build for project is successful but the build for OCLint results into errors for the file which are present into cocoapods and build fails.
So how to make build successful for cocoapods with OCLint?
Any help would be appreciated.
Below is the script I am using to generate html file for cocoapods integrated project with OCLint.
OCLINT_HOME is the path for oclint downloaded folder. I have renamed the folder to oclintrelease.
OCLINT_HOME=/Users/Dheeraj/Downloads/oclintrelease
export PATH=$OCLINT_HOME/bin:$PATH
hash oclint &> /dev/null
if [ $? -eq 1 ]; then
echo >&2 "oclint not found, analyzing stopped"
exit 1
fi
cd ${TARGET_TEMP_DIR}
if [ ! -f compile_commands.json ]; then
echo "[*] compile_commands.json not found, possibly clean was performed"
echo "Workspace Path : ${MY_WORKSPACE}"
echo "[*] starting xcodebuild to rebuild the project.."
# clean previous output
if [ -f xcodebuild.log ]; then
rm xcodebuild.log
echo "Oclint Clean performed"
fi
cd ${SRCROOT}
xcodebuild clean
#build xcodebuild.log
xcodebuild ONLY_ACTIVE_ARCH=NO -workspace ${PROJECT_NAME}.xcworkspace -scheme ${PROJECT_NAME} -configuration Debug clean build| tee ${TARGET_TEMP_DIR}/xcodebuild.log
#xcodebuild <options>| tee ${TARGET_TEMP_DIR}/xcodebuild.log
echo "[*] transforming xcodebuild.log into compile_commands.json..."
cd ${TARGET_TEMP_DIR}
#transform it into compile_commands.json
oclint-xcodebuild
fi
echo "[*] starting analyzing"
cd ${TARGET_TEMP_DIR}
oclint-json-compilation-database -e /Users/Dheeraj/Desktop/sampleCocoaPods/Pods/ -v oclint_args "-report-type html -o /Users/Dheeraj/NewHTMLREPORT.html" | sed 's/\(.*\.\m\{1,2\}:[0-9]*:[0-9]*:\)/\1 warning:/'
It will exclude all the Pods related files.
If you want to include Pods file as well then replace last line in script by :
oclint-json-compilation-database -v oclint_args "-report-type html -o /Users/Dheeraj/NewHTMLREPORT.html" | sed 's/\(.*\.\m\{1,2\}:[0-9]*:[0-9]*:\)/\1 warning:/'
Notes :
Please try first with a short sample Application including cocoapods and once you have generated report for sample application then integrate script into your real application as building with OCLint takes a lot of time to generate the report.
Always clean application and then build with OCLint.
Link for reference

error with Uncrustify in xcode for an ios app

I have installed the uncrustify through brew (as per the git instructions), and I have added the run script build phase to the xcode and tried to build an ios project, but the build is failing with the following error:
**/bin/sh: /Users/test/Library/Developer/Xcode/DerivedData/testProj- amlbymrfycxuzmemclwtovltjxzl/Build/Intermediates/testProj.build/Debug-iphoneos/testProj.build/Script-AC898878187BE0A00056CAB1.sh: sh: bad interpreter: No such file or directory**
How can I resolve this error? Any help would be appreciated. Thanks in advance.
My sh script:
if [ -n "$1" ]
then
# recover directory to format :
pathToSourcesDirectory=`echo $(pwd)/$1`
# go to current folder :
scriptDirectory=$(dirname $0)
cd $scriptDirectory
# find sources files to format :
echo ""
echo "==> Getting files to format in directory " + $pathToSourcesDirectory
mkdir -p temp
find $pathToSourcesDirectory -name "*.[mh]" > temp/sources_to_uncrustify.txt
# format files :
echo ""
echo "==> Format files"
/usr/local/bin/uncrustify -F temp/sources_to_uncrustify.txt -c "../uncrustify_objective_c.cfg" --no-backup
# remove temp files :
rm -rf temp/
else
echo "Error : You must specify a source folder as first parameter"
fi
It looks like you don't have Shell set to /bin/sh in the Xcode Run Script configuration:
(screenshot taken from here).

Resources