I am trying to do an Xcode build in Gradle. Requirements:
Some of my arguments have spaces in them.
I want to pipe the output through xcpretty. Otherwise gitlab complains that there is too much output and I can't see any errors toward the end of the build
I don't want to wait for the command to complete before seeing the output. I want to be able to watch it build, like any ci job
Gradle exec{} doesn't seem to let me pipe the output while building. I can save the output to a file but that doesn't let me watch the build
I.e.,
exec {
executable 'xcodebuild'
ext.output = {
return standardOutput.toString()
}
args = [
'archive',
'-project',
"${buildDir}/iPhone/Unity-iPhone.xcodeproj/",
"-archivePath",
"${buildDir}/iPhone/Unity-iPhone.xcarchive",
"-sdk", "iphoneos",
"GCC_GENERATE_DEBUGGING_SYMBOLS=YES",
"DEBUG_INFORMATION_FORMAT=dwarf-with-dsym",
"DWARF_DSYM_FILE_SHOULD_ACCOMPANY_PRODUCT=NO",
"DWARF_DSYM_FOLDER_PATH=iOS_Dsym",
"DEBUGGING_SYMBOLS=YES",
"DEVELOPMENT_TEAM=RPGSNMH65P",
"CODE_SIGN_IDENTITY=${appleIdentity}",
"CODE_SIGN_STYLE=Manual",
"USYM_UPLOAD_AUTH_TOKEN=${appcenter_login_token}",
"PROVISIONING_PROFILE_SPECIFIER_APP=${provisioningProfile}",
"-configuration", "Release",
"-scheme", "${schemeName}",
"| xcpretty"
]
}
doesn't work
I can't use groovy "xcodebuild ... CODE_SIGN_IDENTITY=${"${appleIdentity}"} ... | xcpretty".execute() because my code signing identity contains spaces and for some reason groovy wants to stick its own quotes into the command string when it finds spaces.
I tried the array execute method but ended up with the same problem.
def cmd = [
'xcodebuild ',
'archive',
'-project',
"${buildDir}/iPhone/Unity-iPhone.xcodeproj/",
"-archivePath",
"${buildDir}/iPhone/Unity-iPhone.xcarchive",
"-sdk", "iphoneos",
"GCC_GENERATE_DEBUGGING_SYMBOLS=YES",
"DEBUG_INFORMATION_FORMAT=dwarf-with-dsym",
"DWARF_DSYM_FILE_SHOULD_ACCOMPANY_PRODUCT=NO",
"DWARF_DSYM_FOLDER_PATH=iOS_Dsym",
"DEBUGGING_SYMBOLS=YES",
"DEVELOPMENT_TEAM=RPGSNMH65P",
"CODE_SIGN_IDENTITY=${appleIdentity}",
"CODE_SIGN_STYLE=Manual",
"USYM_UPLOAD_AUTH_TOKEN=${appcenter_login_token}",
"PROVISIONING_PROFILE_SPECIFIER_APP=${provisioningProfile}",
"-configuration", "Release",
"-scheme", "${schemeName}"
]
println cmd
def proc = cmd.execute()
... except that it's even harder to debug because I can't see the actual command being executed.
I have found various solutions online but nothing that fits these requirements
Related
I have a gradle build setup at the beginning of which I want to execute a shellscript in a subdirectory that prepares my environment.
task build << {
}
task preBuild << {
println 'do prebuild stuff:'
}
task myPrebuildTask(type: Exec) {
workingDir "$projectDir/mySubDir"
commandLine './myScript.sh'
}
build.dependsOn preBuild
preBuild.dependsOn myPrebuildTask
However, when I execute the task either by calling gradle myPrebuildTask or by simply building the project, the following error occurs:
> A problem occurred starting process 'command './myScript.sh''
Unfortunately, thats all I get.
I have also tried the following - same error.
commandLine 'sh mySubDir/myScript.sh'
I use Gradle 1.10 (needed by Android) on Windows, inside a Cygwin shell. Any ideas?
use
commandLine 'sh', './myScript.sh'
your script itself is not a program itself, that's why you have to declare 'sh' as the program and the path to your script as an argument.
A more generic way of writing the exec task, but portable for Windows/Linux, if you are invoking a command file on the PATH:
task myPrebuildTask(type: Exec) {
workingDir "$projectDir/mySubDir"
if (System.getProperty('os.name').toLowerCase(Locale.ROOT).contains('windows')) {
commandLine 'cmd', '/c', 'mycommand'
} else {
commandLine 'sh', '-c', 'mycommand'
}
}
This doesn't directly address the use case for the OP (since there is script file in the working directory), but the title of the question is more generic (and drew me here), so it could help someone maybe.
unfortunately options with commandLine not worked for me in any way and my friend find other way with executable
executable "./myScript.sh"
and full task would be
task startScript() {
doLast {
exec {
executable "./myScript.sh"
}
}
}
This works for me in my Android project
preBuild.doFirst {
println("Executing myScript")
def proc = "mySubDir/myScript.sh".execute()
proc.waitForProcessOutput(System.out, System.err)
}
See here for explanation:
How to make System command calls in Java/Groovy?
This is a solution for Kotlin DSL (build.gradle.kts) derived from Charlie Lee's answer:
task<Exec>("MyTask") {
doLast {
commandLine("git")
.args("rev-parse", "--verify", "--short", "HEAD")
.workingDir(rootProject.projectDir)
}
}
Another approach using the Java standard ProcessBuilder API:
tasks.create("MyTask") {
val command = "git rev-parse --verify --short HEAD"
doLast {
val process = ProcessBuilder()
.command(command.split(" "))
.directory(rootProject.projectDir)
.redirectOutput(Redirect.INHERIT)
.redirectError(Redirect.INHERIT)
.start()
process.waitFor(60, TimeUnit.SECONDS)
val result = process.inputStream.bufferedReader().readText()
println(result)
}
}
For more information see:
How to run a command line command with Kotlin DSL in Gradle 6.1.1?
How to invoke external command from within Kotlin code?
for kotlin gradle you can use
Runtime.getRuntime().exec("./my_script.sh")
I copied my shell scipt to /usr/local/bin with +x permission and used it as just another command:
commandLine 'my_script.sh'
how to use choice parameter in Jenkins declarative pipeline in batch command.
I'm using following stage:
choice(
choices: 'apply\ndestroy\n',
description: '',
name: 'DESTROY_OR_APPLY')
stage ('temp') {
steps {
echo "type ${params.DESTROY_OR_APPLY}"
bat'echo "type01 ${params.DESTROY_OR_APPLY}"'
bat'echo "type01 %{params.DESTROY_OR_APPLY}%"'
bat'echo type01 [${params.DESTROY_OR_APPLY}]'
}
echo does resolve to correct parameter value but under bat none of the above code works.
You almost got the syntax right.
If you change it to one of the below options, the bat command receives the value of your choice.
steps {
bat "echo type01 ${DESTROY_OR_APPLY}"
}
or
steps {
bat 'echo type01 ' + DESTROY_OR_APPLY
}
You can also use ${params.DESTROY_OR_APPLY} in the first or params.DESTROY_OR_APPLY in the second example if you want to use the params definition consequently in your code.
Can anyone explain why the first sample working while the second does nothing?
test {
jvmArgs '-Xdebug',
'-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=4000'
}
test {
jvmArgs.add('-Xdebug')
jvmArgs.add('-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=4000')
}
Because in the second example this method is invoked. You get the list, modify it but the changes are not reflected to settings - read only access. In the first example this method is invoked and arguments passed are set.
Here's the explanation, a copy of the list is returned (it's for safety, security reasons - mutable types should be always returned as a copy)
public List<String> getJvmArgs() {
List<String> args = new ArrayList<String>();
for (Object extraJvmArg : extraJvmArgs) {
args.add(extraJvmArg.toString());
}
return args;
}
I found this problematic with the normal command line arguments using Gradle as well -- Even to the extent that Example 1 works and Example 2 will fail to add the extra argument:
runArgs is set in the main build.gradle
As follows:
ext {
runArgs = [ '-server=localhost', '-port=8080' ];
}
Simply appending to the command line appears challenging (see below).
Example 1:
debug.doFirst(){
// ... <snip> ...
// command line arguments
//
println " debug args (a): ${args}."
runArgs.add( "-memo=${project.name}:debug" );
args = runArgs;
println " debug args (b): ${args}."
}
Output is correct, shows "-memo" parameter is added but also the passed-in args have been replaced by the script variable using this approach.
debug args (a): [-server, localhost, -port, 8080 ].
debug args (b): [-server=localhost, -port=8080, -memo=Client:debug].
Example 2:
debug.doFirst(){
// ... <snip> ...
// command line arguments
//
println " debug args (a): ${args}."
args.add( "-memo=${project.name}:debug" );
println " debug args (b): ${args}."
}
Output (correctly?) shows there was no add(), per answer: from Opal above.
debug args (a): [-server, localhost, -port, 8080 ].
debug args (b): [-server, localhost, -port, 8080 ].
I've posted this example to show that there may be alternatives to accepting the status quo, i expect the jvmArgs to work in a similar pattern. I didn't find examples for adding extra debug specific arguments (say). So here is one.
I also saw in a couple of places (on-line and books), examples such as:
jvmArgs.add( "-DAPPLICATION_LOCATION=City" );
jvmArgs.add( "-DSERVER_HOST=localhost" );
Which as we now understand, do not work.
The use-case I set-out to implement is for the sub-project build.gradle Script to supply missing arguments and/or script specific parameters (e.g. as in the debug run example). It is clear to me that if you want to do this, the script will need to either replace the command line or analyse the args passed-in and then wrinkle-out the defaults by some mechanism.
Hopefully the example will give others more insight.
Actually this hack is working:
def jvmArgsCopy = jvmArgs
jvmArgsCopy.add("-XX:MaxDirectMemorySize=2g")
jvmArgs = jvmArgsCopy
And to add to this here it is in Kotlin gradle
val jvmArgsCopy: ArrayList<String> = jvmArgs as ArrayList<String>
jvmArgsCopy.add("-Xdebug")
jvmArgsCopy.add("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=4000")
jvmArgs = jvmArgsCopy
I have read around stackoverflow and the gradle forms, but I am still stumped. The ultimate goal here is that after I copy some files, I want to set the writable flag -- because 'copy' doesn't like overwriting read-only files on 'nix (huh...), nor can it be forced to do so (harumph!).
Here is the outline of what I have:
task setPermissions (type : Exec) {
executable = 'chmod -R +w'
}
// ... a little while later ...
task('somethingElse') << {
// ... unrelated stuff ...
def String targetDir = "$aVar/theTarget"
// >> TASK CALL <<
setPermissions {
commandLine = [executable + " $targetDir"]
}
// but that doesn't work... this does...
proc = Runtime.getRuntime().exec("chmod -R +w $deployDir")
proc.waitFor()
}
I have tried variations in "setPermissions".
Trial 1:
commandLine = 'chmod'
args = '-R', '+w'
In which case I appended the target directory to "args" when I called setPermissions.
Trial 2:
commandLine = 'chmod -R +w'
In which case I appended the target directory to "commandLine" when I called setPermissions. I also tried making it the only "args" value.
Trial 3:
commandLine = 'chmod', '-R', '+w'
In which case I appended the target directory to "commandLine" when I called setPermissions. I also tried making it the only "args" value.
So what am I doing wrong here that an Exec task won't run this properly, but the Rt.gR.exec() will?
You can't call a task from another task. You'll have to make one depend on the other, or call the Project.exec method from a task action. The syntax for configuring the exec method is exactly the same as for the Exec task.
PS: Have you tried to use Copy.fileMode instead of chmod?
I am using a Phing build script with Jenkins and would like to run it end to end on a job and capture all the reports. The problem is it stop building on a failed build step. Is there a way or a plugin that would continue the job even on failures?
Thanks
I don't know a lot about Phing but, since it's based on Ant, if the build step you are executing has a "failonerror" attribute you should be able to set it to false so that the entire build doesn't fail if the step returns an error.
Yes, use try, catch block in you pipeline scripts
example:
try {
// do some stuff that potentially fails
} catch (error) {
// do stuff if try fails
} finally {
// when you need some clean up to do
}
Or alternatively if you use sh commands to run these tests, consider running your sh scripts with the "|| true" suffix, this tells the linux sh script to exit with a result code of 0, even if your real command exited with an exit code.
example:
stage('Test') {
def testScript = ""
def testProjects = findFiles(glob: 'test/**/project.json')
if (!fileExists('reports/xml')) {
if (!fileExists('reports')) {
sh "mkdir reports"
}
sh "mkdir reports/xml"
}
for(prj in testProjects) {
println "Test project located, running tests: " + prj.path
def matcher = prj.path =~ 'test\\/(.+)\\/project.json'
testScript += "dotnet test --no-build '${prj.path}' -xml 'reports/xml/${matcher[0][1]}.Results.xml' || true\n"
}
sh testScript