From ad174cffa474eee9a2eaf78c2d72dce9e4cd6cb8 Mon Sep 17 00:00:00 2001 From: Maanrifa Bacar Ali Date: Sat, 29 Jun 2024 09:29:19 +0200 Subject: [PATCH 1/4] fix(gradle-plugin): prevent Gradle sync from failing when `import_map_template.json` is not present --- .../task/SupabaseFunctionAggregateImportMapTask.kt | 12 ++++++++---- .../github/manriif/supabase/functions/task/Tasks.kt | 10 +++++++++- gradle/libs.versions.toml | 2 +- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/SupabaseFunctionAggregateImportMapTask.kt b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/SupabaseFunctionAggregateImportMapTask.kt index b66d5a7..d1f4f19 100644 --- a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/SupabaseFunctionAggregateImportMapTask.kt +++ b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/SupabaseFunctionAggregateImportMapTask.kt @@ -29,11 +29,13 @@ import io.github.manriif.supabase.functions.error.SupabaseFunctionImportMapTempl import io.github.manriif.supabase.functions.supabase.supabaseAllFunctionsDirFile import org.gradle.api.DefaultTask import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.RegularFileProperty import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.IgnoreEmptyDirectories import org.gradle.api.tasks.InputDirectory import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.Optional import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.PathSensitive import org.gradle.api.tasks.PathSensitivity @@ -58,9 +60,9 @@ abstract class SupabaseFunctionAggregateImportMapTask : DefaultTask() { internal abstract val supabaseDir: DirectoryProperty @get:InputFile + @get:Optional @get:PathSensitive(PathSensitivity.RELATIVE) - internal val importMapTemplateFile: File - get() = supabaseAllFunctionsDirFile(supabaseDir, IMPORT_MAP_TEMPLATE_FILE_NAME) + internal abstract val importMapTemplateFile: RegularFileProperty @get:OutputFile internal val aggregatedImportMapFile: File @@ -72,9 +74,11 @@ abstract class SupabaseFunctionAggregateImportMapTask : DefaultTask() { .setPrettyPrinting() .create() - val importMap = if (importMapTemplateFile.exists() && importMapTemplateFile.isFile) { + val template = importMapTemplateFile.orNull?.asFile + + val importMap = if (template?.exists() == true && template.isFile) { try { - JsonParser.parseReader(importMapTemplateFile.reader()).asJsonObject + JsonParser.parseReader(template.reader()).asJsonObject } catch (throwable: Throwable) { throw SupabaseFunctionImportMapTemplateException( message = "Failed to load $IMPORT_MAP_TEMPLATE_FILE_NAME", diff --git a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/Tasks.kt b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/Tasks.kt index 6307971..7fe779a 100644 --- a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/Tasks.kt +++ b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/Tasks.kt @@ -21,6 +21,7 @@ */ package io.github.manriif.supabase.functions.task +import io.github.manriif.supabase.functions.IMPORT_MAP_TEMPLATE_FILE_NAME import io.github.manriif.supabase.functions.KOTLIN_MAIN_FUNCTION_NAME import io.github.manriif.supabase.functions.REQUEST_CONFIG_FILE_NAME import io.github.manriif.supabase.functions.SUPABASE_FUNCTION_OUTPUT_DIR @@ -93,8 +94,15 @@ private fun Project.registerAggregateImportMapTask(extension: SupabaseFunctionEx group = SUPABASE_FUNCTION_TASK_GROUP description = "Aggregate functions import maps." - importMapsDir.convention(layout.buildDirectory.dir("${SUPABASE_FUNCTION_OUTPUT_DIR}/importMaps")) supabaseDir.convention(extension.supabaseDir) + + importMapsDir.convention( + layout.buildDirectory.dir("${SUPABASE_FUNCTION_OUTPUT_DIR}/importMaps") + ) + + importMapTemplateFile.convention( + extension.supabaseDir.file("functions/$IMPORT_MAP_TEMPLATE_FILE_NAME").orNone() + ) } tasks.named(PREPARE_KOTLIN_BUILD_SCRIPT_MODEL_TASK) { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fc87d67..ce3f37c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] # Projct version -supabase-functions = "0.0.2" +supabase-functions = "0.0.3" jvm-target = "11" From 614d795022e0d24e1ee1608decc242a3b4c19b0a Mon Sep 17 00:00:00 2001 From: Maanrifa Bacar Ali Date: Sat, 29 Jun 2024 09:54:38 +0200 Subject: [PATCH 2/4] refactor(gradle-plugin): print a message explaining common causes of build failure --- .../manriif/supabase/functions/task/Tasks.kt | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/Tasks.kt b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/Tasks.kt index 7fe779a..560b058 100644 --- a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/Tasks.kt +++ b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/Tasks.kt @@ -25,6 +25,7 @@ import io.github.manriif.supabase.functions.IMPORT_MAP_TEMPLATE_FILE_NAME import io.github.manriif.supabase.functions.KOTLIN_MAIN_FUNCTION_NAME import io.github.manriif.supabase.functions.REQUEST_CONFIG_FILE_NAME import io.github.manriif.supabase.functions.SUPABASE_FUNCTION_OUTPUT_DIR +import io.github.manriif.supabase.functions.SUPABASE_FUNCTION_PLUGIN_NAME import io.github.manriif.supabase.functions.SUPABASE_FUNCTION_TASK_GROUP import io.github.manriif.supabase.functions.SupabaseFunctionExtension import io.github.manriif.supabase.functions.kmp.JsDependency @@ -167,10 +168,18 @@ private fun Project.registerCopyKotlinTask( val compileSyncTaskName = "js${uppercaseEnvironment}LibraryCompileSync" if (tasks.names.none { it == compileSyncTaskName }) { - error( - "Could not locate task `$compileSyncTaskName`, " + - "be sure you add `binaries.library()` to the js node target." + logger.error( + """ + Could not locate task `$compileSyncTaskName`, common reasons for this error are: + + - The `$SUPABASE_FUNCTION_PLUGIN_NAME` plugin was applied on a build script where the kotlin multiplatform plugin was not applied (e.g., root build script) + - The kotlin multiplatform plugin was not applied on this project + - JS target was not initialized on this project + - JS target is missing `binaries.library()` + """.trimIndent() ) + + error("Could not locate task `$compileSyncTaskName`, check the logs for possible causes.") } val taskName = TASK_GENERATE_ENVIRONMENT_TEMPLATE.format(uppercaseEnvironment) From 4a7373c49efa96b5ff39b86b8211f484a62f37f8 Mon Sep 17 00:00:00 2001 From: Maanrifa Bacar Ali Date: Sat, 29 Jun 2024 14:27:46 +0200 Subject: [PATCH 3/4] fix(gradle-plugin): postpone build configuration errors at task execution Build script misconfiguration will now be reported at task execution instead of during project sync. This allows to progressively configure build script. --- .../manriif/supabase/functions/Constants.kt | 1 + .../functions/SupabaseFunctionExtension.kt | 4 + .../manriif/supabase/functions/kmp/Kmp.kt | 81 +++++++++++-------- .../task/SupabaseFunctionCopyJsTask.kt | 2 +- .../task/SupabaseFunctionCopyKotlinTask.kt | 2 + .../SupabaseFunctionGenerateImportMapTask.kt | 12 +-- .../manriif/supabase/functions/task/Tasks.kt | 81 ++++++++++--------- .../manriif/supabase/functions/util/Error.kt | 13 +++ .../manriif/supabase/functions/util/Files.kt | 6 +- gradle/libs.versions.toml | 2 +- 10 files changed, 122 insertions(+), 82 deletions(-) create mode 100644 gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/util/Error.kt diff --git a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/Constants.kt b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/Constants.kt index 4bf1718..631eab7 100644 --- a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/Constants.kt +++ b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/Constants.kt @@ -31,6 +31,7 @@ internal const val COROUTINES_VERSION_GRADLE_PROPERTY = "supabase.functions.coro internal const val DENO_KOTLIN_BRIDGE_FUNCTION_NAME = "denoKotlinBridge" internal const val KOTLIN_MAIN_FUNCTION_NAME = "serve" +internal const val IMPORT_MAPS_DIRECTORY_NAME = "importMaps" internal const val GITIGNORE_FILE_NAME = ".gitignore" internal const val IMPORT_MAP_TEMPLATE_FILE_NAME = "import_map_template.json" internal const val IMPORT_MAP_FILE_NAME = "import_map.json" diff --git a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/SupabaseFunctionExtension.kt b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/SupabaseFunctionExtension.kt index 6796380..864b2da 100644 --- a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/SupabaseFunctionExtension.kt +++ b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/SupabaseFunctionExtension.kt @@ -101,4 +101,8 @@ internal fun SupabaseFunctionExtension.setupConvention(project: Project) { functionName.convention(project.name) verifyJwt.convention(true) importMap.convention(true) + + packageName.convention(project.provider { + error("packageName is not set, please provide the package name of the kotlin main function.") + }) } \ No newline at end of file diff --git a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/kmp/Kmp.kt b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/kmp/Kmp.kt index 54985c0..d0a0fb9 100644 --- a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/kmp/Kmp.kt +++ b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/kmp/Kmp.kt @@ -24,9 +24,12 @@ package io.github.manriif.supabase.functions.kmp import io.github.manriif.supabase.functions.COROUTINES_VERSION import io.github.manriif.supabase.functions.COROUTINES_VERSION_GRADLE_PROPERTY import io.github.manriif.supabase.functions.SUPABASE_FUNCTION_PLUGIN_NAME +import io.github.manriif.supabase.functions.task.SupabaseFunctionCopyKotlinTask import io.github.manriif.supabase.functions.task.TASK_GENERATE_BRIDGE +import io.github.manriif.supabase.functions.util.postponeErrorOnTaskInvocation import org.gradle.api.Project import org.gradle.kotlin.dsl.withType +import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi import org.jetbrains.kotlin.gradle.dsl.JsModuleKind import org.jetbrains.kotlin.gradle.dsl.JsSourceMapEmbedMode import org.jetbrains.kotlin.gradle.dsl.JsSourceMapNamesPolicy @@ -36,7 +39,6 @@ import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget internal fun Project.setupKotlinMultiplatform(kmpExtension: KotlinMultiplatformExtension) { kmpExtension.targets.withType().configureEach { - ensureMeetRequirements() configureCompilation() } @@ -48,57 +50,66 @@ internal fun Project.setupKotlinMultiplatform(kmpExtension: KotlinMultiplatformE implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:${coroutinesVersion}") } } + + afterEvaluate { + kmpExtension.targets.withType().forEach { target -> + target.checkUserConfiguration() + } + } +} + +private fun KotlinJsIrTarget.configureCompilation() { + @OptIn(ExperimentalKotlinGradlePluginApi::class) + compilerOptions { + // [KT-47968](https://youtrack.jetbrains.com/issue/KT-47968/KJS-IR-Debug-in-external-tool-cant-step-into-library-function-with-available-sources) + // [KT-49757](https://youtrack.jetbrains.com/issue/KT-49757/Kotlin-JS-support-sourceMapEmbedSources-setting-by-IR-backend) + sourceMap.set(true) + sourceMapNamesPolicy.set(JsSourceMapNamesPolicy.SOURCE_MAP_NAMES_POLICY_FQ_NAMES) + sourceMapEmbedSources.set(JsSourceMapEmbedMode.SOURCE_MAP_SOURCE_CONTENT_ALWAYS) + } + + compilations.named(KotlinCompilation.MAIN_COMPILATION_NAME) { + compileTaskProvider.configure { + dependsOn(TASK_GENERATE_BRIDGE) + } + } } -private fun KotlinJsIrTarget.ensureMeetRequirements() { +private fun KotlinJsIrTarget.checkUserConfiguration() { + if (isBrowserConfigured) { + project.logger.warn( + "Browser execution environment is not supported by " + + "`$SUPABASE_FUNCTION_PLUGIN_NAME` plugin." + ) + } + val granularity = project.findProperty("kotlin.js.ir.output.granularity")?.toString() if (!(granularity.isNullOrBlank() || granularity == "per-module")) { - error( + project.postponeErrorOnTaskInvocation( "Only `per-module` JS IR output granularity is supported " + "by `$SUPABASE_FUNCTION_PLUGIN_NAME` plugin. " + "Current granularity is `$granularity`." ) } - if (isBrowserConfigured) { - error( - "Browser execution environment is not supported by " + - "`$SUPABASE_FUNCTION_PLUGIN_NAME` plugin." + val compilation = compilations.findByName(KotlinCompilation.MAIN_COMPILATION_NAME) + + // Module kind is not set when using new compiler option DSL, fallback to deprecated one + val options = @Suppress("DEPRECATION") compilation?.compilerOptions?.options + val moduleKind = options?.moduleKind?.orNull + + if (moduleKind != JsModuleKind.MODULE_ES) { + project.postponeErrorOnTaskInvocation( + "Plugin `supabase-function` only supports ES module kind. " + + "Current module kind is `$moduleKind`." ) } if (!isNodejsConfigured) { - error( + project.postponeErrorOnTaskInvocation( "Node.js execution environment is a requirement " + "for `$SUPABASE_FUNCTION_PLUGIN_NAME` plugin." ) } -} - -private fun KotlinJsIrTarget.configureCompilation() { - compilations.named(KotlinCompilation.MAIN_COMPILATION_NAME) { - // Module kind is not set when using new compiler option DSL, fallback to deprecated one - @Suppress("DEPRECATION") - compilerOptions.configure { - val kind = moduleKind.orNull - - if (kind != JsModuleKind.MODULE_ES) { - error( - "Plugin `supabase-function` only supports ES module kind. " + - "Current module kind is $kind." - ) - } - - // [KT-47968](https://youtrack.jetbrains.com/issue/KT-47968/KJS-IR-Debug-in-external-tool-cant-step-into-library-function-with-available-sources) - // [KT-49757](https://youtrack.jetbrains.com/issue/KT-49757/Kotlin-JS-support-sourceMapEmbedSources-setting-by-IR-backend) - sourceMap.set(true) - sourceMapNamesPolicy.set(JsSourceMapNamesPolicy.SOURCE_MAP_NAMES_POLICY_FQ_NAMES) - sourceMapEmbedSources.set(JsSourceMapEmbedMode.SOURCE_MAP_SOURCE_CONTENT_ALWAYS) - } - - compileTaskProvider.configure { - dependsOn(TASK_GENERATE_BRIDGE) - } - } } \ No newline at end of file diff --git a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/SupabaseFunctionCopyJsTask.kt b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/SupabaseFunctionCopyJsTask.kt index 592c422..2282e1a 100644 --- a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/SupabaseFunctionCopyJsTask.kt +++ b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/SupabaseFunctionCopyJsTask.kt @@ -40,7 +40,7 @@ import java.io.File import javax.inject.Inject /** - * Task responsible for copying generated js code into supabase function directory. + * Task responsible for copying js sources into supabase function directory. */ @CacheableTask abstract class SupabaseFunctionCopyJsTask : DefaultTask() { diff --git a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/SupabaseFunctionCopyKotlinTask.kt b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/SupabaseFunctionCopyKotlinTask.kt index 5cd2be9..e99040a 100644 --- a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/SupabaseFunctionCopyKotlinTask.kt +++ b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/SupabaseFunctionCopyKotlinTask.kt @@ -32,6 +32,7 @@ import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.Input import org.gradle.api.tasks.InputDirectory import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.Optional import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.PathSensitive import org.gradle.api.tasks.PathSensitivity @@ -52,6 +53,7 @@ abstract class SupabaseFunctionCopyKotlinTask : DefaultTask() { internal abstract val supabaseDir: DirectoryProperty @get:InputDirectory + @get:Optional @get:PathSensitive(PathSensitivity.RELATIVE) internal abstract val compiledSourceDir: DirectoryProperty diff --git a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/SupabaseFunctionGenerateImportMapTask.kt b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/SupabaseFunctionGenerateImportMapTask.kt index 6d74ea9..ec91d54 100644 --- a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/SupabaseFunctionGenerateImportMapTask.kt +++ b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/SupabaseFunctionGenerateImportMapTask.kt @@ -29,13 +29,15 @@ import io.github.manriif.supabase.functions.JS_SOURCES_INPUT_DIR import io.github.manriif.supabase.functions.kmp.JsDependency import org.gradle.api.DefaultTask import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.RegularFileProperty import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputDirectory +import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.Internal import org.gradle.api.tasks.Nested +import org.gradle.api.tasks.Optional import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.PathSensitive import org.gradle.api.tasks.PathSensitivity @@ -64,9 +66,10 @@ abstract class SupabaseFunctionGenerateImportMapTask : DefaultTask() { @get:Internal internal abstract val importMapsDir: DirectoryProperty - @get:InputDirectory + @get:InputFile + @get:Optional @get:PathSensitive(PathSensitivity.RELATIVE) - internal abstract val packageJsonDir: DirectoryProperty + internal abstract val packageJsonFile: RegularFileProperty @get:Input internal abstract val functionName: Property @@ -94,8 +97,7 @@ abstract class SupabaseFunctionGenerateImportMapTask : DefaultTask() { private fun createFunctionImports(): JsonObject { val imports = JsonObject() - val packageJsonFile = packageJsonDir.file("package.json").get().asFile - val packageJson = fromSrcPackageJson(packageJsonFile) ?: return imports + val packageJson = fromSrcPackageJson(packageJsonFile.orNull?.asFile) ?: return imports packageJson.dependencies.forEach { (packageName, version) -> imports.addProperty(packageName, "npm:$packageName@$version") diff --git a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/Tasks.kt b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/Tasks.kt index 560b058..7591c83 100644 --- a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/Tasks.kt +++ b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/Tasks.kt @@ -21,6 +21,7 @@ */ package io.github.manriif.supabase.functions.task +import io.github.manriif.supabase.functions.IMPORT_MAPS_DIRECTORY_NAME import io.github.manriif.supabase.functions.IMPORT_MAP_TEMPLATE_FILE_NAME import io.github.manriif.supabase.functions.KOTLIN_MAIN_FUNCTION_NAME import io.github.manriif.supabase.functions.REQUEST_CONFIG_FILE_NAME @@ -43,6 +44,7 @@ import org.gradle.kotlin.dsl.support.uppercaseFirstChar import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension internal const val PREPARE_KOTLIN_BUILD_SCRIPT_MODEL_TASK = "prepareKotlinBuildScriptModel" +internal const val JS_PUBLIC_PACKAGE_JSON_TASK = "jsPublicPackageJson" internal const val TASK_PREFIX = "supabaseFunction" internal const val TASK_GENERATE_ENVIRONMENT_TEMPLATE = "${TASK_PREFIX}CopyKotlin%s" @@ -70,7 +72,7 @@ internal fun Project.configurePluginTasks( val jsDependenciesProvider = jsDependencies() registerGenerateImportMapTask(extension, jsDependenciesProvider) - registerGenerateBridgeTask(extension, kmpExtension) + registerGenerateKotlinBridgeTask(extension, kmpExtension) registerCopyJsTask(extension, jsDependenciesProvider) registerCopyKotlinTask(extension, "development") registerCopyKotlinTask(extension, "production") @@ -98,7 +100,7 @@ private fun Project.registerAggregateImportMapTask(extension: SupabaseFunctionEx supabaseDir.convention(extension.supabaseDir) importMapsDir.convention( - layout.buildDirectory.dir("${SUPABASE_FUNCTION_OUTPUT_DIR}/importMaps") + layout.buildDirectory.dir("${SUPABASE_FUNCTION_OUTPUT_DIR}/$IMPORT_MAPS_DIRECTORY_NAME") ) importMapTemplateFile.convention( @@ -120,16 +122,11 @@ private val Project.aggregateTaskProvider: TaskProvider(TASK_GENERATE_BRIDGE) { group = SUPABASE_FUNCTION_TASK_GROUP @@ -137,13 +134,19 @@ private fun Project.registerGenerateBridgeTask( description = "Generate a kotlin function that acts as a bridge between " + "the `Deno.serve` and the kotlin main function." + packageName.convention(extension.packageName) supabaseDir.convention(extension.supabaseDir) generatedSourceOutputDir.convention(outputDir) - packageName.convention(extension.packageName) jsOutputName.convention(jsOutputName(kmpExtension)) functionName.convention(extension.functionName) mainFunctionName.convention(KOTLIN_MAIN_FUNCTION_NAME) } + + afterEvaluate { + kmpExtension.sourceSets.named { it == "jsMain" }.configureEach { + kotlin.srcDir(outputDir) + } + } } private fun Project.registerCopyJsTask( @@ -166,22 +169,6 @@ private fun Project.registerCopyKotlinTask( ) { val uppercaseEnvironment = environment.uppercaseFirstChar() val compileSyncTaskName = "js${uppercaseEnvironment}LibraryCompileSync" - - if (tasks.names.none { it == compileSyncTaskName }) { - logger.error( - """ - Could not locate task `$compileSyncTaskName`, common reasons for this error are: - - - The `$SUPABASE_FUNCTION_PLUGIN_NAME` plugin was applied on a build script where the kotlin multiplatform plugin was not applied (e.g., root build script) - - The kotlin multiplatform plugin was not applied on this project - - JS target was not initialized on this project - - JS target is missing `binaries.library()` - """.trimIndent() - ) - - error("Could not locate task `$compileSyncTaskName`, check the logs for possible causes.") - } - val taskName = TASK_GENERATE_ENVIRONMENT_TEMPLATE.format(uppercaseEnvironment) tasks.register(taskName) { @@ -189,13 +176,29 @@ private fun Project.registerCopyKotlinTask( description = "Copy Kotlin generated sources into supabase function directory." compiledSourceDir.convention( - layout.buildDirectory.dir("compileSync/js/main/${environment}Library/kotlin") + layout.buildDirectory.dir("compileSync/js/main/${environment}Library/kotlin").orNone() ) supabaseDir.convention(extension.supabaseDir) functionName.convention(extension.functionName) - dependsOn(compileSyncTaskName) + if (tasks.names.none { it == compileSyncTaskName }) { + doFirst { + error( + """ + Task `$compileSyncTaskName` was not found during project sync, common reasons for this error are: + + - The `$SUPABASE_FUNCTION_PLUGIN_NAME` plugin was applied on a build script where the kotlin multiplatform plugin was not applied (e.g., root build script) + - The kotlin multiplatform plugin was not applied on this project + - JS target was not initialized on this project + - JS target is missing `binaries.library()` + """.trimIndent() + ) + } + } else { + dependsOn(compileSyncTaskName) + } + dependsOn(TASK_COPY_JS) } } @@ -270,20 +273,24 @@ private fun Project.registerGenerateImportMapTask( group = SUPABASE_FUNCTION_TASK_GROUP description = "Generate import map." - packageJsonDir.convention(layout.buildDirectory.dir("tmp/jsPublicPackageJson")) + importMapsDir.convention( + rootProject.layout.buildDirectory + .dir("${SUPABASE_FUNCTION_OUTPUT_DIR}/$IMPORT_MAPS_DIRECTORY_NAME") + ) + + packageJsonFile.convention( + layout.buildDirectory.file("tmp/jsPublicPackageJson/package.json").orNone() + ) + functionName.convention(extension.functionName) jsDependencies.convention(jsDependenciesProvider) - dependsOn("jsPublicPackageJson") + if (tasks.names.any { it == JS_PUBLIC_PACKAGE_JSON_TASK }) { + dependsOn(JS_PUBLIC_PACKAGE_JSON_TASK) + } } aggregateTaskProvider.configure { - val aggregateTask = apply { - dependsOn(generateTaskProvider) - } - - generateTaskProvider.configure { - importMapsDir.convention(aggregateTask.importMapsDir) - } + dependsOn(generateTaskProvider) } } \ No newline at end of file diff --git a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/util/Error.kt b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/util/Error.kt new file mode 100644 index 0000000..f08fcba --- /dev/null +++ b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/util/Error.kt @@ -0,0 +1,13 @@ +package io.github.manriif.supabase.functions.util + +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.kotlin.dsl.withType + +internal inline fun Project.postponeErrorOnTaskInvocation(errorMessage: String) { + tasks.withType().configureEach { + doFirst { + error(errorMessage) + } + } +} \ No newline at end of file diff --git a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/util/Files.kt b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/util/Files.kt index 567034f..0fbc2b2 100644 --- a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/util/Files.kt +++ b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/util/Files.kt @@ -22,13 +22,13 @@ package io.github.manriif.supabase.functions.util import org.gradle.api.Project -import org.gradle.api.file.RegularFile +import org.gradle.api.file.FileSystemLocation import org.gradle.api.provider.Provider /** * Returns a [Provider] that will provides the file ony if it exists. */ -internal fun Provider.orNone(): Provider { +internal fun Provider.orNone(): Provider { @Suppress("UnstableApiUsage") return filter { it.asFile.exists() } } @@ -36,6 +36,6 @@ internal fun Provider.orNone(): Provider { /** * Returns a [Provider] that will provides the file ony if it exists. */ -internal fun RegularFile.orNone(project: Project): Provider { +internal fun T.orNone(project: Project): Provider { return project.provider { this }.orNone() } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ce3f37c..a1d1726 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] # Projct version -supabase-functions = "0.0.3" +supabase-functions = "0.0.4" jvm-target = "11" From 0e97740dfcfaf6a8f8d0d1576b60544d1975b5ad Mon Sep 17 00:00:00 2001 From: Maanrifa Bacar Ali Date: Sat, 29 Jun 2024 15:37:35 +0200 Subject: [PATCH 4/4] refactor(gradle-plugin): moved import map output directory `import_map.json` files are now generated under the target project build directory instead of the root project build directory. Only projects registered to the SupabaseFunctionAggregateImportMapTask are now taken into account when merging the final `import_map.json`. --- .../manriif/supabase/functions/Constants.kt | 1 - .../SupabaseFunctionAggregateImportMapTask.kt | 11 ++-- .../task/SupabaseFunctionCopyKotlinTask.kt | 1 - .../manriif/supabase/functions/task/Tasks.kt | 61 ++++++++++--------- 4 files changed, 38 insertions(+), 36 deletions(-) diff --git a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/Constants.kt b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/Constants.kt index 631eab7..4bf1718 100644 --- a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/Constants.kt +++ b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/Constants.kt @@ -31,7 +31,6 @@ internal const val COROUTINES_VERSION_GRADLE_PROPERTY = "supabase.functions.coro internal const val DENO_KOTLIN_BRIDGE_FUNCTION_NAME = "denoKotlinBridge" internal const val KOTLIN_MAIN_FUNCTION_NAME = "serve" -internal const val IMPORT_MAPS_DIRECTORY_NAME = "importMaps" internal const val GITIGNORE_FILE_NAME = ".gitignore" internal const val IMPORT_MAP_TEMPLATE_FILE_NAME = "import_map_template.json" internal const val IMPORT_MAP_FILE_NAME = "import_map.json" diff --git a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/SupabaseFunctionAggregateImportMapTask.kt b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/SupabaseFunctionAggregateImportMapTask.kt index d1f4f19..0bcd696 100644 --- a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/SupabaseFunctionAggregateImportMapTask.kt +++ b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/SupabaseFunctionAggregateImportMapTask.kt @@ -28,12 +28,12 @@ import io.github.manriif.supabase.functions.IMPORT_MAP_TEMPLATE_FILE_NAME import io.github.manriif.supabase.functions.error.SupabaseFunctionImportMapTemplateException import io.github.manriif.supabase.functions.supabase.supabaseAllFunctionsDirFile import org.gradle.api.DefaultTask +import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.RegularFileProperty import org.gradle.api.tasks.CacheableTask -import org.gradle.api.tasks.IgnoreEmptyDirectories -import org.gradle.api.tasks.InputDirectory import org.gradle.api.tasks.InputFile +import org.gradle.api.tasks.InputFiles import org.gradle.api.tasks.Internal import org.gradle.api.tasks.Optional import org.gradle.api.tasks.OutputFile @@ -51,10 +51,9 @@ import java.io.File @CacheableTask abstract class SupabaseFunctionAggregateImportMapTask : DefaultTask() { - @get:InputDirectory - @get:IgnoreEmptyDirectories + @get:InputFiles @get:PathSensitive(PathSensitivity.RELATIVE) - internal abstract val importMapsDir: DirectoryProperty + internal abstract val importMapDirs: ConfigurableFileCollection @get:Internal internal abstract val supabaseDir: DirectoryProperty @@ -100,7 +99,7 @@ abstract class SupabaseFunctionAggregateImportMapTask : DefaultTask() { val imports = importMap.getAsJsonObject(IMPORT_MAP_JSON_IMPORTS) val scopes = importMap.getAsJsonObject(IMPORT_MAP_JSON_SCOPES) - importMapsDir.get().asFileTree + importMapDirs.asFileTree .matching { include { file -> !file.isDirectory && file.name.endsWith(".json") diff --git a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/SupabaseFunctionCopyKotlinTask.kt b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/SupabaseFunctionCopyKotlinTask.kt index e99040a..6d60fed 100644 --- a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/SupabaseFunctionCopyKotlinTask.kt +++ b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/SupabaseFunctionCopyKotlinTask.kt @@ -53,7 +53,6 @@ abstract class SupabaseFunctionCopyKotlinTask : DefaultTask() { internal abstract val supabaseDir: DirectoryProperty @get:InputDirectory - @get:Optional @get:PathSensitive(PathSensitivity.RELATIVE) internal abstract val compiledSourceDir: DirectoryProperty diff --git a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/Tasks.kt b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/Tasks.kt index 7591c83..d2d2fa1 100644 --- a/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/Tasks.kt +++ b/gradle-plugin/src/main/kotlin/io/github/manriif/supabase/functions/task/Tasks.kt @@ -21,7 +21,6 @@ */ package io.github.manriif.supabase.functions.task -import io.github.manriif.supabase.functions.IMPORT_MAPS_DIRECTORY_NAME import io.github.manriif.supabase.functions.IMPORT_MAP_TEMPLATE_FILE_NAME import io.github.manriif.supabase.functions.KOTLIN_MAIN_FUNCTION_NAME import io.github.manriif.supabase.functions.REQUEST_CONFIG_FILE_NAME @@ -99,10 +98,6 @@ private fun Project.registerAggregateImportMapTask(extension: SupabaseFunctionEx supabaseDir.convention(extension.supabaseDir) - importMapsDir.convention( - layout.buildDirectory.dir("${SUPABASE_FUNCTION_OUTPUT_DIR}/$IMPORT_MAPS_DIRECTORY_NAME") - ) - importMapTemplateFile.convention( extension.supabaseDir.file("functions/$IMPORT_MAP_TEMPLATE_FILE_NAME").orNone() ) @@ -163,6 +158,19 @@ private fun Project.registerCopyJsTask( } } +private fun missingJsCompileTaskError(compileTaskName: String): Nothing { + error( + """ + Task `$compileTaskName` was not found during project sync, common reasons for this error are: + + - The `$SUPABASE_FUNCTION_PLUGIN_NAME` plugin was applied on a build script where the kotlin multiplatform plugin was not applied (e.g., root build script) + - The kotlin multiplatform plugin was not applied on this project + - JS target was not initialized on this project + - JS target is missing `binaries.library()` + """.trimIndent() + ) +} + private fun Project.registerCopyKotlinTask( extension: SupabaseFunctionExtension, environment: String, @@ -173,30 +181,27 @@ private fun Project.registerCopyKotlinTask( tasks.register(taskName) { group = SUPABASE_FUNCTION_TASK_GROUP - description = "Copy Kotlin generated sources into supabase function directory." - - compiledSourceDir.convention( - layout.buildDirectory.dir("compileSync/js/main/${environment}Library/kotlin").orNone() - ) + description = "Copy Kotlin generated $environment sources into supabase function directory." supabaseDir.convention(extension.supabaseDir) functionName.convention(extension.functionName) - if (tasks.names.none { it == compileSyncTaskName }) { + val compileTaskFound = tasks.names.any { it == compileSyncTaskName } + + if (compileTaskFound) { + compiledSourceDir.convention( + layout.buildDirectory.dir("compileSync/js/main/${environment}Library/kotlin") + ) + + dependsOn(compileSyncTaskName) + } else { + compiledSourceDir.convention(provider { + missingJsCompileTaskError(compileSyncTaskName) + }) + doFirst { - error( - """ - Task `$compileSyncTaskName` was not found during project sync, common reasons for this error are: - - - The `$SUPABASE_FUNCTION_PLUGIN_NAME` plugin was applied on a build script where the kotlin multiplatform plugin was not applied (e.g., root build script) - - The kotlin multiplatform plugin was not applied on this project - - JS target was not initialized on this project - - JS target is missing `binaries.library()` - """.trimIndent() - ) + missingJsCompileTaskError(compileSyncTaskName) } - } else { - dependsOn(compileSyncTaskName) } dependsOn(TASK_COPY_JS) @@ -267,21 +272,20 @@ private fun Project.registerGenerateImportMapTask( extension: SupabaseFunctionExtension, jsDependenciesProvider: Provider> ) { + val importMapDir = layout.buildDirectory + .dir("generated/${SUPABASE_FUNCTION_OUTPUT_DIR}/importMap") + val generateTaskProvider = tasks.register( name = TASK_GENERATE_IMPORT_MAP ) { group = SUPABASE_FUNCTION_TASK_GROUP description = "Generate import map." - importMapsDir.convention( - rootProject.layout.buildDirectory - .dir("${SUPABASE_FUNCTION_OUTPUT_DIR}/$IMPORT_MAPS_DIRECTORY_NAME") - ) - packageJsonFile.convention( layout.buildDirectory.file("tmp/jsPublicPackageJson/package.json").orNone() ) + importMapsDir.convention(importMapDir) functionName.convention(extension.functionName) jsDependencies.convention(jsDependenciesProvider) @@ -291,6 +295,7 @@ private fun Project.registerGenerateImportMapTask( } aggregateTaskProvider.configure { + importMapDirs.from(importMapDir) dependsOn(generateTaskProvider) } } \ No newline at end of file