Skip to content
This repository has been archived by the owner on Nov 5, 2024. It is now read-only.

Commit

Permalink
PR description CI check (#3363)
Browse files Browse the repository at this point in the history
* Add PR description CI check and improve the PR template

* Add it to the ci_actions_test.yml

* Run the check also on PR open

* And reopened

* Rename check

* Implement Main.kt

* Fix workflow

* Add CI troubleshooting docs

* WIP: Fix the workflow

* Fix the workflow

* Fix Detekt issues

* Simplify the PR template

* Expand the workflow trigger
  • Loading branch information
ILIYANGERMANOV authored Jul 23, 2024
1 parent 3c74588 commit 3bb0e2b
Show file tree
Hide file tree
Showing 11 changed files with 317 additions and 10 deletions.
19 changes: 11 additions & 8 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,19 @@ Please check if your pull request fulfills the following requirements:
- [ ] I confirm that I've run the code locally and everything works as expected.
- [ ] My PR includes only the necessary changes to fix the issue (i.e., no unnecessary files or lines of code are changed).
- [ ] 🎬 I've attached a **screen recording** of using the new code to the next paragraph (if applicable).

## Screen recording of interacting with your changes:
<!--💡 Tip: Drag & drop the video here. 💡-->

## What's changed?
Describe with a few bullets **what's new:**
<!--💡 Tip: After each more important point leave one line empty and show your changes in markdown table with screenshots or screen recordings replacing {media}. In the end, it should look like this: 💡-->
- I've fixed...

Before|After
---------|---------
---|---
{media}|{media}
{media}|{media}
- ...
- ...

## Risk factors
**What may go wrong if we merge your PR?**
- ...
Expand All @@ -28,12 +27,16 @@ Before|After
**In what cases won't your code work?**
- ...
- ...
## Does this PR close any GitHub issues?

## Does this PR close any GitHub issues? (do not delete)
- Closes #{ISSUE_NUMBER}

<!--❗For example: - Closes #123 ❗-->
<!--💡 Tip: Replace {ISSUE_NUMBER} with the number of Ivy Wallet ISSUE (https://github.com/Ivy-Apps/ivy-wallet/issues)(❗NOT PR❗) which this pull request fixes. If done correctly, you'll see the issue title linked on PR preview. 💡-->
<!--⚠️ If done correctly, you'll see the issue title linked on the PR preview. ⚠️-->
<!--💡 Tip: Multiple issues:
- Closes #{ISSUE_NUMBER_1}, closes #{ISSUE_NUMBER_2}, closes #{ISSUE_NUMBER_3}
💡-->
## Troubleshooting CI failures ❌
-->
<!-- If the PR doesn't close any GitHub issues, type "Closes N/A" to pass the CI check. -->

## Troubleshooting GitHub Actions (CI) failures ❌
Pull request checks failing? Read our [CI Troubleshooting guide](https://github.com/Ivy-Apps/ivy-wallet/blob/main/docs/CI-Troubleshooting.md).
2 changes: 1 addition & 1 deletion .github/workflows/apk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
distribution: 'adopt'
java-version: '18'

- name: Enable Gradle Wrapper caching (optmization)
- name: Enable Gradle Wrapper caching (optimization)
uses: actions/cache@v4
with:
path: |
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/ci_actions_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,7 @@ jobs:
run: ./gradlew :ci-actions:issue-create-comment:test

- name: Test the CI "compose_stability" action
run: ./gradlew :ci-actions:compose-stability:test
run: ./gradlew :ci-actions:compose-stability:test

- name: Test the CI "pr-description-check" action
run: ./gradlew :ci-actions:pr-description-check:test
34 changes: 34 additions & 0 deletions .github/workflows/pr_description.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: PR description check

on:
pull_request:

jobs:
pr-description-check:
runs-on: ubuntu-latest
steps:
- name: Checkout GIT
uses: actions/checkout@v4

- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: 'adopt'
java-version: '18'

- name: Enable Gradle Wrapper caching (optimization)
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Extract PR description (base 64)
id: extract_description
run: echo "PR_DESCRIPTION=$(jq -r '.pull_request.body' $GITHUB_EVENT_PATH | base64 | tr -d '\n')" >> $GITHUB_ENV

- name: Run PR Description Check
run: ./gradlew :ci-actions:pr-description-check:run --args="${{ env.PR_DESCRIPTION }}"
12 changes: 12 additions & 0 deletions ci-actions/pr-description-check/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
plugins {
id("ivy.script")
application
}

application {
mainClass = "ivy.automate.pr.MainKt"
}

dependencies {
implementation(projects.ciActions.base)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package ivy.automate.pr

import arrow.core.Either

class ClosesIssueAnalyzer : PRDescriptionAnalyzer {
override fun analyze(prDescription: String): Either<String, Unit> {
val cleanedDescription = prDescription.removeMarkdownComments()

// Regex pattern to find "Closes #NUMBER" or "Closes N/A"
val closesPattern = Regex("""(?i)closes\s+#\d+|closes\s+n/a""")
if (closesPattern.containsMatchIn(cleanedDescription)) {
return Either.Right(Unit)
}

return Either.Left(MissingClosesProblem)
}

private fun String.removeMarkdownComments(): String =
replace(Regex("<!--.*?-->", RegexOption.DOT_MATCHES_ALL), "").trim()

companion object {
val MissingClosesProblem = buildString {
append("[PROBLEM] Missing Closes GitHub Issue section\n")
append("This PR does not close any GitHub issues. ")
append("Add \"Closes #123\" where 123 is the issue number ")
append("or \"Closes N/A\" if doesn't close any issue.")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package ivy.automate.pr

import arrow.core.raise.catch
import kotlinx.coroutines.runBlocking
import kotlin.io.encoding.Base64
import kotlin.io.encoding.ExperimentalEncodingApi

@OptIn(ExperimentalEncodingApi::class)
fun main(args: Array<String>): Unit = runBlocking {
require(args.size == 1) { "CI error: Missing PR description argument" }
val description = catch({ String(Base64.decode(args.first())) }) { e ->
throw IllegalArgumentException("CI error: Base 64 decoding failed! $e")
}
println("Analyzing PR description:")
println(description)
println("------")

val analyzers = listOf<PRDescriptionAnalyzer>(
ClosesIssueAnalyzer(),
)

val problems = analyzers.mapNotNull {
it.analyze(description).leftOrNull()
}
if (problems.isNotEmpty()) {
throw PRDescriptionError(
buildString {
append("\nWe found problems in your PR (Pull Request) description. ")
append("Please, follow our PR template:\n")
append("https://github.com/Ivy-Apps/ivy-wallet/blob/main/.github/PULL_REQUEST_TEMPLATE.md\n")
problems.forEach {
append(it)
append("\n\n")
}
}
)
}

println("All good! The PR description looks fine.")
}

class PRDescriptionError(msg: String) : Exception(msg)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package ivy.automate.pr

import arrow.core.Either

interface PRDescriptionAnalyzer {
fun analyze(prDescription: String): Either<String, Unit>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package ivy.automate.pr

import arrow.core.Either
import com.google.testing.junit.testparameterinjector.TestParameter
import com.google.testing.junit.testparameterinjector.TestParameterInjector
import io.kotest.matchers.shouldBe
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(TestParameterInjector::class)
class ClosesIssueAnalyzerTest {

private lateinit var analyzer: PRDescriptionAnalyzer

@Before
fun setup() {
analyzer = ClosesIssueAnalyzer()
}

enum class PRDescTestCase(
val prDescription: String,
val expectedResult: Either<String, Unit>
) {
VALID_SHORT_1(
prDescription = """
## Pull request (PR) checklist
Please check if your pull request fulfills the following requirements:
<!--💡 Tip: Tick checkboxes like this: [x] 💡-->
- [x] I've read the [Contribution Guidelines](https://github.com/Ivy-Apps/ivy-wallet/blob/main/CONTRIBUTING.md) and my PR doesn't break the rules.
- [x] I've read and understand the [Developer Guidelines](https://github.com/Ivy-Apps/ivy-wallet/blob/main/docs/Guidelines.md).
- [x] I confirm that I've run the code locally and everything works as expected.
- [x] My PR includes only the necessary changes to fix the issue (i.e., no unnecessary files or lines of code are changed).
- [x] 🎬 I've attached a **screen recording** of using the new code to the next paragraph (if applicable).
## What's changed?
- The new name reflects the full-featured nature of the application
## Does this PR close any GitHub issues?
- Closes #3361
""".trimIndent(),
expectedResult = Either.Right(Unit),
),
INVALID_SHORT_1(
prDescription = """
## Pull request (PR) checklist
Please check if your pull request fulfills the following requirements:
<!--💡 Tip: Tick checkboxes like this: [x] 💡-->
- [x] I've read the [Contribution Guidelines](https://github.com/Ivy-Apps/ivy-wallet/blob/main/CONTRIBUTING.md) and my PR doesn't break the rules.
- [x] I've read and understand the [Developer Guidelines](https://github.com/Ivy-Apps/ivy-wallet/blob/main/docs/Guidelines.md).
- [x] I confirm that I've run the code locally and everything works as expected.
- [x] My PR includes only the necessary changes to fix the issue (i.e., no unnecessary files or lines of code are changed).
- [x] 🎬 I've attached a **screen recording** of using the new code to the next paragraph (if applicable).
## What's changed?
- The new name reflects the full-featured nature of the application
""".trimIndent(),
expectedResult = Either.Left(ClosesIssueAnalyzer.MissingClosesProblem),
),
INVALID_DEFAULT_TEMPLATE(
prDescription = """
## Pull request (PR) checklist
Please check if your pull request fulfills the following requirements:
<!--💡 Tip: Tick checkboxes like this: [x] 💡-->
- [ ] I've read the [Contribution Guidelines](https://github.com/Ivy-Apps/ivy-wallet/blob/main/CONTRIBUTING.md) and my PR doesn't break the rules.
- [ ] I've read and understand the [Developer Guidelines](https://github.com/Ivy-Apps/ivy-wallet/blob/main/docs/Guidelines.md).
- [ ] I confirm that I've run the code locally and everything works as expected.
- [ ] My PR includes only the necessary changes to fix the issue (i.e., no unnecessary files or lines of code are changed).
- [ ] 🎬 I've attached a **screen recording** of using the new code to the next paragraph (if applicable).
## Screen recording of interacting with your changes:
<!--💡 Tip: Drag & drop the video here. 💡-->
## What's changed?
Describe with a few bullets **what's new:**
<!--💡 Tip: After each more important point leave one line empty and show your changes in markdown table with screenshots or screen recordings replacing {media}. In the end, it should look like this: 💡-->
- I've fixed...
Before|After
---------|---------
{media}|{media}
{media}|{media}
- ...
- ...
## Risk factors
**What may go wrong if we merge your PR?**
- ...
- ...
**In what cases won't your code work?**
- ...
- ...
## Does this PR close any GitHub issues? (do not delete)
- Closes #{ISSUE_NUMBER}
<!--❗For example: - Closes #123 ❗-->
<!--💡 Tip: Replace {ISSUE_NUMBER} with the number of Ivy Wallet ISSUE (https://github.com/Ivy-Apps/ivy-wallet/issues)(❗NOT PR❗) which this pull request fixes. If done correctly, you'll see the issue title linked on PR preview. 💡-->
<!--💡 Tip: Multiple issues:
- Closes #{ISSUE_NUMBER_1}, closes #{ISSUE_NUMBER_2}, closes #{ISSUE_NUMBER_3}
If the PR doesn't close any GitHub issues, type "Closes N/A" to pass the CI check.
💡-->
## Troubleshooting CI failures ❌
Pull request checks failing? Read our [CI Troubleshooting guide](https://github.com/Ivy-Apps/ivy-wallet/blob/main/docs/CI-Troubleshooting.md).
""".trimIndent(),
expectedResult = Either.Left(ClosesIssueAnalyzer.MissingClosesProblem),
),
VALID_TEMPLATE_CLOSES_NUMBER(
prDescription = """
## Pull request (PR) checklist
Please check if your pull request fulfills the following requirements:
<!--💡 Tip: Tick checkboxes like this: [x] 💡-->
- [ ] I've read the [Contribution Guidelines](https://github.com/Ivy-Apps/ivy-wallet/blob/main/CONTRIBUTING.md) and my PR doesn't break the rules.
- [ ] I've read and understand the [Developer Guidelines](https://github.com/Ivy-Apps/ivy-wallet/blob/main/docs/Guidelines.md).
- [ ] I confirm that I've run the code locally and everything works as expected.
- [ ] My PR includes only the necessary changes to fix the issue (i.e., no unnecessary files or lines of code are changed).
- [ ] 🎬 I've attached a **screen recording** of using the new code to the next paragraph (if applicable).
## Screen recording of interacting with your changes:
<!--💡 Tip: Drag & drop the video here. 💡-->
## What's changed?
Describe with a few bullets **what's new:**
- I've fixed...
-
Before|After
---------|---------
{media}|{media}
{media}|{media}
## Risk factors
**What may go wrong if we merge your PR?**
- ...
- ...
**In what cases won't your code work?**
- ...
- ...
## Does this PR close any GitHub issues? (do not delete)
- Closes #123
<!--❗For example: - Closes #123 ❗-->
<!--💡 Tip: Replace {ISSUE_NUMBER} with the number of Ivy Wallet ISSUE (https://github.com/Ivy-Apps/ivy-wallet/issues)(❗NOT PR❗) which this pull request fixes. If done correctly, you'll see the issue title linked on PR preview. 💡-->
<!--💡 Tip: Multiple issues:
- Closes #{ISSUE_NUMBER_1}, closes #{ISSUE_NUMBER_2}, closes #{ISSUE_NUMBER_3}
If the PR doesn't close any GitHub issues, type "Closes N/A" to pass the CI check.
💡-->
## Troubleshooting GitHub Actions (CI) failures ❌
Pull request checks failing? Read our [CI Troubleshooting guide](https://github.com/Ivy-Apps/ivy-wallet/blob/main/docs/CI-Troubleshooting.md).
""".trimIndent(),
expectedResult = Either.Right(Unit)
),
VALID_CLOSES_NA(
prDescription = "Closes N/A",
expectedResult = Either.Right(Unit),
)
}

@Test
fun `validate PR description check`(
@TestParameter testCase: PRDescTestCase,
) {
// When
val result = analyzer.analyze(testCase.prDescription)

// Then
result shouldBe testCase.expectedResult
}
}
6 changes: 6 additions & 0 deletions docs/CI-Troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

If you see any of the PR checks failing (❌) go to [Actions](https://github.com/Ivy-Apps/ivy-wallet/actions) and find it there. Or simply click "Details" next to the failed check and explore the logs to see why it has failed.

## PR description check

It means that you didn't follow our [official PR template](../.github/PULL_REQUEST_TEMPLATE.md).
Update your PR description with all necessary information. You can also check the exact error by
clicking "Details" on the failing (❌) check.

## Detekt
[Detekt](https://detekt.dev/) is a static code analyzer for Kotlin that we use to enforce code readability and good practices.

Expand Down
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ include(":ci-actions:base")
include(":ci-actions:compose-stability")
include(":ci-actions:issue-assign")
include(":ci-actions:issue-create-comment")
include(":ci-actions:pr-description-check")
include(":screen:accounts")
include(":screen:attributions")
include(":screen:balance")
Expand Down

0 comments on commit 3bb0e2b

Please sign in to comment.