diff --git a/build.gradle b/build.gradle index cffa741df..71f536ec2 100644 --- a/build.gradle +++ b/build.gradle @@ -427,7 +427,7 @@ createNpmPackage.dependsOn(copyReadme) task createPackage { println "CCache version: " + getCCacheVersion() - description "Builds the NativeScript Android cleanBuildArtefactsApp Package using an application project template." + description = "Builds the NativeScript Android cleanBuildArtefactsApp Package using an application project template." dependsOn createNpmPackage println "Creating NativeScript Android Package" } diff --git a/test-app/app/build.gradle b/test-app/app/build.gradle index da7d2c5f1..9fbc263bf 100644 --- a/test-app/app/build.gradle +++ b/test-app/app/build.gradle @@ -217,7 +217,7 @@ def computeNamespace = { -> } android { - namespace computeNamespace() + namespace = computeNamespace() applyBeforePluginGradleConfiguration() @@ -271,7 +271,7 @@ android { } buildTypes { release { - signingConfig signingConfigs.release + signingConfig = signingConfigs.release } } @@ -703,7 +703,7 @@ def resolveCompileSdkPlatformName(File sdkDirectory, String compileSdkVersion) { task 'collectAllJars' { dependsOn extractAllJars - description "gathers all paths to jar dependencies before building metadata with them" + description = "gathers all paths to jar dependencies before building metadata with them" def sdkPath = android.sdkDirectory.getAbsolutePath() @@ -964,7 +964,7 @@ task buildMetadata(type: BuildToolTask) { //buildMetadata.finalizedBy(copyMetadata) finalizedBy copyMetadata - description "builds metadata with provided jar dependencies" + description = "builds metadata with provided jar dependencies" inputs.files("$MDG_JAVA_DEPENDENCIES") diff --git a/test-app/app/gradle-helpers/BuildToolTask.gradle b/test-app/app/gradle-helpers/BuildToolTask.gradle index 7b6052f4c..c744f570b 100644 --- a/test-app/app/gradle-helpers/BuildToolTask.gradle +++ b/test-app/app/gradle-helpers/BuildToolTask.gradle @@ -6,8 +6,8 @@ class BuildToolTask extends JavaExec { if(logFile.exists()) { logFile.delete() } - standardOutput new FileOutputStream(logFile) - errorOutput new FailureOutputStream(logger, logFile) + standardOutput = new FileOutputStream(logFile) + errorOutput = new FailureOutputStream(logger, logFile) } } diff --git a/test-app/app/gradle-helpers/CustomExecutionLogger.gradle b/test-app/app/gradle-helpers/CustomExecutionLogger.gradle index ec8ea6c42..0367b870c 100644 --- a/test-app/app/gradle-helpers/CustomExecutionLogger.gradle +++ b/test-app/app/gradle-helpers/CustomExecutionLogger.gradle @@ -1,52 +1,60 @@ +import org.gradle.api.services.BuildService +import org.gradle.api.services.BuildServiceParameters +import org.gradle.build.event.BuildEventsListenerRegistry +import org.gradle.internal.logging.text.StyledTextOutput import org.gradle.internal.logging.text.StyledTextOutputFactory +import org.gradle.tooling.events.FinishEvent +import org.gradle.tooling.events.OperationCompletionListener +import org.gradle.tooling.events.task.TaskFailureResult +import org.gradle.tooling.events.task.TaskFinishEvent import static org.gradle.internal.logging.text.StyledTextOutput.Style -def outLogger = services.get(StyledTextOutputFactory).create("colouredOutputLogger") - -class CustomExecutionLogger extends BuildAdapter implements TaskExecutionListener { - private logger - private failedTask - CustomExecutionLogger(passedLogger) { - logger = passedLogger - } +abstract class CustomExecutionLogger implements BuildService, OperationCompletionListener, AutoCloseable { + // BuildToolTask already logs its own errors; its failures are not repeated here. + final Set selfReportingTaskPaths = Collections.synchronizedSet(new HashSet()) + private final List failures = Collections.synchronizedList(new ArrayList()) - void buildStarted(Gradle gradle) { - failedTask = null - } + // StyledTextOutputFactory cannot be injected into a BuildService, so the output is handed over from the script. + StyledTextOutput output - void beforeExecute(Task task) { - } - - void afterExecute(Task task, TaskState state) { - def failure = state.getFailure() - if(failure) { - failedTask = task + @Override + void onFinish(FinishEvent event) { + if (event instanceof TaskFinishEvent && event.result instanceof TaskFailureResult) { + if (!selfReportingTaskPaths.contains(event.descriptor.taskPath)) { + failures.addAll(event.result.failures) + } } } - void buildFinished(BuildResult result) { - def failure = result.getFailure() - if(failure) { - if(failedTask && (failedTask.getClass().getName().contains("BuildToolTask"))) { - // the error from this task is already logged - return - } - - println "" - logger.withStyle(Style.FailureHeader).println failure.getMessage() + // Build services are closed once all tasks have finished, which makes close() the end-of-build hook. + @Override + void close() { + if (failures.isEmpty() || output == null) { + return + } + failures.each { failure -> + output.println() + output.withStyle(Style.FailureHeader).println failure.message - def causeException = failure.getCause() - while (causeException != null) { - failure = causeException - causeException = failure.getCause() + def rootCause = failure + while (!rootCause.causes.isEmpty()) { + rootCause = rootCause.causes[0] } - if(failure != causeException) { - logger.withStyle(Style.Failure).println failure.getMessage() + if (rootCause != failure) { + output.withStyle(Style.Failure).println rootCause.message } - println "" + output.println() } } } -gradle.useLogger(new CustomExecutionLogger(outLogger)) \ No newline at end of file +def customExecutionLogger = gradle.sharedServices.registerIfAbsent("nsCustomExecutionLogger", CustomExecutionLogger) {} +services.get(BuildEventsListenerRegistry).onTaskCompletion(customExecutionLogger) + +def outLogger = services.get(StyledTextOutputFactory).create("colouredOutputLogger") +gradle.taskGraph.whenReady { graph -> + customExecutionLogger.get().output = outLogger + def selfReporting = graph.allTasks.findAll { it.getClass().getName().contains("BuildToolTask") }*.path + customExecutionLogger.get().selfReportingTaskPaths.addAll(selfReporting) +} diff --git a/test-app/build-tools/jsparser/tests/specs/ast-parser-tests.spec.js b/test-app/build-tools/jsparser/tests/specs/ast-parser-tests.spec.js index b8030989c..a05c6b4fe 100644 --- a/test-app/build-tools/jsparser/tests/specs/ast-parser-tests.spec.js +++ b/test-app/build-tools/jsparser/tests/specs/ast-parser-tests.spec.js @@ -3,11 +3,11 @@ const exec = require("child_process").exec, fs = require("fs"), prefix = path.resolve(__dirname, "../cases/"), sbgBindingOutoutFile = path.resolve(__dirname, "../../../sbg-bindings.txt"), - testsGradleFile = path.resolve(__dirname, "../../../static-binding-generator/runtests.gradle"), + sbgProjectDir = path.resolve(__dirname, "../../../static-binding-generator"), gradleExecutable = path.resolve(__dirname, "../../../../../gradlew"); function execGradle(inputPath, generatedJavaClassesRoot, callback) { - const command = `${gradleExecutable} -b ${testsGradleFile} -PappRoot=${inputPath} -PgeneratedJavaClassesRoot=${generatedJavaClassesRoot}`; + const command = `${gradleExecutable} -p ${sbgProjectDir} -PappRoot=${inputPath} -PgeneratedJavaClassesRoot=${generatedJavaClassesRoot}`; const options = { cwd: path.dirname(gradleExecutable) }; diff --git a/test-app/build-tools/static-binding-generator/runtests.gradle b/test-app/build-tools/static-binding-generator/runtests.gradle index 321ae9f68..d46dd2141 100644 --- a/test-app/build-tools/static-binding-generator/runtests.gradle +++ b/test-app/build-tools/static-binding-generator/runtests.gradle @@ -76,7 +76,7 @@ task prepareInputFiles { task runSbg(type: JavaExec, dependsOn: 'prepareInputFiles') { classpath = files('build/libs/static-binding-generator.jar', '../') workingDir = "../" - main = "org.nativescript.staticbindinggenerator.Main" + mainClass = "org.nativescript.staticbindinggenerator.Main" } java { sourceCompatibility = JavaVersion.VERSION_17 diff --git a/test-app/build-tools/static-binding-generator/settings.gradle b/test-app/build-tools/static-binding-generator/settings.gradle index 48f57764a..6134158c2 100644 --- a/test-app/build-tools/static-binding-generator/settings.gradle +++ b/test-app/build-tools/static-binding-generator/settings.gradle @@ -1 +1,3 @@ -// empty file to avoid using settings.gradle file from test-app \ No newline at end of file +// Only read when this directory is built standalone (`gradlew -p`, as the jsparser tests do); +// as a test-app subproject, test-app's settings and build.gradle apply instead. +rootProject.buildFileName = 'runtests.gradle' diff --git a/test-app/build.gradle b/test-app/build.gradle index 99a1643b2..9799ab860 100644 --- a/test-app/build.gradle +++ b/test-app/build.gradle @@ -134,8 +134,10 @@ version of the {N} CLI install a previous version of the runtime package - 'tns def computeKotlinVersion = { -> project.hasProperty("kotlinVersion") ? kotlinVersion : "${ns_default_kotlin_version}" } def computeBuildToolsVersion = { -> project.hasProperty("androidBuildToolsVersion") ? androidBuildToolsVersion : "${NS_DEFAULT_ANDROID_BUILD_TOOLS_VERSION}" } + def computeR8Version = { -> project.hasProperty("r8Version") ? r8Version : "${NS_DEFAULT_R8_VERSION}" } def kotlinVersion = computeKotlinVersion() def androidBuildToolsVersion = computeBuildToolsVersion() + def r8Version = computeR8Version() repositories { google() @@ -143,6 +145,7 @@ version of the {N} CLI install a previous version of the runtime package - 'tns } dependencies { classpath "com.android.tools.build:gradle:$androidBuildToolsVersion" + classpath "com.android.tools:r8:$r8Version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" classpath "org.apache.groovy:groovy-all:4.0.21" } diff --git a/test-app/gradle.properties b/test-app/gradle.properties index d5a310dc5..e58b0da6b 100644 --- a/test-app/gradle.properties +++ b/test-app/gradle.properties @@ -22,7 +22,9 @@ android.useAndroidX=true NS_DEFAULT_BUILD_TOOLS_VERSION=35.0.0 NS_DEFAULT_COMPILE_SDK_VERSION=35 NS_DEFAULT_MIN_SDK_VERSION=21 -NS_DEFAULT_ANDROID_BUILD_TOOLS_VERSION=8.12.1 +NS_DEFAULT_ANDROID_BUILD_TOOLS_VERSION=8.13.2 +# R8 8.x cannot read Kotlin 2.4 metadata (needs 9.1.29+), so the AGP-bundled R8 is overridden. +NS_DEFAULT_R8_VERSION=9.1.43 ns_default_androidx_appcompat_version = 1.7.0 ns_default_androidx_exifinterface_version = 1.3.7 diff --git a/test-app/runtime/build.gradle b/test-app/runtime/build.gradle index 57a5173d1..4add7d915 100644 --- a/test-app/runtime/build.gradle +++ b/test-app/runtime/build.gradle @@ -80,7 +80,7 @@ base { } android { - namespace "com.tns.android_runtime" + namespace = "com.tns.android_runtime" compileSdk NS_DEFAULT_COMPILE_SDK_VERSION as int buildToolsVersion = NS_DEFAULT_BUILD_TOOLS_VERSION as String @@ -96,9 +96,9 @@ android { } if (hasNdkVersion) { - ndkVersion project.ndkVersion + ndkVersion = project.ndkVersion } else { - ndkVersion defaultNdkVersion + ndkVersion = defaultNdkVersion } defaultConfig { @@ -152,8 +152,8 @@ android { } externalNativeBuild { cmake { - version "3.31.6" - path "CMakeLists.txt" + version = "3.31.6" + path = "CMakeLists.txt" } } @@ -320,7 +320,7 @@ def createPackageConfigFileTask(taskName) { def removeCmdParams = new ArrayList([aaptCommand, "remove", pathToAAR, "config.json"]) exec { - ignoreExitValue true + ignoreExitValue = true workingDir "$projectDir/src/main" commandLine removeCmdParams.toArray() }