diff --git a/.github/workflows/coverage-badge.yml b/.github/workflows/coverage-badge.yml new file mode 100644 index 0000000..a7b0ea7 --- /dev/null +++ b/.github/workflows/coverage-badge.yml @@ -0,0 +1,34 @@ +name: Create coverage badge + +on: + push: + branches: [ "main" ] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Set up JDK + uses: actions/setup-java@v3 + with: + java-version: '21' + distribution: 'temurin' + + - name: Generate coverage output + run: | + echo "COVERAGE=$(${{github.workspace}}/gradlew -q printLineCoverage)" >> $GITHUB_ENV + + - name: Update dynamic badge gist + uses: schneegans/dynamic-badges-action@v1.7.0 + with: + auth: ${{secrets.GIST_SECRET}} + gistID: 040646868c4c6473297b0d4e1546bf21 + filename: KtScheduler_coverage_badge.json + label: coverage + message: ${{env.COVERAGE}}% + valColorRange: ${{env.COVERAGE}} + minColorRange: 0 + maxColorRange: 100 diff --git a/.github/workflows/test_coverage.yml b/.github/workflows/test_coverage.yml new file mode 100644 index 0000000..8b33fcd --- /dev/null +++ b/.github/workflows/test_coverage.yml @@ -0,0 +1,26 @@ +name: coverage + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: set up JDK 21 + uses: actions/setup-java@v3 + with: + java-version: '21' + distribution: 'temurin' + cache: gradle + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Run tests with gradle + run: ./gradlew koverVerify diff --git a/README.md b/README.md index 1dba333..bfa58e8 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,12 @@
**KtScheduler** is a lightweight task/job scheduling library for Kotlin, powered by Kotlin coroutines! The design of @@ -52,7 +54,8 @@ val job = Job( jobId = "OneTimeJob", // Must be unique for each job function = { println("OneTime Job executed at ${ZonedDateTime.now(timeZone)}") }, trigger = OneTimeTrigger(ZonedDateTime.now(timeZone).plusSeconds(5)), - // Next runtime of the job; when creating the job for the first time, it will be used as the initial runtime. + // Next runtime of the job; when creating the job for the first time, + // it will be used as the initial runtime. nextRunTime = ZonedDateTime.now(timeZone).plusSeconds(5), // Coroutine dispatcher in which the job should be executed. dispatcher = Dispatchers.Default @@ -168,7 +171,7 @@ the issue you want to contribute to before starting to work on it. ### Supporting ❤️ If you found this library helpful, you can support me by giving a small tip -via [GitHub Sponsors](https://github.com/sponsors/starry-shivam) and joining the list of stargazers 🌟 +via [GitHub Sponsors](https://github.com/sponsors/starry-shivam) and/or joing the list of [stargazers](https://github.com/starry-shivam/KtScheduler/stargazers) by leaving a star! 🌟 ------ diff --git a/build.gradle.kts b/build.gradle.kts index db4c6ac..7360221 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,5 @@ +import javax.xml.parsers.DocumentBuilderFactory + plugins { kotlin("jvm") version "2.0.0" id("org.jetbrains.kotlinx.kover") version "0.8.1" @@ -24,7 +26,8 @@ dependencies { kover { reports { - verify { rule { minBound(70) } } + // Require 95% minimum test coverage. + verify { rule { minBound(95) } } } } @@ -39,4 +42,39 @@ publishing { } } +// Print line coverage percentage to console so we can generate badge in CI. +tasks.register("printLineCoverage") { + group = "verification" + dependsOn("koverXmlReport") + doLast { + val report = file("$buildDir/reports/kover/report.xml") + + val doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(report) + val rootNode = doc.firstChild + var childNode = rootNode.firstChild + + var coveragePercent = 0.0 + + while (childNode != null) { + if (childNode.nodeName == "counter") { + val typeAttr = childNode.attributes.getNamedItem("type") + if (typeAttr.textContent == "LINE") { + val missedAttr = childNode.attributes.getNamedItem("missed") + val coveredAttr = childNode.attributes.getNamedItem("covered") + + val missed = missedAttr.textContent.toLong() + val covered = coveredAttr.textContent.toLong() + + coveragePercent = (covered * 100.0) / (missed + covered) + + break + } + } + childNode = childNode.nextSibling + } + + println("%.1f".format(coveragePercent)) + } +} +