[Build, IGS] Add a consent details document link
Related to KTI-1223
This commit is contained in:
committed by
Space Team
parent
063e7258ee
commit
04fcffa664
+19
-2
@@ -11,8 +11,12 @@ import java.io.PrintStream
|
|||||||
private val isInIdeaSync
|
private val isInIdeaSync
|
||||||
get() = System.getProperty("idea.sync.active").toBoolean()
|
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 = "# 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 =
|
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."
|
"# 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()
|
""".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 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(
|
internal class ConsentManager(
|
||||||
private val modifier: LocalPropertiesModifier,
|
private val modifier: LocalPropertiesModifier,
|
||||||
private val input: BufferedReader = System.`in`.bufferedReader(),
|
private val input: BufferedReader = System.`in`.bufferedReader(),
|
||||||
@@ -38,14 +46,23 @@ internal class ConsentManager(
|
|||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun askForConsent(): Boolean {
|
fun askForConsent(consentDetailsLink: String? = null): Boolean {
|
||||||
output.println(USER_CONSENT_REQUEST)
|
output.println(USER_CONSENT_REQUEST)
|
||||||
|
if (consentDetailsLink != null) {
|
||||||
|
output.println(USER_CONSENT_DETAILS_LINK_TEMPLATE.formatWithLink(consentDetailsLink))
|
||||||
|
}
|
||||||
while (true) {
|
while (true) {
|
||||||
output.println(PROMPT_REQUEST)
|
output.println(PROMPT_REQUEST)
|
||||||
when (input.readLine()) {
|
when (input.readLine()) {
|
||||||
"yes" -> {
|
"yes" -> {
|
||||||
output.println("You've given the consent")
|
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
|
return true
|
||||||
}
|
}
|
||||||
"no" -> {
|
"no" -> {
|
||||||
|
|||||||
+2
-2
@@ -23,7 +23,7 @@ abstract class InternalGradleSetupSettingsPlugin : Plugin<Settings> {
|
|||||||
private val log = Logging.getLogger(javaClass)
|
private val log = Logging.getLogger(javaClass)
|
||||||
|
|
||||||
override fun apply(target: Settings) {
|
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)
|
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
|
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
|
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 {
|
val setupFile = connection.getInputStream().buffered().use {
|
||||||
parseSetupFile(it)
|
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")
|
log.debug("Skipping automatic local.properties configuration as the consent wasn't given")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,11 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.build
|
package org.jetbrains.kotlin.build
|
||||||
|
|
||||||
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
import kotlinx.serialization.json.JsonNamingStrategy
|
||||||
import java.io.BufferedReader
|
import java.io.BufferedReader
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.InputStreamReader
|
import java.io.InputStreamReader
|
||||||
@@ -16,9 +18,14 @@ import kotlin.streams.asSequence
|
|||||||
@Serializable
|
@Serializable
|
||||||
internal data class SetupFile(
|
internal data class SetupFile(
|
||||||
val properties: Map<String, String>,
|
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
|
// can't use decodeFromStream: https://github.com/Kotlin/kotlinx.serialization/issues/2218
|
||||||
internal fun parseSetupFile(inputStream: InputStream): SetupFile =
|
internal fun parseSetupFile(inputStream: InputStream): SetupFile =
|
||||||
|
|||||||
+20
-2
@@ -52,24 +52,42 @@ class ConsentManagerTest {
|
|||||||
@Test
|
@Test
|
||||||
fun testConsentRequestAgree() = testUserDecision("yes", true, USER_CONSENT_MARKER)
|
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
|
@Test
|
||||||
fun testConsentRequestRefusal() = testUserDecision("no", false, USER_REFUSAL_MARKER)
|
fun testConsentRequestRefusal() = testUserDecision("no", false, USER_REFUSAL_MARKER)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testConsentRequestAnswerAfterBadInput() = testUserDecision("\nasdasd\nno", false, USER_REFUSAL_MARKER, 3)
|
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 ->
|
StringInputStream(prompt).bufferedReader().use { input ->
|
||||||
val outputStream = ByteArrayOutputStream(255)
|
val outputStream = ByteArrayOutputStream(255)
|
||||||
PrintStream(outputStream).use { printStream ->
|
PrintStream(outputStream).use { printStream ->
|
||||||
val consentManager = ConsentManager(modifier, input, printStream)
|
val consentManager = ConsentManager(modifier, input, printStream)
|
||||||
val userDecision = consentManager.askForConsent()
|
val userDecision = consentManager.askForConsent(consentDetailsLink)
|
||||||
assertEquals(expectedDecision, userDecision)
|
assertEquals(expectedDecision, userDecision)
|
||||||
val content = Files.readAllLines(localPropertiesFile)
|
val content = Files.readAllLines(localPropertiesFile)
|
||||||
assertTrue(content.contains(expectedLine))
|
assertTrue(content.contains(expectedLine))
|
||||||
val output = String(outputStream.toByteArray())
|
val output = String(outputStream.toByteArray())
|
||||||
assertContainsExactTimes(output, USER_CONSENT_REQUEST, 1)
|
assertContainsExactTimes(output, USER_CONSENT_REQUEST, 1)
|
||||||
assertContainsExactTimes(output, PROMPT_REQUEST, promptCount)
|
assertContainsExactTimes(output, PROMPT_REQUEST, promptCount)
|
||||||
|
|
||||||
|
if (consentDetailsLink != null) {
|
||||||
|
assertContainsExactTimes(output, USER_CONSENT_DETAILS_LINK_TEMPLATE.formatWithLink(consentDetailsLink), 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
@@ -29,6 +29,7 @@ class SetupFileParseTest {
|
|||||||
parseSetupFile(it)
|
parseSetupFile(it)
|
||||||
}
|
}
|
||||||
assertSampleSetupFileIsParsedCorrectly(setupFile)
|
assertSampleSetupFileIsParsedCorrectly(setupFile)
|
||||||
|
assertNull(setupFile.consentDetailsLink)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -37,5 +38,15 @@ class SetupFileParseTest {
|
|||||||
parseSetupFile(it)
|
parseSetupFile(it)
|
||||||
}
|
}
|
||||||
assertSampleSetupFileIsParsedCorrectly(setupFile)
|
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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"properties": {
|
||||||
|
"newProperty1": "someValue",
|
||||||
|
"newProperty2": "someOtherValue",
|
||||||
|
"alreadySetProperty": "newValue"
|
||||||
|
},
|
||||||
|
"consent_details_link": "https://example.org"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user