Skip to content
This repository was archived by the owner on Jul 16, 2024. It is now read-only.

Commit

Permalink
Allow authentication with Google Accounts (#37)
Browse files Browse the repository at this point in the history
* add flank auth task

* service account credentials is not required anymore

* update readme

* run a spotlessApply to format code

* credentials file convention must be declared in the extension

* check that at least one of the two authentication methods are provided

* Use InputFiles for credentials

* set the environment variable only when the credentials file exists

* restore code formatting not involving changed code

* serviceAccountCredentials doesn't need to be optional

* add another test case
  • Loading branch information
francescocervone authored May 10, 2023
1 parent 2d3c0ee commit a4c4bdb
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 6 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ plugins {
}
```

add your firebase credentials to the rootproject as `ftl-credentials.json`
add your firebase credentials to the rootproject as `ftl-credentials.json` or authenticate with your Google Account with `./gradlew flankAuth`

That's it, run `./gradlew flankRun` and get the results.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ plugins.withType<AppPlugin> {
}
tasks.register<FlankVersionTask>("flankVersion") { flankJarClasspath.from(flankExecutable) }
registerRunFlankTask()
registerAuthTask()
}

plugins.withType<LibraryPlugin> {
Expand All @@ -73,6 +74,7 @@ plugins.withType<LibraryPlugin> {
}
tasks.register<FlankVersionTask>("flankVersion") { flankJarClasspath.from(flankExecutable) }
registerRunFlankTask()
registerAuthTask()
}

fun registerFlankYamlWriter(
Expand Down Expand Up @@ -127,6 +129,7 @@ fun registerFlankRun(
flankJarClasspath.from(flankExecutable)

serviceAccountCredentials.convention(simpleFlankExtension.credentialsFile)
flankAuthDirectory.set(File(System.getProperty("user.home")).resolve(".flank"))
this@register.variant.convention(variant.name)
hermeticTests.convention(simpleFlankExtension.hermeticTests)
this.appApk.convention(appApk)
Expand Down Expand Up @@ -173,3 +176,7 @@ fun registerRunFlankTask() {
dependsOn(tasks.withType<FlankRunTask>())
}
}

fun registerAuthTask() {
tasks.register<FlankAuthTask>("flankAuth") { flankJarClasspath.from(flankExecutable) }
}
31 changes: 31 additions & 0 deletions src/main/kotlin/io/github/flank/gradle/tasks/FlankAuthTask.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.github.flank.gradle.tasks

import javax.inject.Inject
import org.gradle.api.DefaultTask
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.tasks.Classpath
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.TaskAction
import org.gradle.process.ExecOperations

abstract class FlankAuthTask @Inject constructor(private val execOperations: ExecOperations) :
DefaultTask() {
@get:InputFiles @get:Classpath abstract val flankJarClasspath: ConfigurableFileCollection

init {
group = "flank"
description =
"Performs the authentication with a Google Account. https://flank.github.io/flank/#authenticate-with-a-google-account"
}

@TaskAction
fun run() {
execOperations
.javaexec {
classpath = flankJarClasspath
mainClass.set("ftl.Main")
args = listOf("auth", "login")
}
.assertNormalExitValue()
}
}
28 changes: 23 additions & 5 deletions src/main/kotlin/io/github/flank/gradle/tasks/FlankRunTask.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,14 @@ constructor(
@get:Input
val dry: Property<Boolean> = objectFactory.property(Boolean::class.java).convention(false)

@get:InputFile
@get:InputFiles
@get:PathSensitive(PathSensitivity.NONE)
abstract val serviceAccountCredentials: RegularFileProperty

@get:InputFiles
@get:PathSensitive(PathSensitivity.ABSOLUTE)
abstract val flankAuthDirectory: DirectoryProperty

@get:Input abstract val variant: Property<String>

@get:InputFiles @get:Classpath abstract val flankJarClasspath: ConfigurableFileCollection
Expand Down Expand Up @@ -62,17 +66,17 @@ constructor(

@TaskAction
fun run() {
check(serviceAccountCredentials.get().asFile.exists()) {
"serviceAccountCredential file doesn't exist ${serviceAccountCredentials.get()}"
}
checkAuthentication()

getOutputDir().get().asFile.deleteRecursively()
execOperations
.javaexec {
isIgnoreExitValue = true
classpath = flankJarClasspath
mainClass.set("ftl.Main")
environment(mapOf("GOOGLE_APPLICATION_CREDENTIALS" to serviceAccountCredentials.get()))
serviceAccountCredentials.get().takeIf { it.asFile.exists() }?.let { credentialsFile ->
environment(mapOf("GOOGLE_APPLICATION_CREDENTIALS" to credentialsFile))
}
args = listOf("firebase", "test", "android", "run", "-c=${flankYaml.get()}")
if (dumpShards.get()) args("--dump-shards")
if (dry.get()) args("--dry")
Expand All @@ -98,6 +102,20 @@ constructor(
}
}

private fun checkAuthentication() {
val isCredentialsFileProvided = serviceAccountCredentials.get().asFile.exists()
val isFlankAuthenticationProvided = flankAuthDirectory.get().asFile.exists()
check(isCredentialsFileProvided || isFlankAuthenticationProvided) {
"""
Either a service account credential file should be provided or the flank authentication performed.
You can:
- Declare the service account credentials in the ftl-credentials.json file on your rootProject
- Declare the service account credentials in a custom path via the simple flank's extension simpleFlank { credentialsFile = "path/to/file.json" }
- Perform the authentication with a Google Account via "./gradlew flankAuth"
""".trimIndent()
}
}

companion object {
const val NO_TESTS_EXIT_CODE = 3
}
Expand Down
86 changes: 86 additions & 0 deletions src/test/kotlin/CredentialsTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import java.io.File
import org.gradle.testkit.runner.TaskOutcome
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import strikt.api.expectThat
import strikt.assertions.contains
import strikt.gradle.testkit.output
import strikt.gradle.testkit.taskPaths

class CredentialsTest : GradleTest() {
@get:Rule val userHomeDirectory = TemporaryFolder()

@Test
fun `When no service account or flank credentials are provided, build fails`() {
projectFromResources("app")
File(testProjectDir.root, "ftl-credentials.json").deleteRecursively()
File(testProjectDir.root, "build.gradle.kts")
.appendText("simpleFlank { projectId.set(\"my-project\") }")

val build = gradleRunner("flankRun", "--stacktrace").forwardOutput().buildAndFail()

expectThat(build) {
output.contains(
"Either a service account credential file should be provided or the flank authentication performed.")
}
expectThat(build) { taskPaths(TaskOutcome.FAILED).contains(":flankRunDebug") }
}

@Test
fun `When service account is provided using the default file, build is successful`() {
projectFromResources("app")

val build = gradleRunner("flankRun", "--stacktrace").forwardOutput().build()

expectThat(build) {
output
.not()
.contains(
"Either a service account credential file should be provided or the flank authentication performed.")
taskPaths(TaskOutcome.SUCCESS).contains(":flankRunDebug")
}
}

@Test
fun `When service account is provided using the a custom file, build is successful`() {
projectFromResources("app")

val build = gradleRunner("flankRun", "--stacktrace").forwardOutput().build()
File(testProjectDir.root, "ftl-credentials.json").deleteRecursively()
File(testProjectDir.root, "custom-credentials.json")
.appendText("{ \"project_id\": \"custom-project-id\" }")
File(testProjectDir.root, "build.gradle.kts")
.appendText("simpleFlank { credentialsFile.set(file(\"custom-credentials.json\")) }")

expectThat(build) {
output
.not()
.contains(
"Either a service account credential file should be provided or the flank authentication performed.")
taskPaths(TaskOutcome.SUCCESS).contains(":flankRunDebug")
}
}

@Test
fun `When flank Google Account authentication is provided, build is successful`() {
projectFromResources("app")
File(testProjectDir.root, "ftl-credentials.json").deleteRecursively()
File(testProjectDir.root, "build.gradle.kts")
.appendText("simpleFlank { projectId.set(\"my-project\") }")
userHomeDirectory.root.resolve(".flank").mkdir()

val build =
gradleRunner("flankRun", "-Duser.home=${userHomeDirectory.root.path}", "--stacktrace")
.forwardOutput()
.build()

expectThat(build) {
output
.not()
.contains(
"Either a service account credential file should be provided or the flank authentication performed.")
taskPaths(TaskOutcome.SUCCESS).contains(":flankRunDebug")
}
}
}

0 comments on commit a4c4bdb

Please sign in to comment.