The `@Builder` pattern in DCL cannot chain two fun...
# declarative-gradle
j
The
@Builder
pattern in DCL cannot chain two function calls? I am able to do
Copy code
foo = bar
    .baz(...)
But if I do
Copy code
foo = bar
    .baz(...)
    .quux(...)
it fails with
ValueFactoryCallWithComplexReceiver
p
DCL is not Kotlin. Those "function calls" are only syntax supported for "Value Factories".
j
I know, but it is hard to understand how to use
@Builder
and how it looks like as I am mostly doing "blind" development. So I do not understand if I am using the right tool (
@Builder
) or I just have to go with a different tool.
p
Yeah, the fact that you declare your definitions in code doesn't help, we understand that. It is so tempting to want to use all the facilities that are usually available.
j
basically I am playing with multiple ways to override a version to choose what is nicer. I got
Copy code
mapVersion {
    major = 2
    minor = 3.
    ...
}
And I was trying to see
Copy code
mappedVersion = currentVersion
    .major(2)
    .minor(1)
p
The former looks more declarative
A constrained schema language with clear boundaries would help make it clearer what you can and cannot do. We are exploring that path.
1
j
So probably all of those APIs that looks like imperative will be deprecated, no?
p
Unsure yet
j
I would like to have some kind of conditions, but I don't know how to model this.
Copy code
mapVersion {
     if (tagPrefix == "v" && stage == "dev")
         metadata = kotlinVersion()
}
I can do something like
Copy code
mapVersion {
    metadata = kotlinVersion()

    onlyIf {
        tagPrefix = "v"
        stage == "dev"
    }
}
But that would lead to support only
&&
condition. I can have a list of
&&
conditions and another one for
||
conditions, but that becomes really tedious. It is a real escenario in all my repositories that work with compiler/ksp plugins and they do not have an included build to hide this logic under the hood. So I would like to find a way to model this in DCL.
That is the reason I was using the builder pattern too, because it was looking nicer with conditions:
Copy code
mappedVersion = currentVersion
    .major(2)
    .minor(1)
    .onlyIf {
        tagPrefix("v") or stage("dev")
    }
That supposing
infix
would work.
p
Logic in declarative files is a no go. Logic resides in features. That being said. You could ship different strategies in your features and a declarative way to pick the one to apply (name string, enum, int...). If the build itself need custom logic then it must contribute a feature to carry logic.
These strategies could have declarative parameters.
j
The problem is I do not know how to model this without getting a total mess. Do you have some sample where you migrated some plugin from using something similar to that onlyIf to a dcl with some strategies?
I remember there was a Gradle official plugin that indeed had
onlyIf
, but I do not remember which was tho
publishing one maybe, how would you model that?
p
There are some runtime APIs in gradle that have
onlyIf {}
. There is also the signing plugin that has one. But this is because its interaction with other plugins is porely modeled.
I don't have an example handy, sorry
👍 1
j
Planning something like this:
Copy code
//  Kotlin
semver {
    tagPrefix = "p"

    mapVersions {
        mapVersion { // without qualifier, matches all versions

        }
        mapVersion("kotlin") { // Extend SemverDefinition, matches only versions with "kotlin" qualifier, priority over the previous one if matches
            metadata = gradleProperty("kotlinVersion")
            // or metadata = environmentVariable("KOTLIN_VERSION")
            // or metadata = "1.5.0" // hardcoded value
            // or metadata = property("kotlinVersion") // gradle property > environment variable

            conditions {
                condition(Condition.MetadataIsPresent) // condition enum
                condition(Condition.RequestedTagPrefixMatches())
            }

            snapshotRules {
                rule("kotlin-dev") { // if matches, the version is considered a snapshot
                    contains("kotlin-dev") // multiple ways to create this rule, from simple string match to regex
                    contains("another-string")
                    matches {
                        pattern("(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)-dev-(0|[1-9]\\d*)")
                        pattern("another-regex")
                    }
                }
            }
        }
    }
}