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

Commit 3bb0e2b

Browse files
PR description CI check (#3363)
* 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
1 parent 3c74588 commit 3bb0e2b

File tree

11 files changed

+317
-10
lines changed

11 files changed

+317
-10
lines changed

.github/PULL_REQUEST_TEMPLATE.md

+11-8
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,19 @@ Please check if your pull request fulfills the following requirements:
66
- [ ] I confirm that I've run the code locally and everything works as expected.
77
- [ ] My PR includes only the necessary changes to fix the issue (i.e., no unnecessary files or lines of code are changed).
88
- [ ] 🎬 I've attached a **screen recording** of using the new code to the next paragraph (if applicable).
9+
910
## Screen recording of interacting with your changes:
1011
<!--💡 Tip: Drag & drop the video here. 💡-->
1112

1213
## What's changed?
1314
Describe with a few bullets **what's new:**
14-
<!--💡 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: 💡-->
1515
- I've fixed...
1616

1717
Before|After
18-
---------|---------
18+
---|---
1919
{media}|{media}
2020
{media}|{media}
21-
- ...
22-
- ...
21+
2322
## Risk factors
2423
**What may go wrong if we merge your PR?**
2524
- ...
@@ -28,12 +27,16 @@ Before|After
2827
**In what cases won't your code work?**
2928
- ...
3029
- ...
31-
## Does this PR close any GitHub issues?
30+
31+
## Does this PR close any GitHub issues? (do not delete)
3232
- Closes #{ISSUE_NUMBER}
33+
3334
<!--❗For example: - Closes #123 ❗-->
34-
<!--💡 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. 💡-->
35+
<!--⚠️ If done correctly, you'll see the issue title linked on the PR preview. ⚠️-->
3536
<!--💡 Tip: Multiple issues:
3637
- Closes #{ISSUE_NUMBER_1}, closes #{ISSUE_NUMBER_2}, closes #{ISSUE_NUMBER_3}
37-
💡-->
38-
## Troubleshooting CI failures ❌
38+
-->
39+
<!-- If the PR doesn't close any GitHub issues, type "Closes N/A" to pass the CI check. -->
40+
41+
## Troubleshooting GitHub Actions (CI) failures ❌
3942
Pull request checks failing? Read our [CI Troubleshooting guide](https://github.com/Ivy-Apps/ivy-wallet/blob/main/docs/CI-Troubleshooting.md).

.github/workflows/apk.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
distribution: 'adopt'
2020
java-version: '18'
2121

22-
- name: Enable Gradle Wrapper caching (optmization)
22+
- name: Enable Gradle Wrapper caching (optimization)
2323
uses: actions/cache@v4
2424
with:
2525
path: |

.github/workflows/ci_actions_test.yml

+4-1
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,7 @@ jobs:
3939
run: ./gradlew :ci-actions:issue-create-comment:test
4040

4141
- name: Test the CI "compose_stability" action
42-
run: ./gradlew :ci-actions:compose-stability:test
42+
run: ./gradlew :ci-actions:compose-stability:test
43+
44+
- name: Test the CI "pr-description-check" action
45+
run: ./gradlew :ci-actions:pr-description-check:test

.github/workflows/pr_description.yml

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: PR description check
2+
3+
on:
4+
pull_request:
5+
6+
jobs:
7+
pr-description-check:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- name: Checkout GIT
11+
uses: actions/checkout@v4
12+
13+
- name: Setup Java
14+
uses: actions/setup-java@v4
15+
with:
16+
distribution: 'adopt'
17+
java-version: '18'
18+
19+
- name: Enable Gradle Wrapper caching (optimization)
20+
uses: actions/cache@v4
21+
with:
22+
path: |
23+
~/.gradle/caches
24+
~/.gradle/wrapper
25+
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
26+
restore-keys: |
27+
${{ runner.os }}-gradle-
28+
29+
- name: Extract PR description (base 64)
30+
id: extract_description
31+
run: echo "PR_DESCRIPTION=$(jq -r '.pull_request.body' $GITHUB_EVENT_PATH | base64 | tr -d '\n')" >> $GITHUB_ENV
32+
33+
- name: Run PR Description Check
34+
run: ./gradlew :ci-actions:pr-description-check:run --args="${{ env.PR_DESCRIPTION }}"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
plugins {
2+
id("ivy.script")
3+
application
4+
}
5+
6+
application {
7+
mainClass = "ivy.automate.pr.MainKt"
8+
}
9+
10+
dependencies {
11+
implementation(projects.ciActions.base)
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package ivy.automate.pr
2+
3+
import arrow.core.Either
4+
5+
class ClosesIssueAnalyzer : PRDescriptionAnalyzer {
6+
override fun analyze(prDescription: String): Either<String, Unit> {
7+
val cleanedDescription = prDescription.removeMarkdownComments()
8+
9+
// Regex pattern to find "Closes #NUMBER" or "Closes N/A"
10+
val closesPattern = Regex("""(?i)closes\s+#\d+|closes\s+n/a""")
11+
if (closesPattern.containsMatchIn(cleanedDescription)) {
12+
return Either.Right(Unit)
13+
}
14+
15+
return Either.Left(MissingClosesProblem)
16+
}
17+
18+
private fun String.removeMarkdownComments(): String =
19+
replace(Regex("<!--.*?-->", RegexOption.DOT_MATCHES_ALL), "").trim()
20+
21+
companion object {
22+
val MissingClosesProblem = buildString {
23+
append("[PROBLEM] Missing Closes GitHub Issue section\n")
24+
append("This PR does not close any GitHub issues. ")
25+
append("Add \"Closes #123\" where 123 is the issue number ")
26+
append("or \"Closes N/A\" if doesn't close any issue.")
27+
}
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package ivy.automate.pr
2+
3+
import arrow.core.raise.catch
4+
import kotlinx.coroutines.runBlocking
5+
import kotlin.io.encoding.Base64
6+
import kotlin.io.encoding.ExperimentalEncodingApi
7+
8+
@OptIn(ExperimentalEncodingApi::class)
9+
fun main(args: Array<String>): Unit = runBlocking {
10+
require(args.size == 1) { "CI error: Missing PR description argument" }
11+
val description = catch({ String(Base64.decode(args.first())) }) { e ->
12+
throw IllegalArgumentException("CI error: Base 64 decoding failed! $e")
13+
}
14+
println("Analyzing PR description:")
15+
println(description)
16+
println("------")
17+
18+
val analyzers = listOf<PRDescriptionAnalyzer>(
19+
ClosesIssueAnalyzer(),
20+
)
21+
22+
val problems = analyzers.mapNotNull {
23+
it.analyze(description).leftOrNull()
24+
}
25+
if (problems.isNotEmpty()) {
26+
throw PRDescriptionError(
27+
buildString {
28+
append("\nWe found problems in your PR (Pull Request) description. ")
29+
append("Please, follow our PR template:\n")
30+
append("https://github.com/Ivy-Apps/ivy-wallet/blob/main/.github/PULL_REQUEST_TEMPLATE.md\n")
31+
problems.forEach {
32+
append(it)
33+
append("\n\n")
34+
}
35+
}
36+
)
37+
}
38+
39+
println("All good! The PR description looks fine.")
40+
}
41+
42+
class PRDescriptionError(msg: String) : Exception(msg)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package ivy.automate.pr
2+
3+
import arrow.core.Either
4+
5+
interface PRDescriptionAnalyzer {
6+
fun analyze(prDescription: String): Either<String, Unit>
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
package ivy.automate.pr
2+
3+
import arrow.core.Either
4+
import com.google.testing.junit.testparameterinjector.TestParameter
5+
import com.google.testing.junit.testparameterinjector.TestParameterInjector
6+
import io.kotest.matchers.shouldBe
7+
import org.junit.Before
8+
import org.junit.Test
9+
import org.junit.runner.RunWith
10+
11+
@RunWith(TestParameterInjector::class)
12+
class ClosesIssueAnalyzerTest {
13+
14+
private lateinit var analyzer: PRDescriptionAnalyzer
15+
16+
@Before
17+
fun setup() {
18+
analyzer = ClosesIssueAnalyzer()
19+
}
20+
21+
enum class PRDescTestCase(
22+
val prDescription: String,
23+
val expectedResult: Either<String, Unit>
24+
) {
25+
VALID_SHORT_1(
26+
prDescription = """
27+
## Pull request (PR) checklist
28+
Please check if your pull request fulfills the following requirements:
29+
<!--💡 Tip: Tick checkboxes like this: [x] 💡-->
30+
- [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.
31+
- [x] I've read and understand the [Developer Guidelines](https://github.com/Ivy-Apps/ivy-wallet/blob/main/docs/Guidelines.md).
32+
- [x] I confirm that I've run the code locally and everything works as expected.
33+
- [x] My PR includes only the necessary changes to fix the issue (i.e., no unnecessary files or lines of code are changed).
34+
- [x] 🎬 I've attached a **screen recording** of using the new code to the next paragraph (if applicable).
35+
36+
## What's changed?
37+
- The new name reflects the full-featured nature of the application
38+
## Does this PR close any GitHub issues?
39+
- Closes #3361
40+
""".trimIndent(),
41+
expectedResult = Either.Right(Unit),
42+
),
43+
INVALID_SHORT_1(
44+
prDescription = """
45+
## Pull request (PR) checklist
46+
Please check if your pull request fulfills the following requirements:
47+
<!--💡 Tip: Tick checkboxes like this: [x] 💡-->
48+
- [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.
49+
- [x] I've read and understand the [Developer Guidelines](https://github.com/Ivy-Apps/ivy-wallet/blob/main/docs/Guidelines.md).
50+
- [x] I confirm that I've run the code locally and everything works as expected.
51+
- [x] My PR includes only the necessary changes to fix the issue (i.e., no unnecessary files or lines of code are changed).
52+
- [x] 🎬 I've attached a **screen recording** of using the new code to the next paragraph (if applicable).
53+
54+
## What's changed?
55+
- The new name reflects the full-featured nature of the application
56+
""".trimIndent(),
57+
expectedResult = Either.Left(ClosesIssueAnalyzer.MissingClosesProblem),
58+
),
59+
INVALID_DEFAULT_TEMPLATE(
60+
prDescription = """
61+
## Pull request (PR) checklist
62+
Please check if your pull request fulfills the following requirements:
63+
<!--💡 Tip: Tick checkboxes like this: [x] 💡-->
64+
- [ ] 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.
65+
- [ ] I've read and understand the [Developer Guidelines](https://github.com/Ivy-Apps/ivy-wallet/blob/main/docs/Guidelines.md).
66+
- [ ] I confirm that I've run the code locally and everything works as expected.
67+
- [ ] My PR includes only the necessary changes to fix the issue (i.e., no unnecessary files or lines of code are changed).
68+
- [ ] 🎬 I've attached a **screen recording** of using the new code to the next paragraph (if applicable).
69+
## Screen recording of interacting with your changes:
70+
<!--💡 Tip: Drag & drop the video here. 💡-->
71+
72+
## What's changed?
73+
Describe with a few bullets **what's new:**
74+
<!--💡 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: 💡-->
75+
- I've fixed...
76+
77+
Before|After
78+
---------|---------
79+
{media}|{media}
80+
{media}|{media}
81+
- ...
82+
- ...
83+
## Risk factors
84+
**What may go wrong if we merge your PR?**
85+
- ...
86+
- ...
87+
88+
**In what cases won't your code work?**
89+
- ...
90+
- ...
91+
## Does this PR close any GitHub issues? (do not delete)
92+
- Closes #{ISSUE_NUMBER}
93+
<!--❗For example: - Closes #123 ❗-->
94+
<!--💡 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. 💡-->
95+
<!--💡 Tip: Multiple issues:
96+
- Closes #{ISSUE_NUMBER_1}, closes #{ISSUE_NUMBER_2}, closes #{ISSUE_NUMBER_3}
97+
98+
If the PR doesn't close any GitHub issues, type "Closes N/A" to pass the CI check.
99+
💡-->
100+
## Troubleshooting CI failures ❌
101+
Pull request checks failing? Read our [CI Troubleshooting guide](https://github.com/Ivy-Apps/ivy-wallet/blob/main/docs/CI-Troubleshooting.md).
102+
""".trimIndent(),
103+
expectedResult = Either.Left(ClosesIssueAnalyzer.MissingClosesProblem),
104+
),
105+
VALID_TEMPLATE_CLOSES_NUMBER(
106+
prDescription = """
107+
## Pull request (PR) checklist
108+
Please check if your pull request fulfills the following requirements:
109+
<!--💡 Tip: Tick checkboxes like this: [x] 💡-->
110+
- [ ] 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.
111+
- [ ] I've read and understand the [Developer Guidelines](https://github.com/Ivy-Apps/ivy-wallet/blob/main/docs/Guidelines.md).
112+
- [ ] I confirm that I've run the code locally and everything works as expected.
113+
- [ ] My PR includes only the necessary changes to fix the issue (i.e., no unnecessary files or lines of code are changed).
114+
- [ ] 🎬 I've attached a **screen recording** of using the new code to the next paragraph (if applicable).
115+
116+
## Screen recording of interacting with your changes:
117+
<!--💡 Tip: Drag & drop the video here. 💡-->
118+
119+
## What's changed?
120+
Describe with a few bullets **what's new:**
121+
- I've fixed...
122+
-
123+
124+
Before|After
125+
---------|---------
126+
{media}|{media}
127+
{media}|{media}
128+
129+
## Risk factors
130+
**What may go wrong if we merge your PR?**
131+
- ...
132+
- ...
133+
134+
**In what cases won't your code work?**
135+
- ...
136+
- ...
137+
138+
## Does this PR close any GitHub issues? (do not delete)
139+
- Closes #123
140+
141+
<!--❗For example: - Closes #123 ❗-->
142+
<!--💡 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. 💡-->
143+
<!--💡 Tip: Multiple issues:
144+
- Closes #{ISSUE_NUMBER_1}, closes #{ISSUE_NUMBER_2}, closes #{ISSUE_NUMBER_3}
145+
146+
If the PR doesn't close any GitHub issues, type "Closes N/A" to pass the CI check.
147+
💡-->
148+
149+
## Troubleshooting GitHub Actions (CI) failures ❌
150+
Pull request checks failing? Read our [CI Troubleshooting guide](https://github.com/Ivy-Apps/ivy-wallet/blob/main/docs/CI-Troubleshooting.md).
151+
""".trimIndent(),
152+
expectedResult = Either.Right(Unit)
153+
),
154+
VALID_CLOSES_NA(
155+
prDescription = "Closes N/A",
156+
expectedResult = Either.Right(Unit),
157+
)
158+
}
159+
160+
@Test
161+
fun `validate PR description check`(
162+
@TestParameter testCase: PRDescTestCase,
163+
) {
164+
// When
165+
val result = analyzer.analyze(testCase.prDescription)
166+
167+
// Then
168+
result shouldBe testCase.expectedResult
169+
}
170+
}

docs/CI-Troubleshooting.md

+6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
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.
44

5+
## PR description check
6+
7+
It means that you didn't follow our [official PR template](../.github/PULL_REQUEST_TEMPLATE.md).
8+
Update your PR description with all necessary information. You can also check the exact error by
9+
clicking "Details" on the failing (❌) check.
10+
511
## Detekt
612
[Detekt](https://detekt.dev/) is a static code analyzer for Kotlin that we use to enforce code readability and good practices.
713

settings.gradle.kts

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ include(":ci-actions:base")
1616
include(":ci-actions:compose-stability")
1717
include(":ci-actions:issue-assign")
1818
include(":ci-actions:issue-create-comment")
19+
include(":ci-actions:pr-description-check")
1920
include(":screen:accounts")
2021
include(":screen:attributions")
2122
include(":screen:balance")

0 commit comments

Comments
 (0)