Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #5015: Added CI to oppia-android wiki (check toc) #5382

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
13efcfa
Script to Check the Table of Contents in the Wiki and CI workflow
Rd4dev Apr 10, 2024
d3795b3
Fix Lint Tests by adding new lines after and before ( and )
Rd4dev Apr 10, 2024
1840f60
Fix Lint Tests by properly indenting the error messages
Rd4dev Apr 10, 2024
9fdea36
Merge branch 'develop' of https://github.com/Rd4dev/oppia-android int…
Rd4dev Apr 29, 2024
d113747
Modified id with camel case convention and Revised the name to be mor…
Rd4dev Apr 29, 2024
39f0c2f
Merge branch 'develop' of https://github.com/Rd4dev/oppia-android int…
Rd4dev Jun 4, 2024
d55ddac
Resolve merge conflicts and fixed kdoc styling
Rd4dev Jul 4, 2024
49917c7
Renaming wiki dir variables for better clarity
Rd4dev Jul 5, 2024
94fa4f6
Simplified the wiki table of content check logic with kotlin functions
Rd4dev Jul 5, 2024
3e74a99
Code clean up and replaced exception with error statement
Rd4dev Jul 5, 2024
5a8b4b9
Added test cases for wiki toc checks
Rd4dev Jul 5, 2024
9e4386a
Fix Lint Checks for indentation and missing spaces
Rd4dev Jul 5, 2024
9193d15
Fix Lint check buildifier reformat
Rd4dev Jul 5, 2024
620c3b0
Merge branch 'develop' of https://github.com/Rd4dev/oppia-android int…
Rd4dev Sep 4, 2024
99c0371
Merge branch 'develop' of https://github.com/Rd4dev/oppia-android int…
Rd4dev Sep 5, 2024
72d0a2b
Added missing test cases for no directory found to hit 100% coverage
Rd4dev Sep 5, 2024
b5c9cf3
Upgraded the Bazel version, removed cache env, used Regex to check he…
Rd4dev Oct 2, 2024
fab6c2e
Merge branch 'develop' of https://github.com/Rd4dev/oppia-android int…
Rd4dev Oct 2, 2024
afaf59e
Added pull-request trigger to check on every PR creation, removed deb…
Rd4dev Oct 3, 2024
6dfa3bb
Merge branch 'develop' of https://github.com/Rd4dev/oppia-android int…
Rd4dev Oct 3, 2024
be00151
Trigger only when changes are made to the wiki dir
Rd4dev Oct 3, 2024
c18ac91
Conditional execution of the wiki-deploy to only proceed if the event…
Rd4dev Oct 3, 2024
2dfd045
Removed the test case for checking TOC present as the log statement t…
Rd4dev Oct 3, 2024
c7d0d11
Re-adding the test case to hit coverage but now checking with final r…
Rd4dev Oct 3, 2024
7cbad11
Updating the mis-matched TOC to confirm the TOC check status
Rd4dev Oct 9, 2024
2f15577
Merge branch 'develop' of https://github.com/Rd4dev/oppia-android int…
Rd4dev Oct 9, 2024
e9af4ab
Adding concurrency to wiki actions as it continues to run on subseque…
Rd4dev Oct 9, 2024
7110715
Modified the visibilities and removed private fun Kdocs, also updated…
Rd4dev Oct 9, 2024
0077bd4
Fix ktlint unexpected spacing before (
Rd4dev Oct 9, 2024
1d842fc
Adding confetti emoji to match with the header link
Rd4dev Oct 9, 2024
fa76163
Replaced checking toc end by blank endline with header tags as they a…
Rd4dev Oct 9, 2024
609df11
Fixed ktlint max line exceeded
Rd4dev Oct 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion .github/workflows/wiki.yml
Original file line number Diff line number Diff line change
@@ -1,20 +1,45 @@
name: Deploy to Wiki
on:
pull_request:
paths:
- 'wiki/**'
push:
branches:
- develop
paths:
- 'wiki/**'
# Triggers this workflow when the wiki is changed
# Triggers this workflow when the wiki is changed.
# (see https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#gollum).
gollum:

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true

jobs:
table_of_contents_check:
# To verify that the wiki's table of contents matches the headers accurately.
name: Check Wiki Table of Contents
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2

- name: Set up Bazel
uses: abhinavsingh/setup-bazel@v3
with:
version: 6.5.0

- name: Check Wiki Table of Contents
id: checkWikiToc
run: |
bazel run //scripts:wiki_table_of_contents_check -- ${GITHUB_WORKSPACE}

wiki-deploy:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-20.04]
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' }}
steps:
- uses: actions/checkout@v3
with:
Expand Down
9 changes: 9 additions & 0 deletions scripts/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,15 @@ 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",
],
)

kt_jvm_binary(
name = "run_coverage",
testonly = True,
Expand Down
18 changes: 18 additions & 0 deletions scripts/src/java/org/oppia/android/scripts/wiki/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -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",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
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_table_of_contents_check -- <path_to_default_working_directory>
*
* 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_table_of_contents_check -- $(pwd)
*/
fun main(vararg args: String) {
// Path to the repo's wiki.
val wikiDirPath = "${args[0]}/wiki/"
val wikiDir = File(wikiDirPath)

// 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.")
}
}

private fun processWikiDirectory(wikiDir: File) {
wikiDir.listFiles()?.forEach { file ->
checkTableOfContents(file)
}
}

private fun checkTableOfContents(file: File) {
val fileContents = file.readLines()
val tocStartIdx = fileContents.indexOfFirst {
it.contains(Regex("""##\s+Table\s+of\s+Contents""", RegexOption.IGNORE_CASE))
}
if (tocStartIdx == -1) {
return
}

// Skipping the blank line after the ## Table of Contents
val tocEndIdx = fileContents.subList(tocStartIdx + 2, fileContents.size).indexOfFirst {
it.startsWith("#")
}.takeIf { it != -1 }
?: error("Wiki doesn't contain headers referenced in Table of Contents.")

val tocSpecificLines = fileContents.subList(tocStartIdx, tocStartIdx + tocEndIdx + 1)

for (line in tocSpecificLines) {
if (line.trimStart().startsWith("- [") && !line.contains("https://")) {
validateTableOfContents(file, line)
}
}
}

private 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("[?&./:’'*!,(){}\\[\\]+]"), "")
?.trim()

// 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}. " +
"\nThe Title: '${titleRegex.find(line)?.groupValues?.get(1)}' " +
"doesn't match with its corresponding Link: '${linkRegex.find(line)?.groupValues?.get(1)}'."
)
}
}
Original file line number Diff line number Diff line change
@@ -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",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
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
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() {
System.setOut(PrintStream(outContent))
}

@After
fun tearDown() {
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(
"""
## Table of Contents

- [Introduction](#introduction)
- [Usage](#usage)

## Introduction
Content

## Usage
Content
""".trimIndent()
)

runScript()

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_wikiTOCReference_noHeadersFound_throwsException() {
tempFolder.newFolder("wiki")
val file = tempFolder.newFile("wiki/wiki.md")
file.writeText(
"""
## Table of Contents

- [Introduction](#introductions)

""".trimIndent()
)

val exception = assertThrows<IllegalStateException>() {
runScript()
}

assertThat(exception).hasMessageThat().contains(
"Wiki doesn't contain headers referenced in Table of Contents."
)
}

@Test
fun testWikiTOCCheck_mismatchWikiTOC_checkFail() {
tempFolder.newFolder("wiki")
val file = tempFolder.newFile("wiki/wiki.md")
file.writeText(
"""
## Table of Contents

- [Introduction](#introductions)
- [Usage](#usage)

## Introduction
Content

## Usage
Content
""".trimIndent()
)

val exception = assertThrows<IllegalStateException>() {
runScript()
}

assertThat(exception).hasMessageThat().contains(WIKI_TOC_CHECK_FAILED_OUTPUT_INDICATOR)
}

@Test
fun testWikiTOCCheck_validWikiTOCWithSeparator_checkPass() {
tempFolder.newFolder("wiki")
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() {
tempFolder.newFolder("wiki")
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() {
main(tempFolder.root.absolutePath)
}
}
2 changes: 1 addition & 1 deletion wiki/Guidance-on-submitting-a-PR.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Note: If your change involves more than around 500 lines of code, we recommend f
- [Tips for getting your PR submitted](#tips-for-getting-your-pr-submitted)
- [Appendix: Resolving merge conflicts using the terminal](#appendix-resolving-merge-conflicts-using-the-terminal)
- [Appendix: Resolving merge conflicts using Android Studio](#appendix-resolving-merge-conflicts-using-android-studio)
- [Step 4: Tidy up and celebrate!](#step-4-tidy-up-and-celebrate-confetti_ball)
- [Step 4: Tidy up and celebrate! :confetti_ball:](#step-4-tidy-up-and-celebrate-confetti_ball)

## Step 1: Making a local code change

Expand Down
2 changes: 1 addition & 1 deletion wiki/Installing-Oppia-Android.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This wiki page explains how to install Oppia Android on your local machine. If y
- [Prepare developer environment](#prepare-developer-environment)
- [Install oppia-android](#install-oppia-android)
- [Run the app from Android Studio](#run-the-app-from-android-studio)
- [Run the tests](#set-up-and-run-tests)
- [Set up and Run tests](#set-up-and-run-tests)
- [Step-by-Step guidance for setting up and running app modules robolectric test](#step-by-step-guidance-for-setting-up-and-running-app-modules-robolectric-test)
- [For tests that are in non-app modules, such as **domain** or **utility**:](#for-tests-that-are-in-non-app-modules-such-as-domain-or-utility)

Expand Down
2 changes: 1 addition & 1 deletion wiki/Interpreting-CI-Results.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## Table of Contents

- [How to find the error message for a Failing CI check](#how-to-find-error-message-for-failing-ci-checks)
- [How to find error message for Failing CI checks](#how-to-find-error-message-for-failing-ci-checks)
- [Developer Video - Understanding CI check failures](#developer-video---understanding-ci-check-failures)

## How to find error message for Failing CI checks
Expand Down
Loading
Loading