From 13efcfa4e4b40972ab2d951790cb2eea71b44e6d Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 10 Apr 2024 23:51:08 +0530 Subject: [PATCH 01/17] Script to Check the Table of Contents in the Wiki and CI workflow --- .github/workflows/wiki.yml | 18 ++++ scripts/BUILD.bazel | 7 ++ .../oppia/android/scripts/wiki/BUILD.bazel | 18 ++++ .../scripts/wiki/WikiTableOfContentsCheck.kt | 93 +++++++++++++++++++ 4 files changed, 136 insertions(+) create mode 100644 scripts/src/java/org/oppia/android/scripts/wiki/BUILD.bazel create mode 100644 scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt diff --git a/.github/workflows/wiki.yml b/.github/workflows/wiki.yml index f37031f61e9..66ab33d7ca3 100644 --- a/.github/workflows/wiki.yml +++ b/.github/workflows/wiki.yml @@ -10,6 +10,24 @@ on: gollum: jobs: + table_of_contents_check: + name: Wiki Check Table of Contents match Headers + runs-on: ubuntu-20.04 + env: + CACHE_DIRECTORY: ~/.bazel_cache + steps: + - uses: actions/checkout@v2 + + - name: Set up Bazel + uses: abhinavsingh/setup-bazel@v3 + with: + version: 4.0.0 + + - name: Wiki Check Table of Contents + id: wikichecktoc + run: | + bazel run //scripts:wiki_table_of_contents_check -- ${GITHUB_WORKSPACE} + wiki-deploy: runs-on: ${{ matrix.os }} strategy: diff --git a/scripts/BUILD.bazel b/scripts/BUILD.bazel index 01390e600e7..b404a09ef61 100644 --- a/scripts/BUILD.bazel +++ b/scripts/BUILD.bazel @@ -227,6 +227,13 @@ kt_jvm_binary( ], ) +kt_jvm_binary( + name = "wiki_table_of_contents_check", + testonly = True, + main_class = "org.oppia.android.scripts.wiki.WikiTableOfContentsCheckKt", + runtime_deps = ["//scripts/src/java/org/oppia/android/scripts/wiki:wiki_table_of_contents_check_lib"], +) + # Note that this is intentionally not test-only since it's used by the app build pipeline. Also, # this apparently needs to be a java_binary to set up runfiles correctly when executed within a # Starlark rule as a tool. diff --git a/scripts/src/java/org/oppia/android/scripts/wiki/BUILD.bazel b/scripts/src/java/org/oppia/android/scripts/wiki/BUILD.bazel new file mode 100644 index 00000000000..6898d1b8c21 --- /dev/null +++ b/scripts/src/java/org/oppia/android/scripts/wiki/BUILD.bazel @@ -0,0 +1,18 @@ +""" +Libraries corresponding to scripting tools that help with continuous integration workflows. +""" + +load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library") + +kt_jvm_library( + name = "wiki_table_of_contents_check_lib", + testonly = True, + srcs = [ + "WikiTableOfContentsCheck.kt", + ], + visibility = ["//scripts:oppia_script_binary_visibility"], + deps = [ + "//scripts/src/java/org/oppia/android/scripts/common:bazel_client", + "//scripts/src/java/org/oppia/android/scripts/common:git_client", + ], +) diff --git a/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt b/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt new file mode 100644 index 00000000000..eeadf710480 --- /dev/null +++ b/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt @@ -0,0 +1,93 @@ +package org.oppia.android.scripts.wiki + +import java.io.File + +/** + * Script for ensuring that the table of contents in each wiki page matches with its respective headers. + * + * Usage: + * bazel run //scripts:wiki_sample -- + * + * Arguments: + * - path_to_default_working_directory: The default working directory on the runner for steps, and the default location of repository. + * + * Example: + * bazel run //scripts:wiki_sample -- ${GITHUB_WORKSPACE} + */ +fun main(vararg args: String) { + // Path to the repo's wiki. + val githubWorkspace = "${args[0]}/wiki/" + val wikiDirectory = File(githubWorkspace) + + // Check if the wiki directory exists + if (wikiDirectory.exists() && wikiDirectory.isDirectory) { + processWikiDirectory(wikiDirectory) + } else { + println("No contents found in the Wiki directory.") + } +} + +/** + * Checks every file in the wiki repo + * + * @param wikiDirectory the default working directory + */ +fun processWikiDirectory(wikiDirectory: File) { + wikiDirectory.listFiles()?.forEach { file -> + processWikiFile(file) + } +} + +/** + * Processes the contents of a single wiki file to ensure the accuracy of the Table of Contents. + * + * @param file The wiki file to process. + */ +fun processWikiFile(file: File) { + var inTableOfContents = false + var skipBlankLine = false + + file.forEachLine { line -> + when { + // Checking for Table of Contents section + line.trim() == "## Table of Contents" -> { + inTableOfContents = true + skipBlankLine = true + } + // Checking to skip the blank line immediately after the ## Table of Contents + skipBlankLine && line.isBlank() -> skipBlankLine = false + // Validating the contents in the Table of Content + inTableOfContents && line.trimStart().startsWith("- [") && !line.contains("https://") -> { + validateTableOfContents(file, line) + } + // Checking for end of Table of Contents section + inTableOfContents && line.isBlank() -> inTableOfContents = false + } + } +} + +/** + * Validates the accuracy of a Table of Contents entry in a wiki file. + * + * @param file The wiki file being validated. + * @param line The line containing the Table of Contents entry. + */ +fun validateTableOfContents(file: File, line: String) { + val titleRegex = "\\[(.*?)\\]".toRegex() + val title = titleRegex.find(line)?.groupValues?.get(1)?.replace('-', ' ') + ?.replace(Regex("[?&./:’'*!,(){}\\[\\]+]"), "") + ?.trim() + + val linkRegex = "\\(#(.*?)\\)".toRegex() + val link = linkRegex.find(line)?.groupValues?.get(1)?.removePrefix("#")?.replace('-', ' ') + ?.replace(Regex("[?&./:’'*!,(){}\\[\\]+]"), "") + ?.replace("confetti_ball", "")?.trim() + + // Checks if the table of content title matches with the header link text + val matches = title.equals(link, ignoreCase = true) + if (!matches) { + throw Exception("\nMismatch of Table of Content with headers in the File: ${file.name}. " + + "\nThe Title: '${titleRegex.find(line)?.groupValues?.get(1)}' " + + "doesn't match with its corresponding Link: '${linkRegex.find(line)?.groupValues?.get(1)}'.") + } +} From d3795b3c1828fc5abaa27dc1b9ef5fd2c09a5f50 Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 11 Apr 2024 00:54:12 +0530 Subject: [PATCH 02/17] Fix Lint Tests by adding new lines after and before ( and ) --- .../oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt b/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt index eeadf710480..f556ec0da05 100644 --- a/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt +++ b/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt @@ -86,8 +86,10 @@ fun validateTableOfContents(file: File, line: String) { // Checks if the table of content title matches with the header link text val matches = title.equals(link, ignoreCase = true) if (!matches) { - throw Exception("\nMismatch of Table of Content with headers in the File: ${file.name}. " + + throw Exception( + "\nMismatch of Table of Content with headers in the File: ${file.name}. " + "\nThe Title: '${titleRegex.find(line)?.groupValues?.get(1)}' " + - "doesn't match with its corresponding Link: '${linkRegex.find(line)?.groupValues?.get(1)}'.") + "doesn't match with its corresponding Link: '${linkRegex.find(line)?.groupValues?.get(1)}'." + ) } } From 1840f6092efa4ec21b371e0083d32b88c41a3633 Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 11 Apr 2024 00:59:51 +0530 Subject: [PATCH 03/17] Fix Lint Tests by properly indenting the error messages --- .../oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt b/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt index f556ec0da05..fd2412fb082 100644 --- a/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt +++ b/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt @@ -88,8 +88,8 @@ fun validateTableOfContents(file: File, line: String) { if (!matches) { throw Exception( "\nMismatch of Table of Content with headers in the File: ${file.name}. " + - "\nThe Title: '${titleRegex.find(line)?.groupValues?.get(1)}' " + - "doesn't match with its corresponding Link: '${linkRegex.find(line)?.groupValues?.get(1)}'." + "\nThe Title: '${titleRegex.find(line)?.groupValues?.get(1)}' " + + "doesn't match with its corresponding Link: '${linkRegex.find(line)?.groupValues?.get(1)}'." ) } } From d113747e709ac4755adaedaba40f8d574a8ba356 Mon Sep 17 00:00:00 2001 From: Rd Date: Tue, 30 Apr 2024 00:57:53 +0530 Subject: [PATCH 04/17] Modified id with camel case convention and Revised the name to be more concise --- .github/workflows/wiki.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/wiki.yml b/.github/workflows/wiki.yml index 66ab33d7ca3..b3028fc7807 100644 --- a/.github/workflows/wiki.yml +++ b/.github/workflows/wiki.yml @@ -11,7 +11,8 @@ on: jobs: table_of_contents_check: - name: Wiki Check Table of Contents match Headers + # To verify that the wiki's table of contents matches the headers accurately. + name: Check Wiki Table of Contents runs-on: ubuntu-20.04 env: CACHE_DIRECTORY: ~/.bazel_cache @@ -23,8 +24,8 @@ jobs: with: version: 4.0.0 - - name: Wiki Check Table of Contents - id: wikichecktoc + - name: Check Wiki Table of Contents + id: checkWikiToc run: | bazel run //scripts:wiki_table_of_contents_check -- ${GITHUB_WORKSPACE} From 49917c7b73014e276c43389256ab1975f5e4925a Mon Sep 17 00:00:00 2001 From: Rd Date: Fri, 5 Jul 2024 08:05:25 +0530 Subject: [PATCH 05/17] Renaming wiki dir variables for better clarity --- .../scripts/wiki/WikiTableOfContentsCheck.kt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt b/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt index 9a22731c376..920cfd58ad9 100644 --- a/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt +++ b/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt @@ -16,12 +16,12 @@ import java.io.File */ fun main(vararg args: String) { // Path to the repo's wiki. - val githubWorkspace = "${args[0]}/wiki/" - val wikiDirectory = File(githubWorkspace) + val wikiDirPath = "${args[0]}/wiki/" + val wikiDir = File(wikiDirPath) // Check if the wiki directory exists. - if (wikiDirectory.exists() && wikiDirectory.isDirectory) { - processWikiDirectory(wikiDirectory) + if (wikiDir.exists() && wikiDir.isDirectory) { + processWikiDirectory(wikiDir) } else { println("No contents found in the Wiki directory.") } @@ -30,10 +30,10 @@ fun main(vararg args: String) { /** * Checks every file in the wiki repo. * - * @param wikiDirectory the default working directory + * @param wikiDir the default working directory */ -fun processWikiDirectory(wikiDirectory: File) { - wikiDirectory.listFiles()?.forEach { file -> +fun processWikiDirectory(wikiDir: File) { + wikiDir.listFiles()?.forEach { file -> processWikiFile(file) } } From 94fa4f6e0bb5186941741d55da45e515d74c8090 Mon Sep 17 00:00:00 2001 From: Rd Date: Fri, 5 Jul 2024 11:48:11 +0530 Subject: [PATCH 06/17] Simplified the wiki table of content check logic with kotlin functions --- .../scripts/wiki/WikiTableOfContentsCheck.kt | 50 ++++++++++++++--- .../oppia/android/scripts/wiki/BUILD.bazel | 16 ++++++ .../wiki/WikiTableOfContentsCheckTest.kt | 55 +++++++++++++++++++ 3 files changed, 113 insertions(+), 8 deletions(-) create mode 100644 scripts/src/javatests/org/oppia/android/scripts/wiki/BUILD.bazel create mode 100644 scripts/src/javatests/org/oppia/android/scripts/wiki/WikiTableOfContentsCheckTest.kt diff --git a/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt b/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt index 920cfd58ad9..4d17544524e 100644 --- a/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt +++ b/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt @@ -22,6 +22,7 @@ fun main(vararg args: String) { // Check if the wiki directory exists. if (wikiDir.exists() && wikiDir.isDirectory) { processWikiDirectory(wikiDir) + println("WIKI TABLE OF CONTENTS CHECK PASSED") } else { println("No contents found in the Wiki directory.") } @@ -34,20 +35,53 @@ fun main(vararg args: String) { */ fun processWikiDirectory(wikiDir: File) { wikiDir.listFiles()?.forEach { file -> - processWikiFile(file) + checkTableOfContents(file) } } /** - * Processes the contents of a single wiki file to ensure the accuracy of the Table of Contents. + * Checks the contents of a single wiki file to ensure the accuracy of the Table of Contents. * * @param file the wiki file to process. */ -fun processWikiFile(file: File) { - var inTableOfContents = false - var skipBlankLine = false +fun checkTableOfContents(file: File) { +// var inTableOfContents = false +// var skipBlankLine = false - file.forEachLine { line -> + println("File: $file") + val fileContents = file.readLines() + val tocStartIdx = fileContents.indexOfFirst { + it.contains("## Table of Contents") + } + + println("start: $tocStartIdx") + if (tocStartIdx == -1) { + println("No Table of Contents found for the file $file") + return + } + + /*val blankLineIdx = fileContents.subList(tocStartIdx, fileContents.size).indexOfFirst { + it.isBlank() + } + println("blank: $blankLineIdx")*/ + + // Skipping the blank line after the ## Table of Contents + val eOfIdx = fileContents.subList(tocStartIdx + 2, fileContents.size).indexOfFirst { + it.isBlank() + } + println("end: $eOfIdx") + if (eOfIdx == -1) throw Exception("Table of Contents didn't end with a blank line") + + val tocSpecificLines = fileContents.subList(tocStartIdx, tocStartIdx + eOfIdx + 1) + println("Toc line: $tocSpecificLines") + + for (line in tocSpecificLines) { + if (line.trimStart().startsWith("- [") && !line.contains("https://")) { + validateTableOfContents(file, line) + } + } + +/* file.forEachLine { line -> when { // Checking for Table of Contents section. line.trim() == "## Table of Contents" -> { @@ -63,7 +97,7 @@ fun processWikiFile(file: File) { // Checking for end of Table of Contents section. inTableOfContents && line.isBlank() -> inTableOfContents = false } - } + }*/ } /** @@ -86,7 +120,7 @@ fun validateTableOfContents(file: File, line: String) { // Checks if the table of content title matches with the header link text. val matches = title.equals(link, ignoreCase = true) if (!matches) { - throw Exception( + throw Exception("\nWIKI TABLE OF CONTENTS CHECK FAILED" + "\nMismatch of Table of Content with headers in the File: ${file.name}. " + "\nThe Title: '${titleRegex.find(line)?.groupValues?.get(1)}' " + "doesn't match with its corresponding Link: '${linkRegex.find(line)?.groupValues?.get(1)}'." diff --git a/scripts/src/javatests/org/oppia/android/scripts/wiki/BUILD.bazel b/scripts/src/javatests/org/oppia/android/scripts/wiki/BUILD.bazel new file mode 100644 index 00000000000..953b3f7d8d9 --- /dev/null +++ b/scripts/src/javatests/org/oppia/android/scripts/wiki/BUILD.bazel @@ -0,0 +1,16 @@ +""" +Tests corresponding to wiki-related checks. +""" + +load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_test") + +kt_jvm_test( + name = "WikiTableOfContentsCheckTest", + srcs = ["WikiTableOfContentsCheckTest.kt"], + deps = [ + "//scripts/src/java/org/oppia/android/scripts/wiki:wiki_table_of_contents_check_lib", + "//testing:assertion_helpers", + "//third_party:com_google_truth_truth", + "//third_party:org_jetbrains_kotlin_kotlin-test-junit", + ], +) diff --git a/scripts/src/javatests/org/oppia/android/scripts/wiki/WikiTableOfContentsCheckTest.kt b/scripts/src/javatests/org/oppia/android/scripts/wiki/WikiTableOfContentsCheckTest.kt new file mode 100644 index 00000000000..9a7a2eedc95 --- /dev/null +++ b/scripts/src/javatests/org/oppia/android/scripts/wiki/WikiTableOfContentsCheckTest.kt @@ -0,0 +1,55 @@ +package org.oppia.android.scripts.wiki + +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 [WikiTableOfContentsCheck]. */ +class WikiTableOfContentsCheckTest { + private val outContent: ByteArrayOutputStream = ByteArrayOutputStream() + private val originalOut: PrintStream = System.out + + @field:[Rule JvmField] val tempFolder = TemporaryFolder() + + @Before + fun setUp() { + System.setOut(PrintStream(outContent)) + } + + @After + fun tearDown() { + System.setOut(originalOut) + } + + @Test + fun testValidToCWithMatchingHeaders() { + tempFolder.newFolder("wiki") + val file = tempFolder.newFile("wiki/ValidToCWithMatchingHeaders.md") + file.writeText(""" + ## Table of Contents + + - [Introduction](#introduction) + - [Usage](#usage) + + ## Introduction + Content + + ## Usage + Content + """.trimIndent()) + + runScript() + + assertThat(outContent.toString().trim()).contains("WIKI TABLE OF CONTENTS CHECK PASSED") + } + + private fun runScript() { + main(tempFolder.root.absolutePath) + } +} \ No newline at end of file From 3e74a99b48a3c038773d0e4fb7c9863453a4e4d3 Mon Sep 17 00:00:00 2001 From: Rd Date: Fri, 5 Jul 2024 11:52:52 +0530 Subject: [PATCH 07/17] Code clean up and replaced exception with error statement --- .../scripts/wiki/WikiTableOfContentsCheck.kt | 34 ++----------------- 1 file changed, 2 insertions(+), 32 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt b/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt index 4d17544524e..d6188e09755 100644 --- a/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt +++ b/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt @@ -45,32 +45,20 @@ fun processWikiDirectory(wikiDir: File) { * @param file the wiki file to process. */ fun checkTableOfContents(file: File) { -// var inTableOfContents = false -// var skipBlankLine = false - - println("File: $file") val fileContents = file.readLines() val tocStartIdx = fileContents.indexOfFirst { it.contains("## Table of Contents") } - - println("start: $tocStartIdx") if (tocStartIdx == -1) { println("No Table of Contents found for the file $file") return } - /*val blankLineIdx = fileContents.subList(tocStartIdx, fileContents.size).indexOfFirst { - it.isBlank() - } - println("blank: $blankLineIdx")*/ - // Skipping the blank line after the ## Table of Contents val eOfIdx = fileContents.subList(tocStartIdx + 2, fileContents.size).indexOfFirst { it.isBlank() } - println("end: $eOfIdx") - if (eOfIdx == -1) throw Exception("Table of Contents didn't end with a blank line") + if (eOfIdx == -1) error("Table of Contents didn't end with a blank line") val tocSpecificLines = fileContents.subList(tocStartIdx, tocStartIdx + eOfIdx + 1) println("Toc line: $tocSpecificLines") @@ -80,24 +68,6 @@ fun checkTableOfContents(file: File) { validateTableOfContents(file, line) } } - -/* file.forEachLine { line -> - when { - // Checking for Table of Contents section. - line.trim() == "## Table of Contents" -> { - inTableOfContents = true - skipBlankLine = true - } - // Checking to skip the blank line immediately after the ## Table of Contents. - skipBlankLine && line.isBlank() -> skipBlankLine = false - // Validating the contents in the Table of Content. - inTableOfContents && line.trimStart().startsWith("- [") && !line.contains("https://") -> { - validateTableOfContents(file, line) - } - // Checking for end of Table of Contents section. - inTableOfContents && line.isBlank() -> inTableOfContents = false - } - }*/ } /** @@ -120,7 +90,7 @@ fun validateTableOfContents(file: File, line: String) { // Checks if the table of content title matches with the header link text. val matches = title.equals(link, ignoreCase = true) if (!matches) { - throw Exception("\nWIKI TABLE OF CONTENTS CHECK FAILED" + + error("\nWIKI TABLE OF CONTENTS CHECK FAILED" + "\nMismatch of Table of Content with headers in the File: ${file.name}. " + "\nThe Title: '${titleRegex.find(line)?.groupValues?.get(1)}' " + "doesn't match with its corresponding Link: '${linkRegex.find(line)?.groupValues?.get(1)}'." From 5a8b4b9a5839afa0a81e482833e90853e7138641 Mon Sep 17 00:00:00 2001 From: Rd Date: Fri, 5 Jul 2024 12:26:57 +0530 Subject: [PATCH 08/17] Added test cases for wiki toc checks --- .../wiki/WikiTableOfContentsCheckTest.kt | 94 ++++++++++++++++++- 1 file changed, 90 insertions(+), 4 deletions(-) diff --git a/scripts/src/javatests/org/oppia/android/scripts/wiki/WikiTableOfContentsCheckTest.kt b/scripts/src/javatests/org/oppia/android/scripts/wiki/WikiTableOfContentsCheckTest.kt index 9a7a2eedc95..735aa8679cf 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/wiki/WikiTableOfContentsCheckTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/wiki/WikiTableOfContentsCheckTest.kt @@ -14,11 +14,14 @@ import java.io.PrintStream class WikiTableOfContentsCheckTest { private val outContent: ByteArrayOutputStream = ByteArrayOutputStream() private val originalOut: PrintStream = System.out + private val WIKI_TOC_CHECK_PASSED_OUTPUT_INDICATOR = "WIKI TABLE OF CONTENTS CHECK PASSED" + private val WIKI_TOC_CHECK_FAILED_OUTPUT_INDICATOR = "WIKI TABLE OF CONTENTS CHECK FAILED" @field:[Rule JvmField] val tempFolder = TemporaryFolder() @Before fun setUp() { + tempFolder.newFolder("wiki") System.setOut(PrintStream(outContent)) } @@ -28,9 +31,8 @@ class WikiTableOfContentsCheckTest { } @Test - fun testValidToCWithMatchingHeaders() { - tempFolder.newFolder("wiki") - val file = tempFolder.newFile("wiki/ValidToCWithMatchingHeaders.md") + fun testWikiTOCCheck_validWikiTOC_checkPass() { + val file = tempFolder.newFile("wiki/wiki.md") file.writeText(""" ## Table of Contents @@ -46,7 +48,91 @@ class WikiTableOfContentsCheckTest { runScript() - assertThat(outContent.toString().trim()).contains("WIKI TABLE OF CONTENTS CHECK PASSED") + assertThat(outContent.toString().trim()).contains(WIKI_TOC_CHECK_PASSED_OUTPUT_INDICATOR) + } + + @Test + fun testWikiTOCCheck_missingWikiTOC_returnsNoTOCFound() { + val file = tempFolder.newFile("wiki/wiki.md") + file.writeText(""" + - [Introduction](#introduction) + - [Usage](#usage) + + ## Introduction + Content + + ## Usage + Content + """.trimIndent()) + + runScript() + + assertThat(outContent.toString().trim()).contains("No Table of Contents found") + } + + @Test + fun testWikiTOCCheck_mismatchWikiTOC_checkFail() { + val file = tempFolder.newFile("wiki/wiki.md") + file.writeText(""" + ## Table of Contents + + - [Introduction](#introductions) + - [Usage](#usage) + + ## Introduction + Content + + ## Usage + Content + """.trimIndent()) + + val exception = assertThrows() { + runScript() + } + + assertThat(exception).hasMessageThat().contains(WIKI_TOC_CHECK_FAILED_OUTPUT_INDICATOR) + } + + @Test + fun testWikiTOCCheck_validWikiTOCWithSeparator_checkPass() { + val file = tempFolder.newFile("wiki/wiki.md") + file.writeText(""" + ## Table of Contents + + - [Introduction To Wiki](#introduction-to-wiki) + - [Usage Wiki-Content](#usage-wiki-content) + + ## Introduction + Content + + ## Usage + Content + """.trimIndent()) + + runScript() + + assertThat(outContent.toString().trim()).contains(WIKI_TOC_CHECK_PASSED_OUTPUT_INDICATOR) + } + + @Test + fun testWikiTOCCheck_validWikiTOCWithSpecialCharacter_checkPass() { + val file = tempFolder.newFile("wiki/wiki.md") + file.writeText(""" + ## Table of Contents + + - [Introduction](#introduction?) + - [Usage?](#usage) + + ## Introduction + Content + + ## Usage + Content + """.trimIndent()) + + runScript() + + assertThat(outContent.toString().trim()).contains(WIKI_TOC_CHECK_PASSED_OUTPUT_INDICATOR) } private fun runScript() { From 9e4386ae1837d31720a1ae3ea288d08188dbed38 Mon Sep 17 00:00:00 2001 From: Rd Date: Fri, 5 Jul 2024 13:00:12 +0530 Subject: [PATCH 09/17] Fix Lint Checks for indentation and missing spaces --- .../scripts/wiki/WikiTableOfContentsCheck.kt | 5 +-- .../wiki/WikiTableOfContentsCheckTest.kt | 32 ++++++++++++------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt b/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt index d6188e09755..18cb650f1f8 100644 --- a/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt +++ b/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt @@ -90,8 +90,9 @@ fun validateTableOfContents(file: File, line: String) { // Checks if the table of content title matches with the header link text. val matches = title.equals(link, ignoreCase = true) if (!matches) { - error("\nWIKI TABLE OF CONTENTS CHECK FAILED" + - "\nMismatch of Table of Content with headers in the File: ${file.name}. " + + error( + "\nWIKI TABLE OF CONTENTS CHECK FAILED" + + "\nMismatch of Table of Content with headers in the File: ${file.name}. " + "\nThe Title: '${titleRegex.find(line)?.groupValues?.get(1)}' " + "doesn't match with its corresponding Link: '${linkRegex.find(line)?.groupValues?.get(1)}'." ) diff --git a/scripts/src/javatests/org/oppia/android/scripts/wiki/WikiTableOfContentsCheckTest.kt b/scripts/src/javatests/org/oppia/android/scripts/wiki/WikiTableOfContentsCheckTest.kt index 735aa8679cf..fab1892b7eb 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/wiki/WikiTableOfContentsCheckTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/wiki/WikiTableOfContentsCheckTest.kt @@ -33,7 +33,8 @@ class WikiTableOfContentsCheckTest { @Test fun testWikiTOCCheck_validWikiTOC_checkPass() { val file = tempFolder.newFile("wiki/wiki.md") - file.writeText(""" + file.writeText( + """ ## Table of Contents - [Introduction](#introduction) @@ -44,7 +45,8 @@ class WikiTableOfContentsCheckTest { ## Usage Content - """.trimIndent()) + """.trimIndent() + ) runScript() @@ -54,7 +56,8 @@ class WikiTableOfContentsCheckTest { @Test fun testWikiTOCCheck_missingWikiTOC_returnsNoTOCFound() { val file = tempFolder.newFile("wiki/wiki.md") - file.writeText(""" + file.writeText( + """ - [Introduction](#introduction) - [Usage](#usage) @@ -63,7 +66,8 @@ class WikiTableOfContentsCheckTest { ## Usage Content - """.trimIndent()) + """.trimIndent() + ) runScript() @@ -73,7 +77,8 @@ class WikiTableOfContentsCheckTest { @Test fun testWikiTOCCheck_mismatchWikiTOC_checkFail() { val file = tempFolder.newFile("wiki/wiki.md") - file.writeText(""" + file.writeText( + """ ## Table of Contents - [Introduction](#introductions) @@ -84,7 +89,8 @@ class WikiTableOfContentsCheckTest { ## Usage Content - """.trimIndent()) + """.trimIndent() + ) val exception = assertThrows() { runScript() @@ -96,7 +102,8 @@ class WikiTableOfContentsCheckTest { @Test fun testWikiTOCCheck_validWikiTOCWithSeparator_checkPass() { val file = tempFolder.newFile("wiki/wiki.md") - file.writeText(""" + file.writeText( + """ ## Table of Contents - [Introduction To Wiki](#introduction-to-wiki) @@ -107,7 +114,8 @@ class WikiTableOfContentsCheckTest { ## Usage Content - """.trimIndent()) + """.trimIndent() + ) runScript() @@ -117,7 +125,8 @@ class WikiTableOfContentsCheckTest { @Test fun testWikiTOCCheck_validWikiTOCWithSpecialCharacter_checkPass() { val file = tempFolder.newFile("wiki/wiki.md") - file.writeText(""" + file.writeText( + """ ## Table of Contents - [Introduction](#introduction?) @@ -128,7 +137,8 @@ class WikiTableOfContentsCheckTest { ## Usage Content - """.trimIndent()) + """.trimIndent() + ) runScript() @@ -138,4 +148,4 @@ class WikiTableOfContentsCheckTest { private fun runScript() { main(tempFolder.root.absolutePath) } -} \ No newline at end of file +} From 9193d15254670a842e4d7da1747f372f8bc3e9cf Mon Sep 17 00:00:00 2001 From: Rd Date: Fri, 5 Jul 2024 13:08:53 +0530 Subject: [PATCH 10/17] Fix Lint check buildifier reformat --- scripts/BUILD.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/BUILD.bazel b/scripts/BUILD.bazel index 9b95059e3f1..1d564d127ba 100644 --- a/scripts/BUILD.bazel +++ b/scripts/BUILD.bazel @@ -242,7 +242,7 @@ kt_jvm_binary( testonly = True, main_class = "org.oppia.android.scripts.wiki.WikiTableOfContentsCheckKt", runtime_deps = [ - "//scripts/src/java/org/oppia/android/scripts/wiki:wiki_table_of_contents_check_lib" + "//scripts/src/java/org/oppia/android/scripts/wiki:wiki_table_of_contents_check_lib", ], ) From 72d0a2b5b9f88dc09a0d8b4e513ae963bf43413a Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 5 Sep 2024 15:06:41 +0530 Subject: [PATCH 11/17] Added missing test cases for no directory found to hit 100% coverage --- .../wiki/WikiTableOfContentsCheckTest.kt | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/scripts/src/javatests/org/oppia/android/scripts/wiki/WikiTableOfContentsCheckTest.kt b/scripts/src/javatests/org/oppia/android/scripts/wiki/WikiTableOfContentsCheckTest.kt index fab1892b7eb..97a34b91f36 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/wiki/WikiTableOfContentsCheckTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/wiki/WikiTableOfContentsCheckTest.kt @@ -21,7 +21,6 @@ class WikiTableOfContentsCheckTest { @Before fun setUp() { - tempFolder.newFolder("wiki") System.setOut(PrintStream(outContent)) } @@ -30,8 +29,22 @@ class WikiTableOfContentsCheckTest { System.setOut(originalOut) } + @Test + fun testWikiTOCCheck_noWikiDirExists_printsNoContentFound() { + runScript() + assertThat(outContent.toString().trim()).isEqualTo("No contents found in the Wiki directory.") + } + + @Test + fun testWikiTOCCheck_noWikiDirectory_printsNoContentFound() { + tempFolder.newFile("wiki") + runScript() + assertThat(outContent.toString().trim()).isEqualTo("No contents found in the Wiki directory.") + } + @Test fun testWikiTOCCheck_validWikiTOC_checkPass() { + tempFolder.newFolder("wiki") val file = tempFolder.newFile("wiki/wiki.md") file.writeText( """ @@ -55,6 +68,7 @@ class WikiTableOfContentsCheckTest { @Test fun testWikiTOCCheck_missingWikiTOC_returnsNoTOCFound() { + tempFolder.newFolder("wiki") val file = tempFolder.newFile("wiki/wiki.md") file.writeText( """ @@ -76,6 +90,7 @@ class WikiTableOfContentsCheckTest { @Test fun testWikiTOCCheck_mismatchWikiTOC_checkFail() { + tempFolder.newFolder("wiki") val file = tempFolder.newFile("wiki/wiki.md") file.writeText( """ @@ -101,6 +116,7 @@ class WikiTableOfContentsCheckTest { @Test fun testWikiTOCCheck_validWikiTOCWithSeparator_checkPass() { + tempFolder.newFolder("wiki") val file = tempFolder.newFile("wiki/wiki.md") file.writeText( """ @@ -124,6 +140,7 @@ class WikiTableOfContentsCheckTest { @Test fun testWikiTOCCheck_validWikiTOCWithSpecialCharacter_checkPass() { + tempFolder.newFolder("wiki") val file = tempFolder.newFile("wiki/wiki.md") file.writeText( """ From b5c9cf3b8d1f2e87c468c6e9a09ebde6d021f701 Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 2 Oct 2024 17:32:20 +0530 Subject: [PATCH 12/17] Upgraded the Bazel version, removed cache env, used Regex to check heading text --- .github/workflows/wiki.yml | 4 +--- .../oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/wiki.yml b/.github/workflows/wiki.yml index 5f7f34a13d1..4568a6469db 100644 --- a/.github/workflows/wiki.yml +++ b/.github/workflows/wiki.yml @@ -14,15 +14,13 @@ jobs: # To verify that the wiki's table of contents matches the headers accurately. name: Check Wiki Table of Contents runs-on: ubuntu-20.04 - env: - CACHE_DIRECTORY: ~/.bazel_cache steps: - uses: actions/checkout@v2 - name: Set up Bazel uses: abhinavsingh/setup-bazel@v3 with: - version: 4.0.0 + version: 6.5.0 - name: Check Wiki Table of Contents id: checkWikiToc diff --git a/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt b/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt index 18cb650f1f8..489ff4e41cc 100644 --- a/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt +++ b/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt @@ -47,7 +47,7 @@ fun processWikiDirectory(wikiDir: File) { fun checkTableOfContents(file: File) { val fileContents = file.readLines() val tocStartIdx = fileContents.indexOfFirst { - it.contains("## Table of Contents") + it.contains(Regex("""##\s+Table\s+of\s+Contents""", RegexOption.IGNORE_CASE)) } if (tocStartIdx == -1) { println("No Table of Contents found for the file $file") @@ -58,7 +58,7 @@ fun checkTableOfContents(file: File) { val eOfIdx = fileContents.subList(tocStartIdx + 2, fileContents.size).indexOfFirst { it.isBlank() } - if (eOfIdx == -1) error("Table of Contents didn't end with a blank line") + if (eOfIdx == -1) error("Table of Contents didn't end with a blank line.") val tocSpecificLines = fileContents.subList(tocStartIdx, tocStartIdx + eOfIdx + 1) println("Toc line: $tocSpecificLines") From afaf59e92db26b26262560c20e30cdac0131e1da Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 3 Oct 2024 18:14:16 +0530 Subject: [PATCH 13/17] Added pull-request trigger to check on every PR creation, removed debug lines and removed the confetti emoji filtering --- .github/workflows/wiki.yml | 1 + .../oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/wiki.yml b/.github/workflows/wiki.yml index 4568a6469db..1badfd225b3 100644 --- a/.github/workflows/wiki.yml +++ b/.github/workflows/wiki.yml @@ -1,5 +1,6 @@ name: Deploy to Wiki on: + pull_request: push: branches: - develop diff --git a/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt b/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt index 489ff4e41cc..c634792e7a9 100644 --- a/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt +++ b/scripts/src/java/org/oppia/android/scripts/wiki/WikiTableOfContentsCheck.kt @@ -50,7 +50,6 @@ fun checkTableOfContents(file: File) { it.contains(Regex("""##\s+Table\s+of\s+Contents""", RegexOption.IGNORE_CASE)) } if (tocStartIdx == -1) { - println("No Table of Contents found for the file $file") return } @@ -61,7 +60,6 @@ fun checkTableOfContents(file: File) { if (eOfIdx == -1) error("Table of Contents didn't end with a blank line.") val tocSpecificLines = fileContents.subList(tocStartIdx, tocStartIdx + eOfIdx + 1) - println("Toc line: $tocSpecificLines") for (line in tocSpecificLines) { if (line.trimStart().startsWith("- [") && !line.contains("https://")) { @@ -85,7 +83,7 @@ fun validateTableOfContents(file: File, line: String) { val linkRegex = "\\(#(.*?)\\)".toRegex() val link = linkRegex.find(line)?.groupValues?.get(1)?.removePrefix("#")?.replace('-', ' ') ?.replace(Regex("[?&./:’'*!,(){}\\[\\]+]"), "") - ?.replace("confetti_ball", "")?.trim() + ?.trim() // Checks if the table of content title matches with the header link text. val matches = title.equals(link, ignoreCase = true) From be0015172720e07ae04acafef4d58ab5cfbb9c6b Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 3 Oct 2024 18:32:04 +0530 Subject: [PATCH 14/17] Trigger only when changes are made to the wiki dir --- .github/workflows/wiki.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/wiki.yml b/.github/workflows/wiki.yml index 1badfd225b3..40a80ffa5b8 100644 --- a/.github/workflows/wiki.yml +++ b/.github/workflows/wiki.yml @@ -1,6 +1,8 @@ name: Deploy to Wiki on: pull_request: + paths: + - 'wiki/**' push: branches: - develop From c18ac91813523cb3b7db5146176e39b6f490c1e1 Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 3 Oct 2024 18:39:54 +0530 Subject: [PATCH 15/17] Conditional execution of the wiki-deploy to only proceed if the event is push to the develop branch --- .github/workflows/wiki.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/wiki.yml b/.github/workflows/wiki.yml index 40a80ffa5b8..1875e6154be 100644 --- a/.github/workflows/wiki.yml +++ b/.github/workflows/wiki.yml @@ -35,6 +35,7 @@ jobs: strategy: matrix: os: [ubuntu-20.04] + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' }} steps: - uses: actions/checkout@v3 with: From 2dfd045fa9193ea6bc45310fcfc29885e6fb19d1 Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 3 Oct 2024 19:00:30 +0530 Subject: [PATCH 16/17] Removed the test case for checking TOC present as the log statement to display the TOC not found is removed now The log statement is removed as it is unnecessary and clutters the check stack trace and also it isn't mandatory to have a TOC on every page so the check is not needed. --- .../wiki/WikiTableOfContentsCheckTest.kt | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/scripts/src/javatests/org/oppia/android/scripts/wiki/WikiTableOfContentsCheckTest.kt b/scripts/src/javatests/org/oppia/android/scripts/wiki/WikiTableOfContentsCheckTest.kt index 97a34b91f36..f5c66abf2cd 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/wiki/WikiTableOfContentsCheckTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/wiki/WikiTableOfContentsCheckTest.kt @@ -66,28 +66,6 @@ class WikiTableOfContentsCheckTest { assertThat(outContent.toString().trim()).contains(WIKI_TOC_CHECK_PASSED_OUTPUT_INDICATOR) } - @Test - fun testWikiTOCCheck_missingWikiTOC_returnsNoTOCFound() { - tempFolder.newFolder("wiki") - val file = tempFolder.newFile("wiki/wiki.md") - file.writeText( - """ - - [Introduction](#introduction) - - [Usage](#usage) - - ## Introduction - Content - - ## Usage - Content - """.trimIndent() - ) - - runScript() - - assertThat(outContent.toString().trim()).contains("No Table of Contents found") - } - @Test fun testWikiTOCCheck_mismatchWikiTOC_checkFail() { tempFolder.newFolder("wiki") From c7d0d1136d8eeeb43516eee90930c18bb316c68b Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 3 Oct 2024 19:38:16 +0530 Subject: [PATCH 17/17] Re-adding the test case to hit coverage but now checking with final result as the toc not found statement is removed --- .../wiki/WikiTableOfContentsCheckTest.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/scripts/src/javatests/org/oppia/android/scripts/wiki/WikiTableOfContentsCheckTest.kt b/scripts/src/javatests/org/oppia/android/scripts/wiki/WikiTableOfContentsCheckTest.kt index f5c66abf2cd..8b91a453107 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/wiki/WikiTableOfContentsCheckTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/wiki/WikiTableOfContentsCheckTest.kt @@ -66,6 +66,28 @@ class WikiTableOfContentsCheckTest { assertThat(outContent.toString().trim()).contains(WIKI_TOC_CHECK_PASSED_OUTPUT_INDICATOR) } + @Test + fun testWikiTOCCheck_missingWikiTOC_returnsNoTOCFound() { + tempFolder.newFolder("wiki") + val file = tempFolder.newFile("wiki/wiki.md") + file.writeText( + """ + - [Introduction](#introduction) + - [Usage](#usage) + + ## Introduction + Content + + ## Usage + Content + """.trimIndent() + ) + + runScript() + + assertThat(outContent.toString().trim()).contains(WIKI_TOC_CHECK_PASSED_OUTPUT_INDICATOR) + } + @Test fun testWikiTOCCheck_mismatchWikiTOC_checkFail() { tempFolder.newFolder("wiki")