diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index e4a26a8..92f528b 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -22,24 +22,25 @@ jobs:
           java-version: 8
           distribution: 'temurin'
           cache: 'maven'
-      - run: cd tests && mvn clean test --batch-mode -Dmaven.test.failure.ignore=true
+      - run: cd integration-tests/maven && mvn clean verify --batch-mode -Dmaven.test.failure.ignore=true
       - uses: ./
         if: github.ref != 'refs/heads/master'
         with:
           check_name: Example Surefire Test Report
+          report_paths: '**/surefire-reports/*.xml, **/failsafe-reports/*.xml'
       - uses: cclauss/GitHub-Action-for-pytest@0.5.0
         with:
-          args: pytest  --junit-xml=python/report.xml python/ || exit 0
+          args: pytest integration-tests/python/ --junit-xml=integration-tests/python/report.xml || exit 0
       - uses: ./
         if: github.ref != 'refs/heads/master'
         with:
           check_name: Example Pytest Report
-          report_paths: python/report.xml
-      - uses: actions/setup-go@v4
+          report_paths: integration-tests/python/report.xml
+      - uses: actions/setup-go@v5
         with:
-          go-version: 1.18.x
+          go-version: 1.21.x
       - run: |
-          cd go && 
+          cd integration-tests/go && 
             go install github.com/jstemmer/go-junit-report/v2@latest &&
             go test -v 2>&1 ./... |
             go-junit-report -out report.xml
@@ -47,9 +48,9 @@ jobs:
         if: github.ref != 'refs/heads/master'
         with:
           check_name: Example Go Report
-          report_paths: go/report.xml
+          report_paths: integration-tests/go/report.xml
           file_name_in_stack_trace: true
-      - uses: actions/setup-node@v3
+      - uses: actions/setup-node@v4
         with:
           node-version: 20
           cache: npm
diff --git a/.github/workflows/copilot-check.yml b/.github/workflows/copilot-check.yml
new file mode 100644
index 0000000..c9d6f30
--- /dev/null
+++ b/.github/workflows/copilot-check.yml
@@ -0,0 +1,11 @@
+on:
+  pull_request
+
+jobs:
+  check-contributors:
+    name: Check contributors
+    uses: scacap/infra.gh-actions/.github/workflows/copilot-contributor-check.yml@v1
+    secrets: inherit
+    with:
+      repository: ${{ github.repository }}
+      pull_request_number: ${{ github.event.pull_request.number }}
diff --git a/action.test.fixtures.js b/action.test.fixtures.js
index c93fd2a..c37f92c 100644
--- a/action.test.fixtures.js
+++ b/action.test.fixtures.js
@@ -9,7 +9,7 @@ const finishedWithFailures = {
         annotations: [
             {
                 path:
-                    'tests/email/src/test/java/action/surefire/report/email/EmailAddressTest.java',
+                    'integration-tests/maven/email/src/test/java/action/surefire/report/email/EmailAddressTest.java',
                 start_line: 39,
                 end_line: 39,
                 start_column: 0,
@@ -22,7 +22,7 @@ const finishedWithFailures = {
             },
             {
                 path:
-                    'tests/email/src/test/java/action/surefire/report/email/EmailAddressTest.java',
+                    'integration-tests/maven/email/src/test/java/action/surefire/report/email/EmailAddressTest.java',
                 start_line: 49,
                 end_line: 49,
                 start_column: 0,
@@ -35,7 +35,7 @@ const finishedWithFailures = {
             },
             {
                 path:
-                    'tests/email/src/test/java/action/surefire/report/email/EmailAddressTest.java',
+                    'integration-tests/maven/email/src/test/java/action/surefire/report/email/EmailAddressTest.java',
                 start_line: 57,
                 end_line: 57,
                 start_column: 0,
@@ -48,7 +48,7 @@ const finishedWithFailures = {
             },
             {
                 path:
-                    'tests/email/src/test/java/action/surefire/report/email/EmailAddressTest.java',
+                    'integration-tests/maven/email/src/test/java/action/surefire/report/email/EmailAddressTest.java',
                 start_line: 18,
                 end_line: 18,
                 start_column: 0,
@@ -61,7 +61,7 @@ const finishedWithFailures = {
             },
             {
                 path:
-                    'tests/email/src/test/java/action/surefire/report/email/EmailAddressTest.java',
+                    'integration-tests/maven/email/src/test/java/action/surefire/report/email/EmailAddressTest.java',
                 start_line: 32,
                 end_line: 32,
                 start_column: 0,
@@ -74,7 +74,7 @@ const finishedWithFailures = {
             },
             {
                 path:
-                    'tests/email/src/test/java/action/surefire/report/email/EmailAddressTest.java',
+                    'integration-tests/maven/email/src/test/java/action/surefire/report/email/EmailAddressTest.java',
                 start_line: 25,
                 end_line: 25,
                 start_column: 0,
@@ -88,7 +88,7 @@ const finishedWithFailures = {
             },
             {
                 path:
-                    'tests/email/src/test/java/action/surefire/report/email/EmailAddressTest.java',
+                    'integration-tests/maven/email/src/test/java/action/surefire/report/email/EmailAddressTest.java',
                 start_line: 66,
                 end_line: 66,
                 start_column: 0,
@@ -101,7 +101,7 @@ const finishedWithFailures = {
             },
             {
                 path:
-                    'tests/evil_twins/src/test/java/action/surefire/report/twin/second/TwinTest.java',
+                    'integration-tests/maven/evil_twins/src/test/java/action/surefire/report/twin/second/TwinTest.java',
                 start_line: 13,
                 end_line: 13,
                 start_column: 0,
@@ -113,7 +113,7 @@ const finishedWithFailures = {
                     "java.lang.AssertionError: \n\nExpected: \"Good Twin\"\n     but: was \"Evil Twin\"\n\tat action.surefire.report.twin.second.TwinTest.should_always_fail(TwinTest.java:13)"
             },
             {
-                path: 'tests/utils/src/test/java/action/surefire/report/calc/CalcUtilsTest.kt',
+                path: 'integration-tests/maven/utils/src/test/java/action/surefire/report/calc/CalcUtilsTest.kt',
                 start_line: 27,
                 end_line: 27,
                 start_column: 0,
@@ -126,7 +126,7 @@ const finishedWithFailures = {
                     'java.lang.AssertionError: unexpected exception type thrown; expected:<java.lang.IllegalStateException> but was:<java.lang.IllegalArgumentException>\n\tat action.surefire.report.calc.CalcUtilsTest.test error handling(CalcUtilsTest.kt:27)\nCaused by: java.lang.IllegalArgumentException: Amount must have max 2 non-zero decimal places\n\tat action.surefire.report.calc.CalcUtilsTest.scale(CalcUtilsTest.kt:31)\n\tat action.surefire.report.calc.CalcUtilsTest.access$scale(CalcUtilsTest.kt:9)\n\tat action.surefire.report.calc.CalcUtilsTest.test error handling(CalcUtilsTest.kt:27)'
             },
             {
-                path: 'tests/utils/src/test/java/action/surefire/report/calc/CalcUtilsTest.kt',
+                path: 'integration-tests/maven/utils/src/test/java/action/surefire/report/calc/CalcUtilsTest.kt',
                 start_line: 15,
                 end_line: 15,
                 start_column: 0,
@@ -138,7 +138,7 @@ const finishedWithFailures = {
                     'java.lang.AssertionError: \n\nExpected: <100.10>\n     but: was <100.11>\n\tat action.surefire.report.calc.CalcUtilsTest.test scale(CalcUtilsTest.kt:15)'
             },
             {
-                path: 'tests/utils/src/test/java/action/surefire/report/calc/StringUtilsTest.java',
+                path: 'integration-tests/maven/utils/src/test/java/action/surefire/report/calc/StringUtilsTest.java',
                 start_line: 27,
                 end_line: 27,
                 start_column: 0,
@@ -151,7 +151,7 @@ const finishedWithFailures = {
                     'java.lang.AssertionError: \n\nExpected: (an instance of java.lang.IllegalArgumentException and exception with message a string containing "This is unexpected")\n     but: exception with message a string containing "This is unexpected" message was "Input=\'\' didn\'t match condition."\nStacktrace was: java.lang.IllegalArgumentException: Input=\'\' didn\'t match condition.\n\tat action.surefire.report.calc.StringUtils.requireNotBlank(StringUtils.java:25)\n\tat action.surefire.report.calc.StringUtils.requireNotBlank(StringUtils.java:18)\n\tat action.surefire.report.calc.StringUtilsTest.require_fail(StringUtilsTest.java:27)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n\tat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n\tat java.lang.reflect.Method.invoke(Method.java:498)\n\tat org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)\n\tat org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)\n\tat org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)\n\tat org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)\n\tat org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:258)\n\tat org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)\n\tat org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)\n\tat org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)\n\tat org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)\n\tat org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)\n\tat org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)\n\tat org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)\n\tat org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)\n\tat org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)\n\tat org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)\n\tat org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)\n\tat org.junit.runners.ParentRunner.run(ParentRunner.java:413)\n\tat org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:365)\n\tat org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:273)\n\tat org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:238)\n\tat org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:159)\n\tat org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:384)\n\tat org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:345)\n\tat org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:126)\n\tat org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:418)'
             },
             {
-                path: 'tests/utils/src/test/java/action/surefire/report/calc/StringUtilsTest.java',
+                path: 'integration-tests/maven/utils/src/test/java/action/surefire/report/calc/StringUtilsTest.java',
                 start_line: 20,
                 end_line: 20,
                 start_column: 0,
diff --git a/dist/index.js b/dist/index.js
index 9605eaa..e35a431 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -36505,24 +36505,24 @@ const resolveFileAndLine = (file, classname, output, isFilenameInOutput) => {
     let filenameWithPackage;
     if (isFilenameInOutput) {
         filename = output.split(':')[0].trim();
-        filenameWithPackage = filename
+        filenameWithPackage = filename;
     } else {
         filename = file ? file : classname.split('.').slice(-1)[0].split('(')[0];
-        filenameWithPackage = classname.replace(/\./g, "/");
+        filenameWithPackage = classname.replace(/\./g, '/');
     }
     const matches = output.match(new RegExp(`${filename}.*?:\\d+`, 'g'));
-    if (!matches) return { filename: filename, filenameWithPackage: filenameWithPackage, line: 1 };
+    if (!matches) return {filename: filename, filenameWithPackage: filenameWithPackage, line: 1};
 
     const [lastItem] = matches.slice(-1);
     const [, line] = lastItem.split(':');
     core.debug(`Resolved file ${filenameWithPackage} with name ${filename} and line ${line}`);
 
-    return { filename, filenameWithPackage, line: parseInt(line) };
+    return {filename, filenameWithPackage, line: parseInt(line)};
 };
 
 const resolvePath = async filenameWithPackage => {
     core.debug(`Resolving path for ${filenameWithPackage}`);
-    const globber = await glob.create([`**/${filenameWithPackage}.*`, `**/${filenameWithPackage}`].join('\n'), { followSymbolicLinks: false });
+    const globber = await glob.create([`**/${filenameWithPackage}.*`, `**/${filenameWithPackage}`].join('\n'), {followSymbolicLinks: false});
     const results = await globber.glob();
     core.debug(`Matched files: ${results}`);
     const searchPath = globber.getSearchPaths()[0];
@@ -36545,6 +36545,19 @@ const resolvePath = async filenameWithPackage => {
     return canonicalPath;
 };
 
+function getTestsuites(report) {
+    if (report.testsuite) {
+        return [report.testsuite];
+    }
+    if (!report.testsuites || !report.testsuites.testsuite) {
+        return [];
+    }
+    if (Array.isArray(report.testsuites.testsuite)) {
+        return report.testsuites.testsuite;
+    }
+    return [report.testsuites.testsuite];
+}
+
 async function parseFile(file, isFilenameInStackTrace) {
     core.debug(`Parsing file ${file}`);
     let count = 0;
@@ -36553,12 +36566,11 @@ async function parseFile(file, isFilenameInStackTrace) {
 
     const data = await fs.promises.readFile(file);
 
-    const report = JSON.parse(parser.xml2json(data, { compact: true }));
-    const testsuites = report.testsuite
-        ? [report.testsuite]
-        : Array.isArray(report.testsuites.testsuite)
-            ? report.testsuites.testsuite
-            : [report.testsuites.testsuite];
+    const report = JSON.parse(parser.xml2json(data, {compact: true}));
+    core.debug(`parsed report: ${JSON.stringify(report)}`);
+
+    const testsuites = getTestsuites(report);
+    core.debug(`test suites: ${JSON.stringify(testsuites)}`);
 
     for (const testsuite of testsuites) {
         const testcases = Array.isArray(testsuite.testcase)
@@ -36595,7 +36607,7 @@ async function parseFile(file, isFilenameInStackTrace) {
                     testcase._attributes.name
                 ).trim();
 
-                const { filename, filenameWithPackage, line } = resolveFileAndLine(
+                const {filename, filenameWithPackage, line} = resolveFileAndLine(
                     testcase._attributes.file,
                     testcase._attributes.classname,
                     stackTrace,
@@ -36620,22 +36632,22 @@ async function parseFile(file, isFilenameInStackTrace) {
             }
         }
     }
-    return { count, skipped, annotations };
+    return {count, skipped, annotations};
 }
 
 const parseTestReports = async (reportPaths, isFilenameInStackTrace) => {
-    const globber = await glob.create(reportPaths, { followSymbolicLinks: false });
+    const globber = await glob.create(reportPaths, {followSymbolicLinks: false});
     let annotations = [];
     let count = 0;
     let skipped = 0;
     for await (const file of globber.globGenerator()) {
-        const { count: c, skipped: s, annotations: a } = await parseFile(file, isFilenameInStackTrace);
+        const {count: c, skipped: s, annotations: a} = await parseFile(file, isFilenameInStackTrace);
         if (c === 0) continue;
         count += c;
         skipped += s;
         annotations = annotations.concat(a);
     }
-    return { count, skipped, annotations };
+    return {count, skipped, annotations};
 };
 
 module.exports = { resolveFileAndLine, resolvePath, parseFile, parseTestReports };
diff --git a/custom_reports/TEST-pro.taskana.common.api.ListUtilTest-H2.xml b/integration-tests/custom_reports/TEST-pro.taskana.common.api.ListUtilTest-H2.xml
similarity index 100%
rename from custom_reports/TEST-pro.taskana.common.api.ListUtilTest-H2.xml
rename to integration-tests/custom_reports/TEST-pro.taskana.common.api.ListUtilTest-H2.xml
diff --git a/custom_reports/TEST-test.MyIntegrationTestSuite.xml b/integration-tests/custom_reports/TEST-test.MyIntegrationTestSuite.xml
similarity index 100%
rename from custom_reports/TEST-test.MyIntegrationTestSuite.xml
rename to integration-tests/custom_reports/TEST-test.MyIntegrationTestSuite.xml
diff --git a/go/go.mod b/integration-tests/go/go.mod
similarity index 100%
rename from go/go.mod
rename to integration-tests/go/go.mod
diff --git a/go/go.sum b/integration-tests/go/go.sum
similarity index 100%
rename from go/go.sum
rename to integration-tests/go/go.sum
diff --git a/go/main_test.go b/integration-tests/go/main_test.go
similarity index 100%
rename from go/main_test.go
rename to integration-tests/go/main_test.go
diff --git a/go/utils/string_test.go b/integration-tests/go/utils/string_test.go
similarity index 100%
rename from go/utils/string_test.go
rename to integration-tests/go/utils/string_test.go
diff --git a/tests/email/build/java/test/action/surefire/report/email/EmailAddressTest.class b/integration-tests/maven/email/build/java/test/action/surefire/report/email/EmailAddressTest.class
similarity index 100%
rename from tests/email/build/java/test/action/surefire/report/email/EmailAddressTest.class
rename to integration-tests/maven/email/build/java/test/action/surefire/report/email/EmailAddressTest.class
diff --git a/tests/email/pom.xml b/integration-tests/maven/email/pom.xml
similarity index 100%
rename from tests/email/pom.xml
rename to integration-tests/maven/email/pom.xml
diff --git a/tests/email/src/main/java/action/surefire/report/email/EmailAddress.java b/integration-tests/maven/email/src/main/java/action/surefire/report/email/EmailAddress.java
similarity index 100%
rename from tests/email/src/main/java/action/surefire/report/email/EmailAddress.java
rename to integration-tests/maven/email/src/main/java/action/surefire/report/email/EmailAddress.java
diff --git a/tests/email/src/main/java/action/surefire/report/email/InvalidEmailAddressException.java b/integration-tests/maven/email/src/main/java/action/surefire/report/email/InvalidEmailAddressException.java
similarity index 100%
rename from tests/email/src/main/java/action/surefire/report/email/InvalidEmailAddressException.java
rename to integration-tests/maven/email/src/main/java/action/surefire/report/email/InvalidEmailAddressException.java
diff --git a/tests/email/src/test/java/action/surefire/report/email/EmailAddressTest.java b/integration-tests/maven/email/src/test/java/action/surefire/report/email/EmailAddressTest.java
similarity index 100%
rename from tests/email/src/test/java/action/surefire/report/email/EmailAddressTest.java
rename to integration-tests/maven/email/src/test/java/action/surefire/report/email/EmailAddressTest.java
diff --git a/tests/evil_twins/pom.xml b/integration-tests/maven/evil_twins/pom.xml
similarity index 100%
rename from tests/evil_twins/pom.xml
rename to integration-tests/maven/evil_twins/pom.xml
diff --git a/tests/evil_twins/src/main/java/action/surefire/report/twin/first/Twin.java b/integration-tests/maven/evil_twins/src/main/java/action/surefire/report/twin/first/Twin.java
similarity index 100%
rename from tests/evil_twins/src/main/java/action/surefire/report/twin/first/Twin.java
rename to integration-tests/maven/evil_twins/src/main/java/action/surefire/report/twin/first/Twin.java
diff --git a/tests/evil_twins/src/main/java/action/surefire/report/twin/second/Twin.java b/integration-tests/maven/evil_twins/src/main/java/action/surefire/report/twin/second/Twin.java
similarity index 100%
rename from tests/evil_twins/src/main/java/action/surefire/report/twin/second/Twin.java
rename to integration-tests/maven/evil_twins/src/main/java/action/surefire/report/twin/second/Twin.java
diff --git a/tests/evil_twins/src/test/java/action/surefire/report/twin/first/TwinTest.java b/integration-tests/maven/evil_twins/src/test/java/action/surefire/report/twin/first/TwinTest.java
similarity index 100%
rename from tests/evil_twins/src/test/java/action/surefire/report/twin/first/TwinTest.java
rename to integration-tests/maven/evil_twins/src/test/java/action/surefire/report/twin/first/TwinTest.java
diff --git a/tests/evil_twins/src/test/java/action/surefire/report/twin/second/TwinTest.java b/integration-tests/maven/evil_twins/src/test/java/action/surefire/report/twin/second/TwinTest.java
similarity index 100%
rename from tests/evil_twins/src/test/java/action/surefire/report/twin/second/TwinTest.java
rename to integration-tests/maven/evil_twins/src/test/java/action/surefire/report/twin/second/TwinTest.java
diff --git a/tests/pom.xml b/integration-tests/maven/pom.xml
similarity index 85%
rename from tests/pom.xml
rename to integration-tests/maven/pom.xml
index e7c4613..fb2f956 100644
--- a/tests/pom.xml
+++ b/integration-tests/maven/pom.xml
@@ -78,6 +78,19 @@
                     <testFailureIgnore>true</testFailureIgnore>
                 </configuration>
             </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-failsafe-plugin</artifactId>
+                <version>2.22.2</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>integration-test</goal>
+                            <goal>verify</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
         </plugins>
     </build>
 
diff --git a/tests/utils/pom.xml b/integration-tests/maven/utils/pom.xml
similarity index 100%
rename from tests/utils/pom.xml
rename to integration-tests/maven/utils/pom.xml
diff --git a/tests/utils/src/main/java/action/surefire/report/calc/CalcUtils.java b/integration-tests/maven/utils/src/main/java/action/surefire/report/calc/CalcUtils.java
similarity index 100%
rename from tests/utils/src/main/java/action/surefire/report/calc/CalcUtils.java
rename to integration-tests/maven/utils/src/main/java/action/surefire/report/calc/CalcUtils.java
diff --git a/tests/utils/src/main/java/action/surefire/report/calc/StringUtils.java b/integration-tests/maven/utils/src/main/java/action/surefire/report/calc/StringUtils.java
similarity index 100%
rename from tests/utils/src/main/java/action/surefire/report/calc/StringUtils.java
rename to integration-tests/maven/utils/src/main/java/action/surefire/report/calc/StringUtils.java
diff --git a/tests/utils/src/test/java/action/surefire/report/calc/AllOkTest.java b/integration-tests/maven/utils/src/test/java/action/surefire/report/calc/AllOkTest.java
similarity index 100%
rename from tests/utils/src/test/java/action/surefire/report/calc/AllOkTest.java
rename to integration-tests/maven/utils/src/test/java/action/surefire/report/calc/AllOkTest.java
diff --git a/tests/utils/src/test/java/action/surefire/report/calc/CalcUtilsTest.kt b/integration-tests/maven/utils/src/test/java/action/surefire/report/calc/CalcUtilsTest.kt
similarity index 100%
rename from tests/utils/src/test/java/action/surefire/report/calc/CalcUtilsTest.kt
rename to integration-tests/maven/utils/src/test/java/action/surefire/report/calc/CalcUtilsTest.kt
diff --git a/tests/utils/src/test/java/action/surefire/report/calc/StringUtilsTest.java b/integration-tests/maven/utils/src/test/java/action/surefire/report/calc/StringUtilsTest.java
similarity index 99%
rename from tests/utils/src/test/java/action/surefire/report/calc/StringUtilsTest.java
rename to integration-tests/maven/utils/src/test/java/action/surefire/report/calc/StringUtilsTest.java
index 1a7498a..2c9784c 100644
--- a/tests/utils/src/test/java/action/surefire/report/calc/StringUtilsTest.java
+++ b/integration-tests/maven/utils/src/test/java/action/surefire/report/calc/StringUtilsTest.java
@@ -48,4 +48,4 @@ public void require_withNullMsg() {
         thrown.expectMessage("Input='' didn't match condition.");
         StringUtils.requireNotBlank("");
     }
-}
\ No newline at end of file
+}
diff --git a/python/__init__.py b/integration-tests/python/__init__.py
similarity index 100%
rename from python/__init__.py
rename to integration-tests/python/__init__.py
diff --git a/python/test_sample.py b/integration-tests/python/test_sample.py
similarity index 100%
rename from python/test_sample.py
rename to integration-tests/python/test_sample.py
diff --git a/package.json b/package.json
index aaecbcc..6fbe83f 100644
--- a/package.json
+++ b/package.json
@@ -42,7 +42,7 @@
     "@octokit/fixtures": "22.0.6",
     "@vercel/ncc": "0.38.1",
     "enzyme": "3.11.0",
-    "eslint": "8.52.0",
+    "eslint": "8.56.0",
     "jest": "29.7.0",
     "jest-junit": "16.0.0",
     "nock": "14.0.0-beta.1"
diff --git a/tests/email/target/test-classes/action/surefire/report/email/EmailAddressTest.class b/tests/email/target/test-classes/action/surefire/report/email/EmailAddressTest.class
deleted file mode 100644
index d121cb0..0000000
Binary files a/tests/email/target/test-classes/action/surefire/report/email/EmailAddressTest.class and /dev/null differ
diff --git a/utils.js b/utils.js
index 08e7ab5..03d0930 100644
--- a/utils.js
+++ b/utils.js
@@ -9,24 +9,24 @@ const resolveFileAndLine = (file, classname, output, isFilenameInOutput) => {
     let filenameWithPackage;
     if (isFilenameInOutput) {
         filename = output.split(':')[0].trim();
-        filenameWithPackage = filename
+        filenameWithPackage = filename;
     } else {
         filename = file ? file : classname.split('.').slice(-1)[0].split('(')[0];
-        filenameWithPackage = classname.replace(/\./g, "/");
+        filenameWithPackage = classname.replace(/\./g, '/');
     }
     const matches = output.match(new RegExp(`${filename}.*?:\\d+`, 'g'));
-    if (!matches) return { filename: filename, filenameWithPackage: filenameWithPackage, line: 1 };
+    if (!matches) return {filename: filename, filenameWithPackage: filenameWithPackage, line: 1};
 
     const [lastItem] = matches.slice(-1);
     const [, line] = lastItem.split(':');
     core.debug(`Resolved file ${filenameWithPackage} with name ${filename} and line ${line}`);
 
-    return { filename, filenameWithPackage, line: parseInt(line) };
+    return {filename, filenameWithPackage, line: parseInt(line)};
 };
 
 const resolvePath = async filenameWithPackage => {
     core.debug(`Resolving path for ${filenameWithPackage}`);
-    const globber = await glob.create([`**/${filenameWithPackage}.*`, `**/${filenameWithPackage}`].join('\n'), { followSymbolicLinks: false });
+    const globber = await glob.create([`**/${filenameWithPackage}.*`, `**/${filenameWithPackage}`].join('\n'), {followSymbolicLinks: false});
     const results = await globber.glob();
     core.debug(`Matched files: ${results}`);
     const searchPath = globber.getSearchPaths()[0];
@@ -49,6 +49,19 @@ const resolvePath = async filenameWithPackage => {
     return canonicalPath;
 };
 
+function getTestsuites(report) {
+    if (report.testsuite) {
+        return [report.testsuite];
+    }
+    if (!report.testsuites || !report.testsuites.testsuite) {
+        return [];
+    }
+    if (Array.isArray(report.testsuites.testsuite)) {
+        return report.testsuites.testsuite;
+    }
+    return [report.testsuites.testsuite];
+}
+
 async function parseFile(file, isFilenameInStackTrace) {
     core.debug(`Parsing file ${file}`);
     let count = 0;
@@ -57,12 +70,11 @@ async function parseFile(file, isFilenameInStackTrace) {
 
     const data = await fs.promises.readFile(file);
 
-    const report = JSON.parse(parser.xml2json(data, { compact: true }));
-    const testsuites = report.testsuite
-        ? [report.testsuite]
-        : Array.isArray(report.testsuites.testsuite)
-            ? report.testsuites.testsuite
-            : [report.testsuites.testsuite];
+    const report = JSON.parse(parser.xml2json(data, {compact: true}));
+    core.debug(`parsed report: ${JSON.stringify(report)}`);
+
+    const testsuites = getTestsuites(report);
+    core.debug(`test suites: ${JSON.stringify(testsuites)}`);
 
     for (const testsuite of testsuites) {
         const testcases = Array.isArray(testsuite.testcase)
@@ -99,7 +111,7 @@ async function parseFile(file, isFilenameInStackTrace) {
                     testcase._attributes.name
                 ).trim();
 
-                const { filename, filenameWithPackage, line } = resolveFileAndLine(
+                const {filename, filenameWithPackage, line} = resolveFileAndLine(
                     testcase._attributes.file,
                     testcase._attributes.classname,
                     stackTrace,
@@ -124,22 +136,22 @@ async function parseFile(file, isFilenameInStackTrace) {
             }
         }
     }
-    return { count, skipped, annotations };
+    return {count, skipped, annotations};
 }
 
 const parseTestReports = async (reportPaths, isFilenameInStackTrace) => {
-    const globber = await glob.create(reportPaths, { followSymbolicLinks: false });
+    const globber = await glob.create(reportPaths, {followSymbolicLinks: false});
     let annotations = [];
     let count = 0;
     let skipped = 0;
     for await (const file of globber.globGenerator()) {
-        const { count: c, skipped: s, annotations: a } = await parseFile(file, isFilenameInStackTrace);
+        const {count: c, skipped: s, annotations: a} = await parseFile(file, isFilenameInStackTrace);
         if (c === 0) continue;
         count += c;
         skipped += s;
         annotations = annotations.concat(a);
     }
-    return { count, skipped, annotations };
+    return {count, skipped, annotations};
 };
 
 module.exports = { resolveFileAndLine, resolvePath, parseFile, parseTestReports };
diff --git a/utils.test.js b/utils.test.js
index 433bdb9..3a87225 100644
--- a/utils.test.js
+++ b/utils.test.js
@@ -99,32 +99,32 @@ describe('resolvePath', () => {
     it('should find correct file for Java filename', async () => {
         const path = await resolvePath('EmailAddressTest');
         expect(path).toBe(
-            'tests/email/src/test/java/action/surefire/report/email/EmailAddressTest.java'
+            'integration-tests/maven/email/src/test/java/action/surefire/report/email/EmailAddressTest.java'
         );
     });
 
     it('should find correct file for Kotlin filename', async () => {
         const path = await resolvePath('CalcUtilsTest');
-        expect(path).toBe('tests/utils/src/test/java/action/surefire/report/calc/CalcUtilsTest.kt');
+        expect(path).toBe('integration-tests/maven/utils/src/test/java/action/surefire/report/calc/CalcUtilsTest.kt');
     });
 
     it('should find correct file when extension is included', async () => {
         const path = await resolvePath('CalcUtilsTest.kt');
-        expect(path).toBe('tests/utils/src/test/java/action/surefire/report/calc/CalcUtilsTest.kt');
+        expect(path).toBe('integration-tests/maven/utils/src/test/java/action/surefire/report/calc/CalcUtilsTest.kt');
     });
 });
 
 describe('parseFile', () => {
     it('should parse CalcUtils results', async () => {
         const { count, skipped, annotations } = await parseFile(
-            'tests/utils/target/surefire-reports/TEST-action.surefire.report.calc.CalcUtilsTest.xml'
+            'integration-tests/maven/utils/target/surefire-reports/TEST-action.surefire.report.calc.CalcUtilsTest.xml'
         );
 
         expect(count).toBe(2);
         expect(skipped).toBe(0);
         expect(annotations).toStrictEqual([
             {
-                path: 'tests/utils/src/test/java/action/surefire/report/calc/CalcUtilsTest.kt',
+                path: 'integration-tests/maven/utils/src/test/java/action/surefire/report/calc/CalcUtilsTest.kt',
                 start_line: 27,
                 end_line: 27,
                 start_column: 0,
@@ -133,11 +133,10 @@ describe('parseFile', () => {
                 title: 'CalcUtilsTest.test error handling',
                 message:
                     'unexpected exception type thrown; expected:<java.lang.IllegalStateException> but was:<java.lang.IllegalArgumentException>',
-                raw_details:
-                    'java.lang.AssertionError: unexpected exception type thrown; expected:<java.lang.IllegalStateException> but was:<java.lang.IllegalArgumentException>\n\tat action.surefire.report.calc.CalcUtilsTest.test error handling(CalcUtilsTest.kt:27)\nCaused by: java.lang.IllegalArgumentException: Amount must have max 2 non-zero decimal places\n\tat action.surefire.report.calc.CalcUtilsTest.scale(CalcUtilsTest.kt:31)\n\tat action.surefire.report.calc.CalcUtilsTest.access$scale(CalcUtilsTest.kt:9)\n\tat action.surefire.report.calc.CalcUtilsTest.test error handling(CalcUtilsTest.kt:27)'
+                raw_details: expect.stringContaining('at action.surefire.report.calc.CalcUtilsTest.test error handling(CalcUtilsTest.kt:27)')
             },
             {
-                path: 'tests/utils/src/test/java/action/surefire/report/calc/CalcUtilsTest.kt',
+                path: 'integration-tests/maven/utils/src/test/java/action/surefire/report/calc/CalcUtilsTest.kt',
                 start_line: 15,
                 end_line: 15,
                 start_column: 0,
@@ -145,19 +144,18 @@ describe('parseFile', () => {
                 annotation_level: 'failure',
                 title: 'CalcUtilsTest.test scale',
                 message: 'Expected: <100.10>\n     but: was <100.11>',
-                raw_details:
-                    'java.lang.AssertionError: \n\nExpected: <100.10>\n     but: was <100.11>\n\tat action.surefire.report.calc.CalcUtilsTest.test scale(CalcUtilsTest.kt:15)'
+                raw_details: expect.stringContaining('at action.surefire.report.calc.CalcUtilsTest.test scale(CalcUtilsTest.kt:15)')
             }
         ]);
     });
     it('should parse pytest results', async () => {
-        const { count, skipped, annotations } = await parseFile('python/report.xml');
+        const { count, skipped, annotations } = await parseFile('integration-tests/python/report.xml');
 
         expect(count).toBe(3);
         expect(skipped).toBe(0);
         expect(annotations).toStrictEqual([
             {
-                path: 'python/test_sample.py',
+                path: 'integration-tests/python/test_sample.py',
                 start_line: 10,
                 end_line: 10,
                 start_column: 0,
@@ -166,10 +164,10 @@ describe('parseFile', () => {
                 title: 'test_sample.test_which_fails',
                 message: "AssertionError: assert 'test' == 'xyz'\n  - xyz\n  + test",
                 raw_details:
-                    "def test_which_fails():\n        event = { 'attr': 'test'}\n>       assert event['attr'] == 'xyz'\nE       AssertionError: assert 'test' == 'xyz'\nE         - xyz\nE         + test\n\npython/test_sample.py:10: AssertionError"
+                    "def test_which_fails():\n        event = { 'attr': 'test'}\n>       assert event['attr'] == 'xyz'\nE       AssertionError: assert 'test' == 'xyz'\nE         - xyz\nE         + test\n\nintegration-tests/python/test_sample.py:10: AssertionError"
             },
             {
-                path: 'python/test_sample.py',
+                path: 'integration-tests/python/test_sample.py',
                 start_line: 14,
                 end_line: 14,
                 start_column: 0,
@@ -178,19 +176,19 @@ describe('parseFile', () => {
                 title: 'test_sample.test_with_error',
                 message: "AttributeError: 'dict' object has no attribute 'attr'",
                 raw_details:
-                    "def test_with_error():\n        event = { 'attr': 'test'}\n>       assert event.attr == 'test'\nE       AttributeError: 'dict' object has no attribute 'attr'\n\npython/test_sample.py:14: AttributeError"
+                    "def test_with_error():\n        event = { 'attr': 'test'}\n>       assert event.attr == 'test'\nE       AttributeError: 'dict' object has no attribute 'attr'\n\nintegration-tests/python/test_sample.py:14: AttributeError"
             }
         ]);
     });
     it('should parse go results', async () => {
-        const {count, skipped, annotations} = await parseFile('go/report.xml', true);
+        const {count, skipped, annotations} = await parseFile('integration-tests/go/report.xml', true);
 
         expect(count).toBe(3);
         expect(skipped).toBe(0);
         // noinspection RegExpRepeatedSpace
         expect(annotations).toStrictEqual([
             {
-                path: 'go/main_test.go',
+                path: 'integration-tests/go/main_test.go',
                 start_line: 12,
                 end_line: 12,
                 start_column: 0,
@@ -201,7 +199,7 @@ describe('parseFile', () => {
                 raw_details: 'main_test.go:12: failing test'
             },
             {
-                path: 'go/utils/string_test.go',
+                path: 'integration-tests/go/utils/string_test.go',
                 start_line: 7,
                 end_line: 7,
                 start_column: 0,
@@ -210,7 +208,7 @@ describe('parseFile', () => {
                 title: 'string_test.go.TestFailing',
                 message: 'Failed',
                 raw_details: expect.stringMatching(new RegExp(`string_test.go:7: 
-\\s*Error Trace:.*action-surefire-report/go/utils/string_test.go:7
+\\s*Error Trace:.*action-surefire-report/integration-tests/go/utils/string_test.go:7
 \\s*Error:     \\s*Not equal: 
 \\s*expected: "1"
 \\s*actual  : "2"
@@ -227,7 +225,7 @@ describe('parseFile', () => {
     });
     it('should parse custom report with details as an array', async () => {
         const { count, skipped, annotations } = await parseFile(
-            'custom_reports/TEST-pro.taskana.common.api.ListUtilTest-H2.xml'
+            'integration-tests/custom_reports/TEST-pro.taskana.common.api.ListUtilTest-H2.xml'
         );
 
         expect(count).toBe(1);
@@ -282,7 +280,7 @@ describe('parseFile', () => {
 
     it('should parse custom report with flaky failures', async () => {
         const { count, skipped, annotations } = await parseFile(
-            'custom_reports/TEST-test.MyIntegrationTestSuite.xml'
+            'integration-tests/custom_reports/TEST-test.MyIntegrationTestSuite.xml'
         );
 
         expect(count).toBe(5);