diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 41877629563..f2ceb6d3177 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -207,3 +207,5 @@ WORKSPACE @BenHenning .bazelrc @BenHenning /tools/android/ @BenHenning +# License texts. +/app/src/main/res/values/third_party_dependencies.xml @BenHenning diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml index d4e9467b101..b43ba8648b8 100644 --- a/.github/workflows/static_checks.yml +++ b/.github/workflows/static_checks.yml @@ -149,3 +149,8 @@ jobs: if: always() run: | bazel run //scripts:maven_dependencies_list_check -- $(pwd) third_party/maven_install.json scripts/assets/maven_dependencies.pb + + - name: License Texts Check + if: always() + run: | + bazel run //scripts:license_texts_check -- $(pwd)/app/src/main/res/values/third_party_dependencies.xml diff --git a/app/src/main/res/values/third_party_dependencies.xml b/app/src/main/res/values/third_party_dependencies.xml index 6118980d408..b97f957d4f5 100644 --- a/app/src/main/res/values/third_party_dependencies.xml +++ b/app/src/main/res/values/third_party_dependencies.xml @@ -1,4 +1,5 @@ + artifact.name:dependency0 artifact.name:dependency1 diff --git a/scripts/BUILD.bazel b/scripts/BUILD.bazel index 0e3cd8b15c4..244260fc2a6 100644 --- a/scripts/BUILD.bazel +++ b/scripts/BUILD.bazel @@ -134,6 +134,13 @@ kt_jvm_binary( runtime_deps = ["//scripts/src/java/org/oppia/android/scripts/maven:retrieve_license_texts_lib"], ) +kt_jvm_binary( + name = "license_texts_check", + testonly = True, + main_class = "org.oppia.android.scripts.license.LicenseTextsCheckKt", + runtime_deps = ["//scripts/src/java/org/oppia/android/scripts/license:license_texts_check_lib"], +) + ACCESSIBILITY_LABEL_EXEMPTION_ASSETS = generate_accessibility_label_assets_list_from_text_protos( name = "accessibility_label_exemption_assets", accessibility_label_exemptions_name = ["accessibility_label_exemptions"], diff --git a/scripts/src/java/org/oppia/android/scripts/license/BUILD.bazel b/scripts/src/java/org/oppia/android/scripts/license/BUILD.bazel index 0ababbe9a44..8f2fc283c26 100644 --- a/scripts/src/java/org/oppia/android/scripts/license/BUILD.bazel +++ b/scripts/src/java/org/oppia/android/scripts/license/BUILD.bazel @@ -37,3 +37,10 @@ kt_jvm_library( "//scripts/src/java/org/oppia/android/scripts/license:maven_dependencies_retriever", ], ) + +kt_jvm_library( + name = "license_texts_check_lib", + testonly = True, + srcs = ["LicenseTextsCheck.kt"], + visibility = ["//scripts:oppia_script_binary_visibility"], +) diff --git a/scripts/src/java/org/oppia/android/scripts/license/LicenseTextsCheck.kt b/scripts/src/java/org/oppia/android/scripts/license/LicenseTextsCheck.kt new file mode 100644 index 00000000000..ea04eb838c0 --- /dev/null +++ b/scripts/src/java/org/oppia/android/scripts/license/LicenseTextsCheck.kt @@ -0,0 +1,42 @@ +package org.oppia.android.scripts.license + +import java.io.File + +private const val WARNING_COMMENT = + "" + +/** + * Script to verify that the actual license texts are never checked into our VCS. It mainly + * verifies that the script-generated version of third_party_dependencies.xml file is never + * checked in. + * + * Usage: + * bazel run //scripts:maven_dependencies_list_check -- + * + * Arguments: + * - path_to_third_party_deps_xml: path to the third_party_dependencies.xml + * + * Example: + * bazel run //scripts:maven_dependencies_list_check -- $(pwd)/app/src/main/res/values/third_party_dependencies.xml + */ +fun main(args: Array) { + if (args.size < 1) { + throw Exception("Too few arguments passed") + } + val pathToThirdPartyDepsXml = args[0] + val thirdPartyDepsXml = File(pathToThirdPartyDepsXml) + check(thirdPartyDepsXml.exists()) { "File does not exist: $thirdPartyDepsXml" } + + val xmlContent = thirdPartyDepsXml.readText() + + checkIfCommentIsPresent(xmlContent = xmlContent, comment = WARNING_COMMENT) + + println("License texts Check Passed") +} + +private fun checkIfCommentIsPresent(xmlContent: String, comment: String) { + if (comment !in xmlContent) { + println("Please revert the changes in third_party_dependencies.xml") + throw Exception("License texts potentially checked into VCS") + } +} diff --git a/scripts/src/javatests/org/oppia/android/scripts/license/BUILD.bazel b/scripts/src/javatests/org/oppia/android/scripts/license/BUILD.bazel index d074723ed63..707ec3e8081 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/license/BUILD.bazel +++ b/scripts/src/javatests/org/oppia/android/scripts/license/BUILD.bazel @@ -4,6 +4,17 @@ Tests corresponding to the maven dependencies and their license checks. load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_test") +kt_jvm_test( + name = "LicenseTextsCheckTest", + srcs = ["LicenseTextsCheckTest.kt"], + deps = [ + "//scripts/src/java/org/oppia/android/scripts/license:license_texts_check_lib", + "//testing:assertion_helpers", + "//third_party:com_google_truth_truth", + "//third_party:org_jetbrains_kotlin_kotlin-test-junit", + ], +) + kt_jvm_test( name = "MavenDependenciesListCheckTest", size = "large", diff --git a/scripts/src/javatests/org/oppia/android/scripts/license/LicenseTextsCheckTest.kt b/scripts/src/javatests/org/oppia/android/scripts/license/LicenseTextsCheckTest.kt new file mode 100644 index 00000000000..8a70436c6c7 --- /dev/null +++ b/scripts/src/javatests/org/oppia/android/scripts/license/LicenseTextsCheckTest.kt @@ -0,0 +1,121 @@ +package org.oppia.android.scripts.license + +import com.google.common.truth.Truth.assertThat +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TemporaryFolder +import org.oppia.android.testing.assertThrows +import java.io.ByteArrayOutputStream +import java.io.PrintStream + +/** Tests for [LicenseTextsCheck]. */ +class LicenseTextsCheckTest { + private val WARNING_COMMENT = + "" + private val SCRIPT_PASSED_MESSAGE = "License texts Check Passed" + private val LICENSE_TEXTS_CHECKED_IN_FAILURE = "License texts potentially checked into VCS" + private val TOO_FEW_ARGS_PASSED_FAILURE = "Too few arguments passed" + + private val outContent: ByteArrayOutputStream = ByteArrayOutputStream() + private val originalOut: PrintStream = System.out + + @Rule + @JvmField + var tempFolder = TemporaryFolder() + + @Before + fun setUp() { + tempFolder.newFolder("values") + System.setOut(PrintStream(outContent)) + } + + @After + fun restoreStreams() { + System.setOut(originalOut) + } + + @Test + fun testLicenseTexsCheck_noArgsPassed_failWithException() { + val thirdPartyDepsXmlFile = tempFolder.newFile("values/third_party_dependencies.xml") + thirdPartyDepsXmlFile.writeText(WARNING_COMMENT) + + val exception = assertThrows(Exception::class) { + main(arrayOf()) + } + + assertThat(exception).hasMessageThat().contains(TOO_FEW_ARGS_PASSED_FAILURE) + } + + @Test + fun testLicenseTexsCheck_emptyXmlFile_checkFailsWithException() { + val thirdPartyDepsXmlFile = tempFolder.newFile("values/third_party_dependencies.xml") + thirdPartyDepsXmlFile.writeText("") + + val exception = assertThrows(Exception::class) { + main(arrayOf("${tempFolder.root}/values/third_party_dependencies.xml")) + } + + assertThat(exception).hasMessageThat().contains(LICENSE_TEXTS_CHECKED_IN_FAILURE) + } + + @Test + fun testLicenseTexsCheck_warningCommentNotPresent_checkFailsWithException() { + val thirdPartyDepsXmlFile = tempFolder.newFile("values/third_party_dependencies.xml") + thirdPartyDepsXmlFile.writeText( + """ + + + Glide + + """.trimIndent() + ) + + val exception = assertThrows(Exception::class) { + main(arrayOf("${tempFolder.root}/values/third_party_dependencies.xml")) + } + + assertThat(exception).hasMessageThat().contains(LICENSE_TEXTS_CHECKED_IN_FAILURE) + } + + @Test + fun testLicenseTexsCheck_onlyWarningCommentPresent_checkPasses() { + val thirdPartyDepsXmlFile = tempFolder.newFile("values/third_party_dependencies.xml") + thirdPartyDepsXmlFile.writeText(WARNING_COMMENT) + + main(arrayOf("${tempFolder.root}/values/third_party_dependencies.xml")) + + assertThat(outContent.toString()).contains(SCRIPT_PASSED_MESSAGE) + } + + @Test + fun testLicenseTexsCheck_warningCommentPresentWithSomeXmlCode_checkPasses() { + val thirdPartyDepsXmlFile = tempFolder.newFile("values/third_party_dependencies.xml") + thirdPartyDepsXmlFile.writeText( + """ + + $WARNING_COMMENT + + Glide + + """.trimIndent() + ) + + main(arrayOf("${tempFolder.root}/values/third_party_dependencies.xml")) + + assertThat(outContent.toString()).contains(SCRIPT_PASSED_MESSAGE) + } + + @Test + fun testLicenseTexsCheck_xmlFileNotPresent_checkFailsWithFileNotFoundException() { + val pathToThirdPartyDepsXml = "${tempFolder.root}/values/third_party_dependencies.xml" + val exception = assertThrows(Exception::class) { + main(arrayOf("${tempFolder.root}/values/third_party_dependencies.xml")) + } + + assertThat(exception).hasMessageThat().contains( + "File does not exist: $pathToThirdPartyDepsXml" + ) + } +}