Extracting that part of the conversation from the ...
# apollo-kotlin
s
Extracting that part of the conversation from the last discussion, about the task of altering the generated graphqls file from a custom task 🧵
I got something like this going now:
Copy code
tasks.withType<com.apollographql.apollo.gradle.internal.ApolloDownloadSchemaTask>().configureEach {
    setFinalizedBy(listOf("updateSchema"))
}

tasks.register("updateSchema") {
    val downloadedSchema = file("src/main/graphql/com/hedvig/android/owldroid/schema.graphqls")
    val patchedSchema = file("src/main/graphql/com/hedvig/android/owldroid/schema.graphqls")
    inputs.file(downloadedSchema)
    outputs.file(patchedSchema)

    doLast {
        patchedSchema.writeText(
            downloadedSchema.readText().replace(
                oldValue = "\"\"\"${System.lineSeparator()}  \"\"\"",
                newValue = "\"\"\"",
                ignoreCase = false
            )
        )
    }
}
Which I’d have hoped it works but doesn’t seem to.
Optimally, I would like to not make every other dev start using a different task and having that one dependOn(“downloadGiraffeSchemaFromIntrospection”). I’d like them to just call
downloadGiraffeSchemaFromIntrospection
directly and have it work for hem, hence trying to go with the approach above. But I am not sure gradle likes that approach, googling online a bunch of people tell how one should always use the dependsOn instead, to depend on stuff done before and not after what you’re doing. If you have any idea how I’d fix my code snippet above it’d be awesome!
b
Hey there was somebody who needed to do something similar here and I think doing this worked:
Copy code
tasks.withType(com.apollographql.apollo3.gradle.internal.ApolloDownloadSchemaTask::class.java) {
    doLast {
        // your custom code
    }
}
(at least “your custom code” was called when I tried it 😅 )
s
Right, but then if I put all the code from my task in there it doesn’t work since I am assuming the:
Copy code
inputs.file(downloadedSchema)
outputs.file(patchedSchema)
can’t exist in there like this. And I can’t figure out if it’s possible to instead inside the doLast{} lambda to actually call a whole task. Current code that doesn’t work for reference:
Copy code
tasks.withType(com.apollographql.apollo.gradle.internal.ApolloDownloadSchemaTask::class.java) {
    doLast {
        val downloadedSchema = file("src/main/graphql/com/hedvig/android/owldroid/schema.graphqls")
        val patchedSchema = file("src/main/graphql/com/hedvig/android/owldroid/schema.graphqls")
        inputs.file(downloadedSchema)
        outputs.file(patchedSchema)
        patchedSchema.writeText(
            downloadedSchema.readText().replace(
                oldValue = "\"\"\"${System.lineSeparator()}  \"\"\"",
                newValue = "\"\"\"",
                ignoreCase = false
            )
        )
    }
}
b
when you say it doesn’t work you mean nothing happens, or an error?
s
Interestingly enough, on a project where I am using apollo 3, which also changes the import to apollo3 (see I write just apollo on the above post, I am using 2 there) this does seem to run properly as erroring about adding “inputs” to the task after the task has already started execution. On apollo 2 it doesn’t error, it just doesn’t do anything, nor do the print statements work, so it makes me think it just never goes inside the lambda 🤔
b
woops I assumed you were on v3. Haven’t tried on v2. But wondering if you really need the inputs/outputs?
s
This works perfectly fine in apollo3:
Copy code
tasks.withType(com.apollographql.apollo3.gradle.internal.ApolloDownloadSchemaTask::class.java) {
    doLast {
        val downloadedSchema = file("src/commonMain/graphql/com/hedvig/embarkx/schema.graphqls")
        val patchedSchema = file("src/commonMain/graphql/com/hedvig/embarkx/schema.graphqls")
        patchedSchema.writeText(
            downloadedSchema.readText()
                .replace(
                    oldValue = "\"\"\"${System.lineSeparator()}  \\\"\"\"",
                    newValue = "\"\"\"",
                    ignoreCase = false
                )
                .replace(
                    oldValue = "\\\"\"\"${System.lineSeparator()}  \"\"\"",
                    newValue = "\"\"\"",
                    ignoreCase = false
                )
        )
    }
}
(Notice a change in the replace methods, as in apollo 2 the comment gets generated as pic1 and in apollo 3 it gets generated as pic2 😄
b
how weird 😅
s
While this just never enters the lambda for apollo 2
Copy code
tasks.withType(com.apollographql.apollo.gradle.internal.ApolloDownloadSchemaTask::class.java) {
    doLast {
        val downloadedSchema = file("src/main/graphql/com/hedvig/android/owldroid/schema.graphqls")
        val patchedSchema = file("src/main/graphql/com/hedvig/android/owldroid/schema.graphqls")
        patchedSchema.writeText(
            downloadedSchema.readText().replace(
                oldValue = "\"\"\"${System.lineSeparator()}  \"\"\"",
                newValue = "\"\"\"",
                ignoreCase = false
            )
        )
    }
}
Nothing inside there runs ever. It feels like either I am using the wrong import somehow, or we’re changing the task somehow somewhere else? Not sure how that’d be possible, but it is indeed very weird
Both versions should use the exact same
ApolloDownloadSchemaTask
function right? The only other difference that I can see if that in the v2.0 version I am calling just
./gradlew downloadApolloSchema
since we’re not using the
service("name")
block in our apollo configuration While in the 3.0 version I am calling
./gradlew :shared:downloadGiraffeApolloSchemaFromIntrospection
since we are using the service name there. I can’t see any other reason just a simple tasks.withType<>() on the DownloadTask would just not work. Maybe this isn’t worth looking into anyway, since we’re eveeentually gonna go to 3.0 anyway, but it’s interesting nonetheless
b
to be honest I don’t have a lot of experience with v2 (well less than v3 in any case) 😅
🙏 1
s
Yeah don’t worry about it, thanks for helping and hearing my rant though 😅 If I eventually spend more time on making this work for v2 for whatever reason I’ll make sure to update here. Otherwise I think we’ll just have to wait until we move to v3 instead.
b
👍 happy to help (or at least try to! 😛)
m
The only other difference that I can see if that in the v2.0 version I am calling just 
./gradlew downloadApolloSchema
This is the difference. 2.x has 2 classes: •
ApolloDownloadSchemaTask
: to download from introspection •
ApolloDownloadSchemaCliTask
: to download from the command line
💡 1
3.x has only one task
Overall, the approach from @bod should work:
Copy code
# or ApolloDownloadSchemaCliTask if you're on 2.x and calling downloadApolloSchema
tasks.withType(com.apollographql.apollo3.gradle.internal.ApolloDownloadSchemaTask::class.java) {
    doLast {
        // your custom code
    }
}
The only drawback is that it uses internal APIs.
Doing things with separate tasks is a more granular option and doesn't use any internal API:
Copy code
tasks.register("updateSchema") {
    dependsOn("downloadGiraffeApolloSchemaFromIntrospection")
    inputs.file(downloadedSchema)
    outputs.file(patchedSchema)

    doLast {
        patchedSchema.writeText(downloadedSchema.readText().replace("\\\"\"\"", ""))
    }
}
(then you'll have to call
updateSchema
instead of
downloadGiraffeApolloSchemaFromIntrospection
If we wanted, we could go all in on the lazy property and expose a Gradle
FileProperty
that carries task dependencies
f
Copy code
patchedSchema.writeText(downloadedSchema.readText().replace("\\\"\"\"", ""))
I like this snippet for different reasons, I've noticed I get lots of extra
\n
when I download schema for the first time with apollo v3. Haven't looked into it, but I'll assume I can revert to v2 behavior somehow? Something like
replace ("\n\n", "\n" )
or easier ? Otherwise I'm going to get a lot of flak from my team when I land my v3 upgrade.
m
Are you talking about things like this?
Copy code
type LaunchConnection {
  cursor: String!

  hasMore: Boolean!

  launches: [Launch]!
}
instead of
Copy code
type LaunchConnection {
  cursor: String!
  hasMore: Boolean!
  launches: [Launch]!
}
In that case, yes,
replace ("\n\n", "\n" )
will make everything more packed
Ultimately, we certainly need a formatter like ktlint or so but for GraphQL
💡 2
@Stylianos Gakis the escaped triple quotes were valid actually (even if looking a bit weird). I just pushed a fix at https://github.com/apollographql/apollo-kotlin/pull/3895/files
s
Wow didn’t even know this could be fixed 😅 Making our lives easier one commit at a time, thanks! 🎉
❤️ 2
Hey I just happened to read some gradle docs which suggest using the new lazy APIs, specifically in the section “Migrating from the existing Gradle Tasks API to the new API” they suggest adding after the
withType
a
configureEach
block to turn it into a lazy configuration. For the sake of myself and whoever happens to see this thread in the future, wouldn’t that mean that one should probably adjust the snippet provided here to add the configureEach block? Maybe the
doLast
running every time isn’t a big deal, but at the same time this probably doesn’t need to run every time if you’re doing something unrelated right?
b
adjust the snippet provided here to add the configureEach block?
I think, yes 👍
s
Been doing some Gradle reading lately, looking at your change to convention plugins and all that kind of jazz and I’m realizing how much there is I don’t know about Gradle 😂 So thought I’d ask this question here to at least see if I understood that part right, and it seems like yeah, so that’s good 😅
b
how much there is I don’t know about Gradle
Same here 😅 Gradle is huge! Probably because it's been around for a while.