[Build, IGS] Add a consent details document link

Related to KTI-1223
This commit is contained in:
Alexander.Likhachev
2023-05-31 14:40:06 +02:00
committed by Space Team
parent 063e7258ee
commit 04fcffa664
6 changed files with 68 additions and 7 deletions
@@ -11,8 +11,12 @@ import java.io.PrintStream
private val isInIdeaSync
get() = System.getProperty("idea.sync.active").toBoolean()
private const val linkPlaceholder = "%LINK%"
internal const val USER_CONSENT_MARKER = "# This line indicates that you have chosen to enable automatic configuration of properties."
internal const val USER_CONSENT_MARKER_WITH_DETAILS_LINK = "$USER_CONSENT_MARKER Details: $linkPlaceholder"
internal const val USER_REFUSAL_MARKER =
"# This line indicates that you have chosen to disable automatic configuration of properties. If you want to enable it, remove this line."
@@ -24,8 +28,12 @@ internal val USER_CONSENT_REQUEST = """
""".trimIndent()
internal val USER_CONSENT_DETAILS_LINK_TEMPLATE = "You can read more details here: $linkPlaceholder"
internal const val PROMPT_REQUEST = "Do you agree with this? Please answer with 'yes' or 'no': "
internal fun String.formatWithLink(link: String) = replace(linkPlaceholder, link)
internal class ConsentManager(
private val modifier: LocalPropertiesModifier,
private val input: BufferedReader = System.`in`.bufferedReader(),
@@ -38,14 +46,23 @@ internal class ConsentManager(
else -> null
}
fun askForConsent(): Boolean {
fun askForConsent(consentDetailsLink: String? = null): Boolean {
output.println(USER_CONSENT_REQUEST)
if (consentDetailsLink != null) {
output.println(USER_CONSENT_DETAILS_LINK_TEMPLATE.formatWithLink(consentDetailsLink))
}
while (true) {
output.println(PROMPT_REQUEST)
when (input.readLine()) {
"yes" -> {
output.println("You've given the consent")
modifier.putLine(USER_CONSENT_MARKER)
modifier.putLine(
if (consentDetailsLink != null) {
USER_CONSENT_MARKER_WITH_DETAILS_LINK.formatWithLink(consentDetailsLink)
} else {
USER_CONSENT_MARKER
}
)
return true
}
"no" -> {
@@ -23,7 +23,7 @@ abstract class InternalGradleSetupSettingsPlugin : Plugin<Settings> {
private val log = Logging.getLogger(javaClass)
override fun apply(target: Settings) {
// `kotlin-build-gradle-plugin` is not used here intentionally, as it caches properties, we don't want to cache them before modificaation
// `kotlin-build-gradle-plugin` is not used here intentionally, as it caches properties, we don't want to cache them before modification
val shouldApplyPlugin = target.providers.gradleProperty(PLUGIN_SWITCH_PROPERTY).orElse("false").map(String::toBoolean)
if (!shouldApplyPlugin.get()) return // the plugin is disabled, do nothing at all
val isTeamCityBuild = (target as? ExtensionAware)?.extra?.has("teamcity") == true || System.getenv("TEAMCITY_VERSION") != null
@@ -43,7 +43,7 @@ abstract class InternalGradleSetupSettingsPlugin : Plugin<Settings> {
val setupFile = connection.getInputStream().buffered().use {
parseSetupFile(it)
}
if (initialDecision == null && !consentManager.askForConsent()) {
if (initialDecision == null && !consentManager.askForConsent(setupFile.consentDetailsLink)) {
log.debug("Skipping automatic local.properties configuration as the consent wasn't given")
return
}
@@ -5,9 +5,11 @@
package org.jetbrains.kotlin.build
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonNamingStrategy
import java.io.BufferedReader
import java.io.InputStream
import java.io.InputStreamReader
@@ -16,9 +18,14 @@ import kotlin.streams.asSequence
@Serializable
internal data class SetupFile(
val properties: Map<String, String>,
val consentDetailsLink: String? = null,
)
private val json = Json { ignoreUnknownKeys = true }
@OptIn(ExperimentalSerializationApi::class)
private val json = Json {
ignoreUnknownKeys = true
namingStrategy = JsonNamingStrategy.SnakeCase
}
// can't use decodeFromStream: https://github.com/Kotlin/kotlinx.serialization/issues/2218
internal fun parseSetupFile(inputStream: InputStream): SetupFile =
@@ -52,24 +52,42 @@ class ConsentManagerTest {
@Test
fun testConsentRequestAgree() = testUserDecision("yes", true, USER_CONSENT_MARKER)
@Test
fun testConsentRequestAgreeWithDetailsLink() = testUserDecision(
"yes",
true,
USER_CONSENT_MARKER_WITH_DETAILS_LINK.formatWithLink("https://example.org"),
consentDetailsLink = "https://example.org"
)
@Test
fun testConsentRequestRefusal() = testUserDecision("no", false, USER_REFUSAL_MARKER)
@Test
fun testConsentRequestAnswerAfterBadInput() = testUserDecision("\nasdasd\nno", false, USER_REFUSAL_MARKER, 3)
private fun testUserDecision(prompt: String, expectedDecision: Boolean, expectedLine: String, promptCount: Int = 1) {
private fun testUserDecision(
prompt: String,
expectedDecision: Boolean,
expectedLine: String,
promptCount: Int = 1,
consentDetailsLink: String? = null,
) {
StringInputStream(prompt).bufferedReader().use { input ->
val outputStream = ByteArrayOutputStream(255)
PrintStream(outputStream).use { printStream ->
val consentManager = ConsentManager(modifier, input, printStream)
val userDecision = consentManager.askForConsent()
val userDecision = consentManager.askForConsent(consentDetailsLink)
assertEquals(expectedDecision, userDecision)
val content = Files.readAllLines(localPropertiesFile)
assertTrue(content.contains(expectedLine))
val output = String(outputStream.toByteArray())
assertContainsExactTimes(output, USER_CONSENT_REQUEST, 1)
assertContainsExactTimes(output, PROMPT_REQUEST, promptCount)
if (consentDetailsLink != null) {
assertContainsExactTimes(output, USER_CONSENT_DETAILS_LINK_TEMPLATE.formatWithLink(consentDetailsLink), 1)
}
}
}
}
@@ -29,6 +29,7 @@ class SetupFileParseTest {
parseSetupFile(it)
}
assertSampleSetupFileIsParsedCorrectly(setupFile)
assertNull(setupFile.consentDetailsLink)
}
@Test
@@ -37,5 +38,15 @@ class SetupFileParseTest {
parseSetupFile(it)
}
assertSampleSetupFileIsParsedCorrectly(setupFile)
assertNull(setupFile.consentDetailsLink)
}
@Test
fun testParsingWithConsentDetailsLink() {
val setupFile = openPropertiesJsonStream("properties-with-consent-details").use {
parseSetupFile(it)
}
assertSampleSetupFileIsParsedCorrectly(setupFile)
assertEquals(setupFile.consentDetailsLink, "https://example.org")
}
}
@@ -0,0 +1,8 @@
{
"properties": {
"newProperty1": "someValue",
"newProperty2": "someOtherValue",
"alreadySetProperty": "newValue"
},
"consent_details_link": "https://example.org"
}