dotenv-gradle icon indicating copy to clipboard operation
dotenv-gradle copied to clipboard

Problem with use cases of executing subproject's task with dotenv option by using CLI arguments

Open uzzu opened this issue 1 year ago • 6 comments

Forked from https://github.com/uzzu/dotenv-gradle/issues/39#issuecomment-1827020991

refs: https://github.com/uzzu/dotenv-gradle/issues/39#issuecomment-1466671706

I'm still working on how to make the use cases of executing subproject's task with dotenv option by using CLI arguments, but I think the following tests would be good to pass.

Now failing test case
    @Test
    fun changeFileWithIgnoringParentByUsingCliOptionWithCallSubProject() {
        RootProject(projectDir) {
            settingsGradle(
                """
                include("sub")
                """.trimIndent()
            )
            buildGradle(
                """
                plugins {
                    id("base")
                    id("co.uzzu.dotenv.gradle")
                }
                println("[root] FOO: ${'$'}{env.FOO.value}")
                """.trimIndent()
            )
            file(
                ".env.template",
                """
                FOO=
                """.trimIndent()
            )
            file(
                ".env",
                """
                FOO=100
                """.trimIndent()
            )
            directory("sub")
            file(
                "sub/build.gradle",
                """
                plugins {
                    id("base")
                }
                println("[sub] BAR: ${'$'}{env.BAR.value}")
                """.trimIndent()
            )
            file(
                "sub/.env.template",
                """
                BAR=
                """.trimIndent()
            )
            file(
                "sub/.env",
                """
                BAR=200
                """.trimIndent()
            )
            file(
                "sub/.env.local",
                """
                BAR=2000
                """.trimIndent()
            )
        }

        val result = GradleRunner.create()
            .withPluginClasspath()
            .withProjectDir(projectDir)
            .withArguments(":sub:clean", "-Pdotenv.filename=.env.local")
            .build()

        assertAll {
            assertThat(result.output).contains("[root] FOO: 100")
            assertThat(result.output).contains("[sub] BAR: 2000")
        }
    }

execution log

FAILURE: Build failed with an exception.

* Where:
Build file '/private/var/folders/xxx/build.gradle.kts' line: 1

* What went wrong:
An exception occurred applying plugin request [id: 'co.uzzu.dotenv.gradle']
> Failed to apply plugin 'co.uzzu.dotenv.gradle'.
   > Could not read the dotenv file specified in the gradle.properties. dotenv.filename: .env.local, path: /private/var/folders/xxx/.env.local

workaround: Use gradle.properties

uzzu avatar Nov 27 '23 02:11 uzzu

(memo) Perhaps the plugin can be resolved all command line arguments by using StartParameter

logs

println(target.gradle.startParameter.toString())

StartParameter{taskRequests=[DefaultTaskExecutionRequest{args=[:sub:clean],projectPath='null',rootDir='null'}], excludedTaskNames=[], currentDir=<<omitted>>, projectProperties={dotenv.filename=.env.local}, systemPropertiesArgs={}, gradleUserHomeDir=<<omitted>>/dotenv-gradle/plugin/build/tmp/test/work/.gradle-test-kit, gradleHome=<<omitted>>, logLevel=LIFECYCLE, showStacktrace=INTERNAL_EXCEPTIONS, buildFile=null, initScripts=[], dryRun=false, rerunTasks=false, offline=false, refreshDependencies=false, parallelProjectExecution=false, configureOnDemand=false, maxWorkerCount=8, buildCacheEnabled=false, writeDependencyLocks=false, verificationMode=STRICT, refreshKeys=false}

uzzu avatar Dec 02 '23 14:12 uzzu

I have created a prototype, but it has a lot of problem to resolve this plugins cofigurations.

When executing Gradle from the CLI, it's possible to specify tasks for multiple subprojects, but you can't specify -P options for each task individually. This means that you cannot specify different .env file names for each subproject you execute.

Determining the expected behavior when CLI arguments are provided is extremely challenging. Seriously, in this plugin, deciding not to support CLI arguments (like -Pdotenv.xyz=aaa) is crucial for sustainable maintenance.

I could consider supporting local.properties, but there hasn't been a demand for that so far.

uzzu avatar Dec 09 '23 06:12 uzzu

I think the root cause is the use of Gradle Properties for configuration. However, it's currently unavoidable, as it provides an understandable and minimally necessary functionality for many users. The use of CLI options was unexpected.

Apart from this, until I decide to stop using Gradle Properties for configuring this plugin by facing other issues, CLI options will not be supported.

uzzu avatar Dec 09 '23 07:12 uzzu

I have followed this issue and I am a bit unsure how to realize the following:

I want to develop a library that will be built in different variants. These variants all use different .env files (e.g., different server configurations or default API keys).

It used to be possible to simply set ENV_FILE=.env.variant1 ./gradlew …, with an older version of this plugin.

How else can one set a different env file to use? Editing gradle.properties is not a solution since that file is also committed to the repository; I cannot change it every time I want to build a different variant.

slhck avatar Feb 20 '24 10:02 slhck

I have a workaround that is not very clean, but here it goes.

In my build.gradle for the library, I define some defaults:

def envLookup() {
    def defaults = [
        'API_ENDPOINT': 'http://10.0.2.2:3001/api/v1',
        'API_KEY'     : 'test',
        'VARIANT'     : 'default',
        'SERVICE'     : 'default'
    ]

    def envLookup = [:]
    defaults.each { key, value ->
        envLookup[key] = env.fetch(key, value)
    }

    return envLookup
}

I can use this, e.g., like:

buildConfigField "String", "API_ENDPOINT", "\"${envLookup()['API_ENDPOINT']}\""

For actually building the library, I have a Bash script:

#!/bin/bash

# trap exit by restoring the original gradle.properties from Git
function cleanup {
  echo "Restoring gradle.properties"
  git checkout gradle.properties
}

trap cleanup EXIT

# set the envfile to use for building
envFile=$1

gradleOpts="dotenv.filename=$envFile"

# temporarily write the filename setting into gradle.properties (see: https://github.com/uzzu/dotenv-gradle/issues/39)
echo >> gradle.properties
echo "$gradleOpts" >> gradle.properties

# build
./gradlew clean
./gradlew example:assembleRelease

# any other build steps as necessary

This will overwrite the gradle.properties on the fly and restore it to the default after completion.

slhck avatar Feb 20 '24 10:02 slhck

I'll reopen the issue aside from how to solve it.

uzzu avatar Apr 01 '24 11:04 uzzu