From ee11847235c35bab46d04ff8d0190dd3cc1a2e46 Mon Sep 17 00:00:00 2001 From: Alexander Weigl Date: Mon, 6 Jul 2026 05:54:44 +0200 Subject: [PATCH 1/4] add stuff --- .editorconfig | 6 + .github/workflows/code_quality.yml | 95 ++++++++- .github/workflows/codeql.yml | 82 ++++++++ buildSrc/build.gradle.kts | 2 + ...ldlogic.java-common-conventions.gradle.kts | 51 ++++- .../main/kotlin/publish-convention.gradle.kts | 83 ++++++++ .../main/kotlin/standard-kotlin.gradle.kts | 45 +++++ gradle/libs.versions.toml | 2 + scripts/cover2cover.py | 186 ++++++++++++++++++ 9 files changed, 548 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/codeql.yml create mode 100644 buildSrc/src/main/kotlin/publish-convention.gradle.kts create mode 100644 buildSrc/src/main/kotlin/standard-kotlin.gradle.kts create mode 100644 scripts/cover2cover.py diff --git a/.editorconfig b/.editorconfig index 0d8add46c63..37d5948ca03 100644 --- a/.editorconfig +++ b/.editorconfig @@ -16,6 +16,12 @@ tab_width = 4 # ij_visual_guides = none # ij_wrap_on_typing = false + +[{*.yml,*.yaml}] +indent_size = 2 +tab_width = 2 +insert_final_newline = true + [*.dcl] # ij_declarative_keep_indents_on_empty_lines = false diff --git a/.github/workflows/code_quality.yml b/.github/workflows/code_quality.yml index e0d199dd782..c6865856cf4 100644 --- a/.github/workflows/code_quality.yml +++ b/.github/workflows/code_quality.yml @@ -11,6 +11,16 @@ on: env: JAVA_VERSION: 21 +# If a build is running in the current branch, and the branch is updated, we cancel the previous build and start +# a new one with the updated changes. +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + code-quality: write + jobs: formatting: @@ -26,6 +36,89 @@ jobs: - name: Build with Gradle run: ./gradlew --parallel --continue spotlessCheck + test_on_branch: + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest ] #, macos-latest, windows-latest ] + jdk: [ 21 ] + + env: + OS: ubuntu-latest + JDK: 21 + + runs-on: ubuntu-latest + + steps: + - name: Checkout latest code + uses: actions/checkout@v7.0.0 + with: + fetch-depth: "0" + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + ## Setup the specified version of Java (includes maven/gradle). + - &setupjava + name: Set up JDK ${{ matrix.jdk }} + uses: actions/setup-java@v5 + with: + distribution: 'zulu' # v2 requires explicitly stating the distribution - `zulu` and `adopt` supported at time of writing + java-version: ${{ matrix.jdk }} # Use matrix to select which JDK level to use + java-package: jdk # optional (jdk or jre) - defaults to jdk + cache: 'gradle' + + - name: Setup SMT solvers + uses: keyproject/setup-smt@v0 + + - name: z3 version + run: z3 --version + + - name: cvc5 version + run: cvc5 --version + + - &checkjava + name: Echo exact java version being used + run: java -version + + - name: Test with Gradle and generate coverage + run: ./gradlew --continue --parallel test aggregateCoverageReport aggregateTestReport + + - run: python scripts/cover2cover.py build/reports/jacoco/aggregateCoverageReport/aggregateCoverageReport.xml **/src/main/java > cov-report.xml + if: success() || failure() + + - name: Upload coverage report + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository + uses: actions/upload-code-coverage@v1 + with: + file: cov-report.xml + language: Java + label: code-coverage/jacoco + + - name: Upload Test Report + if: success() || failure() + uses: actions/upload-artifact@v7 + with: + name: aggregated-results + path: build/reports/tests/test/aggregated-results + compression-level: '9' + retention-days: 7 + + - name: Upload Coverage Report + if: success() || failure() + uses: actions/upload-artifact@v7 + with: + name: aggregated-coverage + path: build/reports/jacoco/aggregateCoverageReport/html/ + compression-level: '9' + retention-days: 7 + + - name: Test reporting + uses: dorny/test-reporter@v3 + if: success() || failure() + with: + name: Test Report + path: "*/build/test-results/test/*.xml" + reporter: java-junit + unit-tests: strategy: fail-fast: false @@ -68,4 +161,4 @@ jobs: path: | **/build/test-results/*/*.xml **/build/reports/ - !**/jacocoTestReport.xml \ No newline at end of file + !**/jacocoTestReport.xml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000000..71f25ad1615 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,82 @@ +name: "CodeQL Advanced" + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + schedule: + - cron: '43 14 * * 4' + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners (GitHub.com only) + # Consider using larger runners or machines with greater resources for possible analysis time improvements. + runs-on: 'ubuntu-latest' + permissions: + # required for all workflows + security-events: write + + # required to fetch internal or private CodeQL packs + packages: read + + # only required for workflows in private repositories + actions: read + contents: read + + strategy: + fail-fast: false + matrix: + include: + - language: actions + build-mode: none + - language: java-kotlin + build-mode: autobuild + # CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift' + # Use `c-cpp` to analyze code written in C, C++ or both + # Use 'java-kotlin' to analyze code written in Java, Kotlin or both + # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both + # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, + # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. + # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how + # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages + steps: + - name: Checkout repository + uses: actions/checkout@v7 + + - name: Set up JDK 21 + if: matrix.language == 'java-kotlin' + uses: actions/setup-java@v5 + with: + distribution: 'zulu' + java-version: 21 + java-package: jdk + cache: 'gradle' + + - name: Echo exact java version being used + run: java -version + + - run: ./gradlew --parallel testClasses + if: matrix.language == 'java-kotlin' + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v4 + with: + category: "/language:${{matrix.language}}" diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index e1e5faa0c98..8010cdfe304 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -10,4 +10,6 @@ dependencies { implementation(libs.kotlin.gradle.plugin) implementation(libs.spotless) implementation(libs.dokka) + implementation(libs.jacoco.cobertura) + implementation(libs.vanniktech.maven) } \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/buildlogic.java-common-conventions.gradle.kts b/buildSrc/src/main/kotlin/buildlogic.java-common-conventions.gradle.kts index 7d44a805951..41fdeee2721 100644 --- a/buildSrc/src/main/kotlin/buildlogic.java-common-conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/buildlogic.java-common-conventions.gradle.kts @@ -5,6 +5,11 @@ plugins { id("com.diffplug.spotless") id("org.jetbrains.kotlin.jvm") id("org.jetbrains.dokka") + + id("test-report-aggregation") + id("jacoco-report-aggregation") + `jvm-test-suite` + jacoco } repositories { @@ -24,6 +29,32 @@ java { } } +testing { + suites { + getByName("test") { + useJUnitJupiter() + targets { + all { + testTask.configure { + // maxHeapSize = "8g" + // jvmArgs("-Xmx2g") + // finalizedBy(tasks.jacocoTestReport) + } + } + } + } + } +} + +tasks.withType { + options.encoding = "UTF-8" + options.compilerArgs.add("-parameters") + + // See: https://docs.oracle.com/en/java/javase/12/tools/javac.html + options.compilerArgs.add("-Xlint:all") + // "-Werror", // Terminates compilation when warnings occur. +} + tasks.named("test") { useJUnitPlatform() } @@ -62,7 +93,7 @@ dokka { skipEmptyPackages.set(true) skipDeprecated.set(false) suppressGeneratedFiles.set(true) - //samples.from("samples/Basic.kt", "samples/Advanced.kt") + // samples.from("samples/Basic.kt", "samples/Advanced.kt") sourceLink { remoteUrl("https://github.com/keyproject/key-rpc/tree/main/") @@ -97,7 +128,7 @@ dokka { } dokkaPublications.html { - //moduleName.set() + // moduleName.set() val exists = layout.projectDirectory.file("README.md").asFile if (exists.exists()) { includes.from("README.md") @@ -119,4 +150,18 @@ val dokkaJavadocJar by tasks.registering(Jar::class) { from(tasks.dokkaGeneratePublicationJavadoc.flatMap { it.outputDirectory }) archiveClassifier.set("javadoc") } -*/ \ No newline at end of file +*/ + +jacoco { + toolVersion = "0.8.15" +} + +tasks.jacocoTestReport { + dependsOn(tasks.test) + + reports { + xml.required.set(true) + html.required.set(true) + csv.required.set(false) + } +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/publish-convention.gradle.kts b/buildSrc/src/main/kotlin/publish-convention.gradle.kts new file mode 100644 index 00000000000..4225cb427f3 --- /dev/null +++ b/buildSrc/src/main/kotlin/publish-convention.gradle.kts @@ -0,0 +1,83 @@ +import com.vanniktech.maven.publish.JavaLibrary +import com.vanniktech.maven.publish.JavadocJar +import com.vanniktech.maven.publish.SourcesJar + +plugins { + id("com.vanniktech.maven.publish") + signing +} + + +publishing { + repositories { + maven { + name = "LOCAL" + url = uri("$rootDir/local") + } + maven { + // deployment to git.key-project.org/key-public/key + name = "KEYLAB" + url = uri("https://git.key-project.org/api/v4/projects/35/packages/maven") + credentials(HttpHeaderCredentials::class) { + val userToken = envOrPropertyValue("GITLAB_USER_TOKEN") + val deployToken = envOrPropertyValue("GITLAB_DEPLOY_TOKEN") + val ciToken = envOrPropertyValue("GITLAB_CIJOB_TOKEN") + + if (userToken != "") { + name = "Private-Token" + value = userToken + } else if (deployToken != "") { + name = "Deploy-Token" + value = deployToken + } else { + name = "Job-Token" + value = ciToken + } + } + authentication { + create("basic", HttpHeaderAuthentication::class) + } + } + } +} + +mavenPublishing { + publishToMavenCentral() + //signAllPublications() + + configure( + JavaLibrary( + javadocJar = JavadocJar.Javadoc(), + sourcesJar = SourcesJar.Sources(), + ), + ) + + pom { + licenses { + license { + name = "The GNU General Public License 2" + url = "http://www.apache.org/licenses/LICENSE-2.0.txt" + } + } + developers { + } + scm { + connection = "scm:git:git://example.com/my-library.git" + developerConnection = "scm:git:ssh://example.com/my-library.git" + url = "http://example.com/my-library/" + } + } +} + +fun envOrPropertyValue(key: String): String = + if (key in System.getenv()) { + System.getenv(key) + } else { + project.properties[key]?.toString() ?: "" + } + +val emptyJavadocJar = tasks.findByName("plainJavadocJar")!! +val meta = tasks.findByName("generateMetadataFileForMavenPublication")!! +meta.dependsOn(emptyJavadocJar) + +signing { useGpgCmd() } \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/standard-kotlin.gradle.kts b/buildSrc/src/main/kotlin/standard-kotlin.gradle.kts new file mode 100644 index 00000000000..e79080fc2d4 --- /dev/null +++ b/buildSrc/src/main/kotlin/standard-kotlin.gradle.kts @@ -0,0 +1,45 @@ +import com.diffplug.gradle.spotless.SpotlessExtension + +plugins { + kotlin("jvm") + id("buildlogic.java-library-conventions") +} + +val libs = extensions.getByType().named("libs") + +dependencies { + api(project(":jmlparser-core")) + testImplementation(libs.findBundle("testing").get()) + testRuntimeOnly(libs.findBundle("testing-runtime").get()) +} + +kotlin { + jvmToolchain(21) +} + +tasks.named("test") { + useJUnitPlatform() + + maxHeapSize = "1G" + + testLogging { + events("passed") + } +} + +configure { + kotlin { + target("src/**/*.kt") + ktlint().setEditorConfigPath("$rootDir/.editorconfig") + trimTrailingWhitespace() + endWithNewline() + licenseHeaderFile("$rootDir/gradle/header", "(package|import|//)") + } + + kotlinGradle { + target("*.gradle.kts", "buildSrc/**/*.gradle.kts") + ktlint() + trimTrailingWhitespace() + endWithNewline() + } +} \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a90b91ce496..3825ef30c72 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -19,6 +19,7 @@ dokka = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "dok dokka-mermaid = { module = "com.glureau:html-mermaid-dokka-plugin", version = "0.6.0" } key-core = { module = "org.key-project:key.core", version.ref = "key" } key-ui = { module = "org.key-project:key.ui", version.ref = "key" } +jacoco-cobertura = { module = "name.remal.jacoco-to-cobertura:name.remal.jacoco-to-cobertura.gradle.plugin", version = "2.0.4" } lsp4j-jsonrpc = { module = "org.eclipse.lsp4j:org.eclipse.lsp4j.jsonrpc", version.ref = "lsp4j" } lsp4j-websocket-jakarta = { module = "org.eclipse.lsp4j:org.eclipse.lsp4j.websocket.jakarta", version.ref = "lsp4j" } @@ -28,3 +29,4 @@ guava = { module = "com.google.guava:guava", version.ref = "guava" } therapi-runtime-javadoc-scribe = { module = "com.github.therapi:therapi-runtime-javadoc-scribe", version.ref = "therapi" } therapi-runtime-javadoc = { module = "com.github.therapi:therapi-runtime-javadoc", version.ref = "therapi" } clickt = { module = "com.github.ajalt.clikt:clikt", version = "5.1.0" } +vanniktech-maven = { module = "com.vanniktech.maven.publish:com.vanniktech.maven.publish.gradle.plugin", version = "0.37.0" } diff --git a/scripts/cover2cover.py b/scripts/cover2cover.py new file mode 100644 index 00000000000..e6597613275 --- /dev/null +++ b/scripts/cover2cover.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python +import os.path +import sys +import time +import xml.etree.ElementTree as ET + + +def find_lines(j_package, filename): # noqa + """Return all elements for a given source file in a package.""" + lines = list() + sources = j_package.findall("sourcefile") + for source in sources: + if source.attrib.get("name") == os.path.basename(filename): + lines = lines + source.findall("line") + return lines + + +def line_is_after(jm, start_line): + return int(jm.attrib.get('line', 0)) > start_line + + +# noinspection SpellCheckingInspection +def method_lines(jmethod, jmethods, jlines): + """Filter the lines from the given set of jlines that apply to the given jmethod.""" + start_line = int(jmethod.attrib.get('line', 0)) + larger = list(int(jm.attrib.get('line', 0)) for jm in jmethods if line_is_after(jm, start_line)) + end_line = min(larger) if len(larger) else 99999999 + + for jline in jlines: + if start_line <= int(jline.attrib['nr']) < end_line: + yield jline + + +# noinspection SpellCheckingInspection +def convert_lines(j_lines, into): + """Convert the JaCoCo elements into Cobertura elements, add them under the given element.""" + c_lines = ET.SubElement(into, 'lines') + for jline in j_lines: + mb = int(jline.attrib['mb']) + cb = int(jline.attrib['cb']) + ci = int(jline.attrib['ci']) + + cline = ET.SubElement(c_lines, 'line') + cline.set('number', jline.attrib['nr']) + cline.set('hits', '1' if ci > 0 else '0') # Probably not true but no way to know from JaCoCo XML file + + if mb + cb > 0: + percentage = str(int(100 * (float(cb) / (float(cb) + float(mb))))) + '%' + cline.set('branch', 'true') + cline.set('condition-coverage', percentage + ' (' + str(cb) + '/' + str(cb + mb) + ')') + + cond = ET.SubElement(ET.SubElement(cline, 'conditions'), 'condition') + cond.set('number', '0') + cond.set('type', 'jump') + cond.set('coverage', percentage) + else: + cline.set('branch', 'false') + + +def path_to_filepath(path_to_class, source_filename): + return path_to_class[0: path_to_class.rfind("/") + 1] + source_filename + + +def add_counters(source, target): + target.set('line-rate', counter(source, 'LINE')) + target.set('branch-rate', counter(source, 'BRANCH')) + target.set('complexity', counter(source, 'COMPLEXITY', sum)) + + +def fraction(covered, missed): + if not covered: + return 0.0 + return covered / (covered + missed) + + +# noinspection PyShadowingBuiltins +def sum(covered, missed): + return covered + missed + + +# noinspection PyShadowingBuiltins +def counter(source, type, operation=fraction): + cs = source.findall('counter') + c = next((ct for ct in cs if ct.attrib.get('type') == type), None) + + if c is not None: + covered = float(c.attrib['covered']) + missed = float(c.attrib['missed']) + + return str(operation(covered, missed)) + else: + return '0.0' + + +def convert_method(j_method, j_lines): + c_method = ET.Element('method') + c_method.set('name', j_method.attrib['name']) + c_method.set('signature', j_method.attrib['desc']) + + add_counters(j_method, c_method) + convert_lines(j_lines, c_method) + + return c_method + + +def convert_class(j_class, j_package): + c_class = ET.Element('class') + c_class.set('name', j_class.attrib['name'].replace('/', '.')) + # sourcefilename is optional, required for multi-module maven/gradle builds + if 'sourcefilename' in j_class.attrib: + c_class.set('filename', path_to_filepath(j_class.attrib['name'], j_class.attrib['sourcefilename'])) + else: + c_class.set('filename', path_to_filepath(j_class.attrib['name'], j_class.attrib['name'])) + + all_j_lines = list(find_lines(j_package, c_class.attrib['filename'])) + + c_methods = ET.SubElement(c_class, 'methods') + all_j_methods = list(j_class.findall('method')) + for j_method in all_j_methods: + j_method_lines = method_lines(j_method, all_j_methods, all_j_lines) + c_methods.append(convert_method(j_method, j_method_lines)) + + add_counters(j_class, c_class) + convert_lines(all_j_lines, c_class) + + return c_class + + +def convert_package(j_package): + c_package = ET.Element('package') + c_package.attrib['name'] = j_package.attrib['name'].replace('/', '.') + + c_classes = ET.SubElement(c_package, 'classes') + for j_class in j_package.findall('class'): + c_classes.append(convert_class(j_class, j_package)) + + add_counters(j_package, c_package) + + return c_package + + +# noinspection PyShadowingBuiltins +def convert_root(source, target, source_roots): # noqa + try: + target.set('timestamp', str(int(source.find('sessioninfo').attrib['start']) / 1000)) + except AttributeError as e: + target.set('timestamp', str(int(time.time() / 1000))) + sources = ET.SubElement(target, 'sources') + for s in source_roots: + ET.SubElement(sources, 'source').text = s + + packages = ET.SubElement(target, 'packages') + + for group in source.findall('group'): + for package in group.findall('package'): + packages.append(convert_package(package)) + + for package in source.findall('package'): + packages.append(convert_package(package)) + + add_counters(source, target) + + +def jacoco2cobertura(filename, source_roots): # noqa + if filename == '-': + root = ET.fromstring(sys.stdin.read()) + else: + tree = ET.parse(filename) + root = tree.getroot() + + into = ET.Element('coverage') + convert_root(root, into, source_roots) + print('') + print(ET.tostring(into, encoding='unicode')) + + +if __name__ == '__main__': + if len(sys.argv) < 2: + print("Usage: cover2cover.py FILENAME [SOURCE_ROOTS]") + sys.exit(1) + + filename = sys.argv[1] + source_roots = sys.argv[2:] if 2 < len(sys.argv) else '.' + + jacoco2cobertura(filename, source_roots) + From 6eb0ff698ba807ac086cc3d7da63005781f16fc3 Mon Sep 17 00:00:00 2001 From: Alexander Weigl Date: Mon, 6 Jul 2026 05:55:49 +0200 Subject: [PATCH 2/4] aggregated reports --- build.gradle.kts | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index dc1b3d58774..0d4f24805bb 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,14 +1,34 @@ import org.jetbrains.dokka.gradle.engine.parameters.VisibilityModifier -plugins { id("org.jetbrains.dokka") } +plugins { + id("org.jetbrains.dokka") + jacoco + id("jacoco-report-aggregation") + id("test-report-aggregation") +} repositories { mavenCentral() } + dependencies { - dokka(project(":keyext.api")) - dokka(project(":keyext.api.doc")) - dokka(project(":keyext.api.app")) - dokka(project(":keyext.api.client")) + subprojects.forEach { + if(it.name != "tools") { + dokka(it) + jacocoAggregation(it) + testReportAggregation(it) + } + } +} + +reporting { + reports { + create("aggregateTestReport") { + testSuiteName = "test" + } + create("aggregateCoverageReport") { + testSuiteName = "test" + } + } } dokka { @@ -18,4 +38,8 @@ dokka { suppressObviousFunctions.set(true) offlineMode.set(false) } +} + +jacoco { + toolVersion = "0.8.15" } \ No newline at end of file From 8b3e9895628b07b3c4a7c84cbefdbebbe6bb7005 Mon Sep 17 00:00:00 2001 From: Alexander Weigl Date: Mon, 6 Jul 2026 06:03:13 +0200 Subject: [PATCH 3/4] split --- .github/workflows/code_quality.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/code_quality.yml b/.github/workflows/code_quality.yml index c6865856cf4..b7338f6c2d9 100644 --- a/.github/workflows/code_quality.yml +++ b/.github/workflows/code_quality.yml @@ -80,7 +80,9 @@ jobs: run: java -version - name: Test with Gradle and generate coverage - run: ./gradlew --continue --parallel test aggregateCoverageReport aggregateTestReport + run: ./gradlew --continue --parallel test + + - run: ./gradlew --continue --parallel aggregateCoverageReport aggregateTestReport - run: python scripts/cover2cover.py build/reports/jacoco/aggregateCoverageReport/aggregateCoverageReport.xml **/src/main/java > cov-report.xml if: success() || failure() From f9e8b80e2e2b8015994a373dee3e9531e64f880d Mon Sep 17 00:00:00 2001 From: Alexander Weigl Date: Mon, 6 Jul 2026 06:07:23 +0200 Subject: [PATCH 4/4] split --- .github/workflows/code_quality.yml | 6 ++---- build.gradle.kts | 5 ++++- .../java/edu/kit/keyext/client/RPCLayerTest.java | 14 +++----------- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/.github/workflows/code_quality.yml b/.github/workflows/code_quality.yml index b7338f6c2d9..5cd187c86c4 100644 --- a/.github/workflows/code_quality.yml +++ b/.github/workflows/code_quality.yml @@ -80,11 +80,9 @@ jobs: run: java -version - name: Test with Gradle and generate coverage - run: ./gradlew --continue --parallel test + run: ./gradlew --continue --parallel test aggregateCoverageReport aggregateTestReport - - run: ./gradlew --continue --parallel aggregateCoverageReport aggregateTestReport - - - run: python scripts/cover2cover.py build/reports/jacoco/aggregateCoverageReport/aggregateCoverageReport.xml **/src/main/java > cov-report.xml + - run: python scripts/cover2cover.py build/reports/jacoco/aggregateCoverageReport/aggregateCoverageReport.xml **/src/main/{java,kotlin} > cov-report.xml if: success() || failure() - name: Upload coverage report diff --git a/build.gradle.kts b/build.gradle.kts index 0d4f24805bb..8f1351534bd 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -7,7 +7,10 @@ plugins { id("test-report-aggregation") } -repositories { mavenCentral() } +repositories { + mavenCentral() + maven { url = uri("https://central.sonatype.com/repository/maven-snapshots/") } +} dependencies { diff --git a/keyext.api.client/src/test/java/edu/kit/keyext/client/RPCLayerTest.java b/keyext.api.client/src/test/java/edu/kit/keyext/client/RPCLayerTest.java index f70f21fdd2c..905a6ed7f1a 100644 --- a/keyext.api.client/src/test/java/edu/kit/keyext/client/RPCLayerTest.java +++ b/keyext.api.client/src/test/java/edu/kit/keyext/client/RPCLayerTest.java @@ -116,14 +116,6 @@ private static JsonObject take(ArrayBlockingQueue queue) return v; } - private static void awaitUntil(java.util.function.BooleanSupplier condition) - throws InterruptedException { - long deadline = System.currentTimeMillis() + 5000; - while (!condition.getAsBoolean() && System.currentTimeMillis() < deadline) { - Thread.sleep(5); - } - } - /** A {@link Reader} that hands out at most one character per read call. */ private static final class OneCharAtATimeReader extends Reader { private final String data; @@ -157,7 +149,7 @@ public void close() {} */ @Test @Timeout(value = 10, unit = TimeUnit.SECONDS) - void handlerSurvivesUnknownResponseId() throws Exception { + void handlerSurvivesUnknownResponseId() { var in = new FeedableReader(); var layer = new RPCLayer(in, new StringWriter()); layer.start(); @@ -235,7 +227,7 @@ synchronized void feed(String s) { @Override public synchronized int read(char[] cbuf, int off, int len) throws IOException { - while (buffer.length() == 0 && !closed) { + while (buffer.isEmpty() && !closed) { try { wait(); } catch (InterruptedException e) { @@ -243,7 +235,7 @@ public synchronized int read(char[] cbuf, int off, int len) throws IOException { throw new IOException(e); } } - if (buffer.length() == 0 && closed) { + if (buffer.isEmpty() && closed) { return -1; } int n = Math.min(len, buffer.length());