Compare commits

..

17 Commits

Author SHA1 Message Date
Julien Catania
2c5485e682 feat(lcov) fix CI 2024-01-12 16:54:11 +01:00
Julien Catania
6effce6d66 feat(lcov) fix CI 2024-01-12 16:52:34 +01:00
Julien Catania
f19a7213c3 feat(lcov) use really lcov.info file 2024-01-12 16:18:04 +01:00
Julien Catania
712fabc3c8 Merge branch 'main' into feature/lcov-support
# Conflicts:
#	dist/index.js
#	src/main.ts
2024-01-12 16:15:57 +01:00
Julien Catania
fb59f4f91d feat(lcov) use really lcov.info file 2024-01-12 16:10:04 +01:00
Julien Catania
61007344dd Merge pull request #351 from j-catania/main
Adding LCOV Support
2024-01-02 21:25:14 +01:00
Julien Catania
4dff4fc7ee Merge remote-tracking branch 'origin/main'
# Conflicts:
#	__tests__/lcov.test.ts
#	action.yml
#	package-lock.json
#	package.json
#	src/main.ts
2024-01-02 21:23:53 +01:00
Julien Catania
39f548db94 sync fork 2024-01-02 21:21:26 +01:00
Julien Catania
cc150eb989 add lcov as reporter 2024-01-02 21:20:18 +01:00
Julien Catania
440cc5265e add lcov as reporter 2024-01-02 21:19:57 +01:00
Julien Catania
713455873c good start 2024-01-02 21:19:21 +01:00
Julien Catania
883ec99854 add lcov as reporter 2024-01-02 21:05:34 +01:00
Julien Catania
62968bd2b2 add lcov as reporter 2024-01-02 17:05:11 +01:00
Julien Catania
0fc59a15c8 Merge pull request #9 from j-catania/dependabot/npm_and_yarn/xml2js-0.5.0
Bump xml2js from 0.4.23 to 0.5.0
2023-09-18 20:42:44 +02:00
dependabot[bot]
dc9819d851 Bump xml2js from 0.4.23 to 0.5.0
Bumps [xml2js](https://github.com/Leonidas-from-XIV/node-xml2js) from 0.4.23 to 0.5.0.
- [Commits](https://github.com/Leonidas-from-XIV/node-xml2js/commits/0.5.0)

---
updated-dependencies:
- dependency-name: xml2js
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-18 18:41:14 +00:00
Julien Catania
48cc88be3a update dep 2023-09-18 20:38:25 +02:00
Julien Catania
5db7763d84 good start 2023-08-12 15:51:32 +02:00
27 changed files with 1410 additions and 1019 deletions

View File

@@ -1,12 +1,5 @@
# Changelog # Changelog
## 1.8.0
* Add `SwiftXunitParser` class based on `JavaJunitParser` for `swift-xunit` reporter https://github.com/dorny/test-reporter/pull/317
* Use NodeJS 18 LTS as default runtime https://github.com/dorny/test-reporter/pull/332
* Escape `<>` characters in suite name https://github.com/dorny/test-reporter/pull/236
* Update actions runtime to Node20 https://github.com/dorny/test-reporter/pull/315
* Update check title and remove icon https://github.com/dorny/test-reporter/pull/144
## 1.7.0 ## 1.7.0
* Fix #199: Use ✅ instead of ✔️ for better cross platform look by @petrdvorak in https://github.com/dorny/test-reporter/pull/200 * Fix #199: Use ✅ instead of ✔️ for better cross platform look by @petrdvorak in https://github.com/dorny/test-reporter/pull/200
* Verify content of dist/ folder matches build output by @dorny in https://github.com/dorny/test-reporter/pull/207 * Verify content of dist/ folder matches build output by @dorny in https://github.com/dorny/test-reporter/pull/207

View File

@@ -142,7 +142,6 @@ jobs:
# java-junit # java-junit
# jest-junit # jest-junit
# mocha-json # mocha-json
# rspec-json
reporter: '' reporter: ''
# Allows you to generate only the summary. # Allows you to generate only the summary.

View File

@@ -0,0 +1,21 @@
![Tests failed](https://img.shields.io/badge/tests-4%20passed%2C%202%20failed-critical)
## ❌ <a id="user-content-r0" href="#r0">fixtures/lcov.info</a>
**6** tests were completed in **0ms** with **4** passed, **2** failed and **0** skipped.
|Test suite|Passed|Failed|Skipped|Time|
|:---|---:|---:|---:|---:|
|[src/services/notifier/NotifierService.js](#r0s0)|2✅|1❌||0ms|
|[src/services/notifier/providers/DiscordNotifierProvider.js](#r0s1)|2✅|1❌||0ms|
### ❌ <a id="user-content-r0s0" href="#r0s0">src/services/notifier/NotifierService.js</a>
```
src/services/notifier/NotifierService.js
✅ lines 100% (21/21)
✅ functions 100% (10/10)
❌ branches 50% (3/6)
```
### ❌ <a id="user-content-r0s1" href="#r0s1">src/services/notifier/providers/DiscordNotifierProvider.js</a>
```
src/services/notifier/providers/DiscordNotifierProvider.js
✅ lines 100% (17/17)
✅ functions 100% (3/3)
❌ branches 75% (3/4)
```

View File

@@ -1,16 +0,0 @@
![Tests failed](https://img.shields.io/badge/tests-1%20passed%2C%201%20failed%2C%201%20skipped-critical)
## ❌ <a id="user-content-r0" href="#r0">fixtures/rspec-json.json</a>
**3** tests were completed in **0ms** with **1** passed, **1** failed and **1** skipped.
|Test suite|Passed|Failed|Skipped|Time|
|:---|---:|---:|---:|---:|
|[./spec/config/check_env_vars_spec.rb](#r0s0)|1✅|1❌|1⚪|0ms|
### ❌ <a id="user-content-r0s0" href="#r0s0">./spec/config/check_env_vars_spec.rb</a>
```
CheckEnvVars#call when all env vars are defined behaves like success load
❌ CheckEnvVars#call when all env vars are defined behaves like success load fails in assertion
(#ActiveSupport::BroadcastLogger:0x00007f1007fedf58).debug("All config env vars exist")
expected: 0 times with arguments: ("All config env vars exist")
received: 1 time with arguments: ("All config env vars exist")
✅ CheckEnvVars#call when all env vars are defined behaves like success load logs success message
⚪ CheckEnvVars#call when all env vars are defined behaves like success load skips the test
```

View File

@@ -0,0 +1,62 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`lcov report coverage report from facebook/jest test results matches snapshot 1`] = `
TestRunResult {
"path": "fixtures/lcov.info",
"suites": [
TestSuiteResult {
"groups": [
TestGroupResult {
"name": "src/services/notifier/NotifierService.js",
"tests": [
{
"name": "lines 100% (21/21)",
"result": "success",
"time": 0,
},
{
"name": "functions 100% (10/10)",
"result": "success",
"time": 0,
},
{
"name": "branches 50% (3/6)",
"result": "failed",
"time": 0,
},
],
},
],
"name": "src/services/notifier/NotifierService.js",
"totalTime": undefined,
},
TestSuiteResult {
"groups": [
TestGroupResult {
"name": "src/services/notifier/providers/DiscordNotifierProvider.js",
"tests": [
{
"name": "lines 100% (17/17)",
"result": "success",
"time": 0,
},
{
"name": "functions 100% (3/3)",
"result": "success",
"time": 0,
},
{
"name": "branches 75% (3/4)",
"result": "failed",
"time": 0,
},
],
},
],
"name": "src/services/notifier/providers/DiscordNotifierProvider.js",
"totalTime": undefined,
},
],
"totalTime": undefined,
}
`;

View File

@@ -1,49 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`rspec-json tests report from ./reports/rspec-json test results matches snapshot 1`] = `
TestRunResult {
"path": "fixtures/rspec-json.json",
"suites": [
TestSuiteResult {
"groups": [
TestGroupResult {
"name": "CheckEnvVars#call when all env vars are defined behaves like success load",
"tests": [
TestCaseResult {
"error": {
"details": "/usr/local/bundle/ruby/3.3.0/gems/net-http-0.4.1/lib/net/http.rb:1603:in \`initialize'
./config/check_env_vars.rb:11:in \`call'
./spec/config/check_env_vars_spec.rb:7:in \`block (3 levels) in <top (required)>'
./spec/config/check_env_vars_spec.rb:19:in \`block (4 levels) in <top (required)>'",
"line": 11,
"message": "(#ActiveSupport::BroadcastLogger:0x00007f1007fedf58).debug("All config env vars exist")
expected: 0 times with arguments: ("All config env vars exist")
received: 1 time with arguments: ("All config env vars exist")",
"path": "./config/check_env_vars.rb",
},
"name": "CheckEnvVars#call when all env vars are defined behaves like success load fails in assertion",
"result": "failed",
"time": 0.004411051,
},
TestCaseResult {
"error": undefined,
"name": "CheckEnvVars#call when all env vars are defined behaves like success load logs success message",
"result": "success",
"time": 0.079159625,
},
TestCaseResult {
"error": undefined,
"name": "CheckEnvVars#call when all env vars are defined behaves like success load skips the test",
"result": "skipped",
"time": 0.000023007,
},
],
},
],
"name": "./spec/config/check_env_vars_spec.rb",
"totalTime": undefined,
},
],
"totalTime": 0.19118387,
}
`;

View File

@@ -1,15 +1,9 @@
{"protocolVersion":"0.1.1","runnerVersion":"1.25.3","pid":7103,"type":"start","time":0} {"protocolVersion":"0.1.1","runnerVersion":"1.15.4","pid":21320,"type":"start","time":0}
{"suite":{"id":0,"platform":"vm","path":"test/second_test.dart"},"type":"suite","time":0} {"suite":{"id":0,"platform":"vm","path":"test\\main_test.dart"},"type":"suite","time":0}
{"test":{"id":1,"name":"loading test/second_test.dart","suiteID":0,"groupIDs":[],"metadata":{"skip":false,"skipReason":null},"line":null,"column":null,"url":null},"type":"testStart","time":0} {"test":{"id":1,"name":"loading test\\main_test.dart","suiteID":0,"groupIDs":[],"metadata":{"skip":false,"skipReason":null},"line":null,"column":null,"url":null},"type":"testStart","time":1}
{"suite":{"id":2,"platform":"vm","path":"test/main_test.dart"},"type":"suite","time":4} {"suite":{"id":2,"platform":"vm","path":"test\\second_test.dart"},"type":"suite","time":11}
{"test":{"id":3,"name":"loading test/main_test.dart","suiteID":2,"groupIDs":[],"metadata":{"skip":false,"skipReason":null},"line":null,"column":null,"url":null},"type":"testStart","time":4} {"test":{"id":3,"name":"loading test\\second_test.dart","suiteID":2,"groupIDs":[],"metadata":{"skip":false,"skipReason":null},"line":null,"column":null,"url":null},"type":"testStart","time":11}
{"count":2,"time":5,"type":"allSuites"} {"count":2,"type":"allSuites","time":11}
{"testID":1,"result":"success","skipped":false,"hidden":true,"type":"testDone","time":294} {"testID":1,"result":"success","skipped":false,"hidden":true,"type":"testDone","time":4018}
{"testID":3,"messageType":"print","message":"Hello from the test","type":"print","time":297} {"testID":3,"result":"success","skipped":false,"hidden":true,"type":"testDone","time":4025}
{"testID":3,"result":"success","skipped":false,"hidden":true,"type":"testDone","time":321} {"success":true,"type":"done","time":4029}
{"group":{"id":4,"suiteID":2,"parentID":null,"name":"","metadata":{"skip":false,"skipReason":null},"testCount":0,"line":null,"column":null,"url":null},"type":"group","time":322}
{"test":{"id":5,"name":"(setUpAll)","suiteID":2,"groupIDs":[4],"metadata":{"skip":false,"skipReason":null},"line":6,"column":3,"url":"file:///Users/domu/Downloads/test-reporter/reports/dart/test/main_test.dart"},"type":"testStart","time":322}
{"testID":5,"result":"success","skipped":false,"hidden":true,"type":"testDone","time":330}
{"test":{"id":6,"name":"(tearDownAll)","suiteID":2,"groupIDs":[4],"metadata":{"skip":false,"skipReason":null},"line":7,"column":3,"url":"file:///Users/domu/Downloads/test-reporter/reports/dart/test/main_test.dart"},"type":"testStart","time":330}
{"testID":6,"result":"success","skipped":false,"hidden":true,"type":"testDone","time":331}
{"success":true,"type":"done","time":333}

View File

@@ -1,17 +0,0 @@
{
"version": "3.13.0",
"messages": [
"No examples found."
],
"examples": [
],
"summary": {
"duration": 0.002514266,
"example_count": 0,
"failure_count": 0,
"pending_count": 0,
"errors_outside_of_examples_count": 0
},
"summary_line": "0 examples, 0 failures"
}

View File

@@ -0,0 +1,92 @@
TN:
SF:src/services/notifier/NotifierService.js
FN:9,(anonymous_0)
FN:10,(anonymous_1)
FN:26,(anonymous_2)
FN:27,(anonymous_3)
FN:29,(anonymous_4)
FN:30,(anonymous_5)
FN:46,(anonymous_6)
FN:47,(anonymous_7)
FN:48,(anonymous_8)
FN:49,(anonymous_9)
FNF:10
FNH:10
FNDA:1,(anonymous_0)
FNDA:1,(anonymous_1)
FNDA:1,(anonymous_2)
FNDA:3,(anonymous_3)
FNDA:3,(anonymous_4)
FNDA:3,(anonymous_5)
FNDA:1,(anonymous_6)
FNDA:3,(anonymous_7)
FNDA:3,(anonymous_8)
FNDA:3,(anonymous_9)
DA:9,1
DA:10,1
DA:11,1
DA:13,1
DA:14,1
DA:26,1
DA:27,3
DA:29,1
DA:30,3
DA:31,3
DA:33,3
DA:34,3
DA:46,1
DA:47,3
DA:48,3
DA:51,3
DA:53,3
DA:54,3
DA:58,3
DA:61,1
DA:64,1
LF:21
LH:21
BRDA:11,0,0,1
BRDA:11,0,1,0
BRDA:31,1,0,3
BRDA:31,1,1,0
BRDA:51,2,0,3
BRDA:51,2,1,0
BRF:6
BRH:3
end_of_record
TN:
SF:src/services/notifier/providers/DiscordNotifierProvider.js
FN:12,(anonymous_0)
FN:33,(anonymous_1)
FN:51,(anonymous_2)
FNF:3
FNH:3
FNDA:1,(anonymous_0)
FNDA:1,(anonymous_1)
FNDA:1,(anonymous_2)
DA:3,1
DA:12,1
DA:13,1
DA:14,1
DA:22,1
DA:23,1
DA:33,1
DA:34,1
DA:35,1
DA:40,1
DA:41,1
DA:51,1
DA:52,1
DA:53,1
DA:58,1
DA:59,1
DA:62,1
LF:17
LH:17
BRDA:18,0,0,0
BRDA:18,0,1,1
BRDA:20,1,0,1
BRDA:20,1,1,1
BRF:4
BRH:3
end_of_record

View File

@@ -1,53 +0,0 @@
{
"version": "3.13.0",
"examples": [
{
"id": "./spec/config/check_env_vars_spec.rb[1:1:1:1:1]",
"description": "logs success message",
"full_description": "CheckEnvVars#call when all env vars are defined behaves like success load logs success message",
"status": "passed",
"file_path": "./spec/config/check_env_vars_spec.rb",
"line_number": 12,
"run_time": 0.079159625,
"pending_message": null
},
{
"id": "./spec/config/check_env_vars_spec.rb[1:1:1:1:2]",
"description": "fails in assertion",
"full_description": "CheckEnvVars#call when all env vars are defined behaves like success load fails in assertion",
"status": "failed",
"file_path": "./spec/config/check_env_vars_spec.rb",
"line_number": 17,
"run_time": 0.004411051,
"pending_message": null,
"exception": {
"class": "RSpec::Mocks::MockExpectationError",
"message": "(#ActiveSupport::BroadcastLogger:0x00007f1007fedf58).debug(\"All config env vars exist\")\n expected: 0 times with arguments: (\"All config env vars exist\")\n received: 1 time with arguments: (\"All config env vars exist\")",
"backtrace": [
"/usr/local/bundle/ruby/3.3.0/gems/net-http-0.4.1/lib/net/http.rb:1603:in `initialize'",
"./config/check_env_vars.rb:11:in `call'",
"./spec/config/check_env_vars_spec.rb:7:in `block (3 levels) in \u003ctop (required)\u003e'",
"./spec/config/check_env_vars_spec.rb:19:in `block (4 levels) in \u003ctop (required)\u003e'"
]
}
},
{
"id": "./spec/config/check_env_vars_spec.rb[1:1:1:1:4]",
"description": "skips the test",
"full_description": "CheckEnvVars#call when all env vars are defined behaves like success load skips the test",
"status": "pending",
"file_path": "./spec/config/check_env_vars_spec.rb",
"line_number": 27,
"run_time": 2.3007e-05,
"pending_message": "Temporarily skipped with xit"
}
],
"summary": {
"duration": 0.19118387,
"example_count": 3,
"failure_count": 1,
"pending_count": 1,
"errors_outside_of_examples_count": 0
},
"summary_line": "3 examples, 1 failures, 1 pending"
}

23
__tests__/lcov.test.ts Normal file
View File

@@ -0,0 +1,23 @@
import * as fs from 'fs'
import * as path from 'path'
import {getReport} from '../src/report/get-report'
import {normalizeFilePath} from '../src/utils/path-utils'
import {LcovParser} from '../src/parsers/lcov/lcov-parser'
describe('lcov report coverage', () => {
it('report from facebook/jest test results matches snapshot', async () => {
const fixturePath = path.join(__dirname, 'fixtures', 'lcov.info')
const outputPath = path.join(__dirname, '__outputs__', 'lcov-report-results.md')
const filePath = normalizeFilePath(path.relative(__dirname, fixturePath))
const fileContent = fs.readFileSync(fixturePath, {encoding: 'utf8'})
const parser = new LcovParser({parseErrors: true, trackedFiles: []})
const result = await parser.parse(filePath, fileContent)
expect(result).toMatchSnapshot()
const report = getReport([result])
fs.mkdirSync(path.dirname(outputPath), {recursive: true})
fs.writeFileSync(outputPath, report)
})
})

View File

@@ -1,45 +0,0 @@
import * as fs from 'fs'
import * as path from 'path'
import {RspecJsonParser} from '../src/parsers/rspec-json/rspec-json-parser'
import {ParseOptions} from '../src/test-parser'
import {getReport} from '../src/report/get-report'
import {normalizeFilePath} from '../src/utils/path-utils'
describe('rspec-json tests', () => {
it('produces empty test run result when there are no test cases', async () => {
const fixturePath = path.join(__dirname, 'fixtures', 'empty', 'rspec-json.json')
const filePath = normalizeFilePath(path.relative(__dirname, fixturePath))
const fileContent = fs.readFileSync(fixturePath, {encoding: 'utf8'})
const opts: ParseOptions = {
parseErrors: true,
trackedFiles: []
}
const parser = new RspecJsonParser(opts)
const result = await parser.parse(filePath, fileContent)
expect(result.tests).toBe(0)
expect(result.result).toBe('success')
})
it('report from ./reports/rspec-json test results matches snapshot', async () => {
const fixturePath = path.join(__dirname, 'fixtures', 'rspec-json.json')
const outputPath = path.join(__dirname, '__outputs__', 'rspec-json.md')
const filePath = normalizeFilePath(path.relative(__dirname, fixturePath))
const fileContent = fs.readFileSync(fixturePath, {encoding: 'utf8'})
const opts: ParseOptions = {
parseErrors: true,
trackedFiles: ['test/main.test.js', 'test/second.test.js', 'lib/main.js']
}
const parser = new RspecJsonParser(opts)
const result = await parser.parse(filePath, fileContent)
expect(result).toMatchSnapshot()
const report = getReport([result])
fs.mkdirSync(path.dirname(outputPath), {recursive: true})
fs.writeFileSync(outputPath, report)
})
})

View File

@@ -31,8 +31,8 @@ inputs:
- java-junit - java-junit
- jest-junit - jest-junit
- mocha-json - mocha-json
- rspec-json
- swift-xunit - swift-xunit
- lcov
required: true required: true
list-suites: list-suites:
description: | description: |

467
dist/index.js generated vendored
View File

@@ -265,10 +265,10 @@ const dotnet_trx_parser_1 = __nccwpck_require__(2664);
const java_junit_parser_1 = __nccwpck_require__(676); const java_junit_parser_1 = __nccwpck_require__(676);
const jest_junit_parser_1 = __nccwpck_require__(1113); const jest_junit_parser_1 = __nccwpck_require__(1113);
const mocha_json_parser_1 = __nccwpck_require__(6043); const mocha_json_parser_1 = __nccwpck_require__(6043);
const rspec_json_parser_1 = __nccwpck_require__(406);
const swift_xunit_parser_1 = __nccwpck_require__(5366); const swift_xunit_parser_1 = __nccwpck_require__(5366);
const path_utils_1 = __nccwpck_require__(4070); const path_utils_1 = __nccwpck_require__(4070);
const github_utils_1 = __nccwpck_require__(3522); const github_utils_1 = __nccwpck_require__(3522);
const lcov_parser_1 = __nccwpck_require__(5698);
function main() { function main() {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
try { try {
@@ -435,10 +435,10 @@ class TestReporter {
return new jest_junit_parser_1.JestJunitParser(options); return new jest_junit_parser_1.JestJunitParser(options);
case 'mocha-json': case 'mocha-json':
return new mocha_json_parser_1.MochaJsonParser(options); return new mocha_json_parser_1.MochaJsonParser(options);
case 'rspec-json':
return new rspec_json_parser_1.RspecJsonParser(options);
case 'swift-xunit': case 'swift-xunit':
return new swift_xunit_parser_1.SwiftXunitParser(options); return new swift_xunit_parser_1.SwiftXunitParser(options);
case 'lcov':
return new lcov_parser_1.LcovParser(options);
default: default:
throw new Error(`Input variable 'reporter' is set to invalid value '${reporter}'`); throw new Error(`Input variable 'reporter' is set to invalid value '${reporter}'`);
} }
@@ -558,7 +558,7 @@ class DartJsonParser {
group.tests.push(test); group.tests.push(test);
tests[evt.test.id] = test; tests[evt.test.id] = test;
} }
else if ((0, dart_json_types_1.isTestDoneEvent)(evt) && tests[evt.testID]) { else if ((0, dart_json_types_1.isTestDoneEvent)(evt) && !evt.hidden && tests[evt.testID]) {
tests[evt.testID].testDone = evt; tests[evt.testID].testDone = evt;
} }
else if ((0, dart_json_types_1.isErrorEvent)(evt) && tests[evt.testID]) { else if ((0, dart_json_types_1.isErrorEvent)(evt) && tests[evt.testID]) {
@@ -585,9 +585,7 @@ class DartJsonParser {
groups.sort((a, b) => { var _a, _b; return ((_a = a.group.line) !== null && _a !== void 0 ? _a : 0) - ((_b = b.group.line) !== null && _b !== void 0 ? _b : 0); }); groups.sort((a, b) => { var _a, _b; return ((_a = a.group.line) !== null && _a !== void 0 ? _a : 0) - ((_b = b.group.line) !== null && _b !== void 0 ? _b : 0); });
return groups.map(group => { return groups.map(group => {
group.tests.sort((a, b) => { var _a, _b; return ((_a = a.testStart.test.line) !== null && _a !== void 0 ? _a : 0) - ((_b = b.testStart.test.line) !== null && _b !== void 0 ? _b : 0); }); group.tests.sort((a, b) => { var _a, _b; return ((_a = a.testStart.test.line) !== null && _a !== void 0 ? _a : 0) - ((_b = b.testStart.test.line) !== null && _b !== void 0 ? _b : 0); });
const tests = group.tests const tests = group.tests.map(tc => {
.filter(tc => { var _a; return !((_a = tc.testDone) === null || _a === void 0 ? void 0 : _a.hidden); })
.map(tc => {
const error = this.getError(suite, tc); const error = this.getError(suite, tc);
const testName = group.group.name !== undefined && tc.testStart.test.name.startsWith(group.group.name) const testName = group.group.name !== undefined && tc.testStart.test.name.startsWith(group.group.name)
? tc.testStart.test.name.slice(group.group.name.length).trim() ? tc.testStart.test.name.slice(group.group.name.length).trim()
@@ -1295,6 +1293,120 @@ class JestJunitParser {
exports.JestJunitParser = JestJunitParser; exports.JestJunitParser = JestJunitParser;
/***/ }),
/***/ 5698:
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.LcovParser = void 0;
const test_results_1 = __nccwpck_require__(2768);
const lcov_utils_1 = __nccwpck_require__(4750);
class LcovParser {
constructor(options) {
this.options = options;
}
parse(path, content) {
return __awaiter(this, void 0, void 0, function* () {
const report = yield this.parseFile(path, content);
return this.getTestRunResult(path, report);
});
}
parseFile(path, content) {
return __awaiter(this, void 0, void 0, function* () {
try {
return (0, lcov_utils_1.parseProm)(content);
//return JSON.parse(content) as LcovReport
}
catch (e) {
throw new Error(`Invalid JSON at ${path}\n\n${e}`);
}
});
}
getTestRunResult(path, report) {
return __awaiter(this, void 0, void 0, function* () {
const suites = [];
for (const reportElement of report) {
const fileName = reportElement.file;
const statementCaseResult = {
name: `lines ${this.getPartInfo(reportElement.lines)}`,
time: 0,
result: this.getPercentage(reportElement.lines) >= 80 ? 'success' : 'failed'
};
const fonctionCaseResult = {
name: `functions ${this.getPartInfo(reportElement.functions)}`,
time: 0,
result: this.getPercentage(reportElement.functions) >= 80 ? 'success' : 'failed'
};
const brancheCaseResult = {
name: `branches ${this.getPartInfo(reportElement.branches)}`,
time: 0,
result: this.getPercentage(reportElement.branches) >= 80 ? 'success' : 'failed'
};
const testCases = [statementCaseResult, fonctionCaseResult, brancheCaseResult];
const groups = [new test_results_1.TestGroupResult(fileName, testCases)];
const suite = new test_results_1.TestSuiteResult(fileName, groups);
suites.push(suite);
}
return new test_results_1.TestRunResult(path, suites);
});
}
getPercentage(stat) {
return stat ? (stat.hit / stat.found) * 100 : 100;
}
getPartInfo(stat) {
return `${this.getPercentage(stat)}% (${stat.hit}/${stat.found})`;
}
}
exports.LcovParser = LcovParser;
/***/ }),
/***/ 4750:
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.parseProm = void 0;
const lcov_parse_1 = __importDefault(__nccwpck_require__(7454));
const parseProm = (pathOrStr) => __awaiter(void 0, void 0, void 0, function* () {
return new Promise((resolve, reject) => {
(0, lcov_parse_1.default)(pathOrStr, (err, data) => {
if (err) {
reject(err);
}
resolve(data !== null && data !== void 0 ? data : []);
});
});
});
exports.parseProm = parseProm;
/***/ }), /***/ }),
/***/ 6043: /***/ 6043:
@@ -1408,121 +1520,6 @@ class MochaJsonParser {
exports.MochaJsonParser = MochaJsonParser; exports.MochaJsonParser = MochaJsonParser;
/***/ }),
/***/ 406:
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.RspecJsonParser = void 0;
const test_results_1 = __nccwpck_require__(2768);
class RspecJsonParser {
constructor(options) {
this.options = options;
}
parse(path, content) {
return __awaiter(this, void 0, void 0, function* () {
const mocha = this.getRspecJson(path, content);
const result = this.getTestRunResult(path, mocha);
result.sort(true);
return Promise.resolve(result);
});
}
getRspecJson(path, content) {
try {
return JSON.parse(content);
}
catch (e) {
throw new Error(`Invalid JSON at ${path}\n\n${e}`);
}
}
getTestRunResult(resultsPath, rspec) {
const suitesMap = {};
const getSuite = (test) => {
var _a;
const path = test.file_path;
return (_a = suitesMap[path]) !== null && _a !== void 0 ? _a : (suitesMap[path] = new test_results_1.TestSuiteResult(path, []));
};
for (const test of rspec.examples) {
const suite = getSuite(test);
if (test.status === 'failed') {
this.processTest(suite, test, 'failed');
}
else if (test.status === 'passed') {
this.processTest(suite, test, 'success');
}
else if (test.status === 'pending') {
this.processTest(suite, test, 'skipped');
}
}
const suites = Object.values(suitesMap);
return new test_results_1.TestRunResult(resultsPath, suites, rspec.summary.duration);
}
processTest(suite, test, result) {
var _a;
const groupName = test.full_description !== test.description
? test.full_description.substr(0, test.full_description.length - test.description.length).trimEnd()
: null;
let group = suite.groups.find(grp => grp.name === groupName);
if (group === undefined) {
group = new test_results_1.TestGroupResult(groupName, []);
suite.groups.push(group);
}
const error = this.getTestCaseError(test);
const testCase = new test_results_1.TestCaseResult(test.full_description, result, (_a = test.run_time) !== null && _a !== void 0 ? _a : 0, error);
group.tests.push(testCase);
}
getTestCaseError(test) {
var _a, _b;
const backtrace = (_a = test.exception) === null || _a === void 0 ? void 0 : _a.backtrace;
const message = (_b = test.exception) === null || _b === void 0 ? void 0 : _b.message;
if (backtrace === undefined) {
return undefined;
}
let path;
let line;
const details = backtrace.join('\n');
const src = this.getExceptionSource(backtrace);
if (src) {
path = src.path;
line = src.line;
}
return {
path,
line,
message,
details
};
}
getExceptionSource(backtrace) {
const re = /^(.*?):(\d+):/;
for (const str of backtrace) {
const match = str.match(re);
if (match !== null) {
const [_, path, lineStr] = match;
if (path.startsWith('./')) {
const line = parseInt(lineStr);
return { path, line };
}
}
}
return undefined;
}
}
exports.RspecJsonParser = RspecJsonParser;
/***/ }), /***/ }),
/***/ 5366: /***/ 5366:
@@ -2153,11 +2150,26 @@ function downloadArtifact(octokit, artifactId, fileName, token) {
const headers = { const headers = {
Authorization: `Bearer ${token}` Authorization: `Bearer ${token}`
}; };
const downloadStream = got_1.default.stream(req.url, { headers }); const resp = yield (0, got_1.default)(req.url, {
const fileWriterStream = (0, fs_1.createWriteStream)(fileName); headers,
downloadStream.on('redirect', response => { followRedirect: false
core.info(`Downloading ${response.headers.location}`);
}); });
core.info(`Fetch artifact URL: ${resp.statusCode} ${resp.statusMessage}`);
if (resp.statusCode !== 302) {
throw new Error('Fetch artifact URL failed: received unexpected status code');
}
const url = resp.headers.location;
if (url === undefined) {
const receivedHeaders = Object.keys(resp.headers);
core.info(`Received headers: ${receivedHeaders.join(', ')}`);
throw new Error('Location header was not found in API response');
}
if (typeof url !== 'string') {
throw new Error(`Location header has unexpected value: ${url}`);
}
const downloadStream = got_1.default.stream(url, { headers });
const fileWriterStream = (0, fs_1.createWriteStream)(fileName);
core.info(`Downloading ${url}`);
downloadStream.on('downloadProgress', ({ transferred }) => { downloadStream.on('downloadProgress', ({ transferred }) => {
core.info(`Progress: ${transferred} B`); core.info(`Progress: ${transferred} B`);
}); });
@@ -11324,8 +11336,7 @@ module.exports = function (/**String*/ input, /** object */ options) {
* *
* @return Array * @return Array
*/ */
getEntries: function (/**String*/ password) { getEntries: function () {
_zip.password=password;
return _zip ? _zip.entries : []; return _zip ? _zip.entries : [];
}, },
@@ -11402,7 +11413,7 @@ module.exports = function (/**String*/ input, /** object */ options) {
return true; return true;
} }
var content = item.getData(_zip.password); var content = item.getData();
if (!content) throw new Error(Utils.Errors.CANT_EXTRACT_FILE); if (!content) throw new Error(Utils.Errors.CANT_EXTRACT_FILE);
if (filetools.fs.existsSync(target) && !overwrite) { if (filetools.fs.existsSync(target) && !overwrite) {
@@ -11564,9 +11575,9 @@ module.exports = function (/**String*/ input, /** object */ options) {
callback(getError("Unable to set times", filePath)); callback(getError("Unable to set times", filePath));
return; return;
} }
fileEntries.delete(entry);
// call the callback if it was last entry // call the callback if it was last entry
done(); done();
fileEntries.delete(entry);
}); });
}); });
} }
@@ -11730,9 +11741,7 @@ module.exports = function () {
set time(val) { set time(val) {
setTime(val); setTime(val);
}, },
get timeHighByte() {
return (_time >>> 8) & 0xff;
},
get crc() { get crc() {
return _crc; return _crc;
}, },
@@ -12346,12 +12355,8 @@ function decrypt(/*Buffer*/ data, /*Object*/ header, /*String, Buffer*/ pwd) {
// 2. decrypt salt what is always 12 bytes and is a part of file content // 2. decrypt salt what is always 12 bytes and is a part of file content
const salt = decrypter(data.slice(0, 12)); const salt = decrypter(data.slice(0, 12));
// if bit 3 (0x08) of the general-purpose flags field is set, check salt[11] with the high byte of the header time // 3. does password meet expectations
// 2 byte data block (as per Info-Zip spec), otherwise check with the high byte of the header entry if (salt[11] !== header.crc >>> 24) {
const verifyByte = ((header.flags & 0x8) === 0x8) ? header.timeHighByte : header.crc >>> 24;
//3. does password meet expectations
if (salt[11] !== verifyByte) {
throw "ADM-ZIP: Wrong Password"; throw "ADM-ZIP: Wrong Password";
} }
@@ -13317,7 +13322,6 @@ module.exports = function (/*Buffer|null*/ inBuffer, /** object */ options) {
_comment = Buffer.alloc(0), _comment = Buffer.alloc(0),
mainHeader = new Headers.MainHeader(), mainHeader = new Headers.MainHeader(),
loadedEntries = false; loadedEntries = false;
var password = null;
// assign options // assign options
const opts = Object.assign(Object.create(null), options); const opts = Object.assign(Object.create(null), options);
@@ -13569,7 +13573,7 @@ module.exports = function (/*Buffer|null*/ inBuffer, /** object */ options) {
// 1.2. postheader - data after data header // 1.2. postheader - data after data header
const postHeader = Buffer.alloc(entryNameLen + entry.extra.length); const postHeader = Buffer.alloc(entryNameLen + entry.extra.length);
entry.rawEntryName.copy(postHeader, 0); entry.rawEntryName.copy(postHeader, 0);
entry.extra.copy(postHeader, entryNameLen); postHeader.copy(entry.extra, entryNameLen);
// 2. offsets // 2. offsets
const dataLength = dataHeader.length + postHeader.length + compressedData.length; const dataLength = dataHeader.length + postHeader.length + compressedData.length;
@@ -23547,6 +23551,139 @@ class Keyv extends EventEmitter {
module.exports = Keyv; module.exports = Keyv;
/***/ }),
/***/ 7454:
/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
/*
Copyright (c) 2012, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://yuilibrary.com/license/
*/
var fs = __nccwpck_require__(7147),
path = __nccwpck_require__(1017);
/* istanbul ignore next */
var exists = fs.exists || path.exists;
var walkFile = function(str, cb) {
var data = [], item;
[ 'end_of_record' ].concat(str.split('\n')).forEach(function(line) {
line = line.trim();
var allparts = line.split(':'),
parts = [allparts.shift(), allparts.join(':')],
lines, fn;
switch (parts[0].toUpperCase()) {
case 'TN':
item.title = parts[1].trim();
break;
case 'SF':
item.file = parts.slice(1).join(':').trim();
break;
case 'FNF':
item.functions.found = Number(parts[1].trim());
break;
case 'FNH':
item.functions.hit = Number(parts[1].trim());
break;
case 'LF':
item.lines.found = Number(parts[1].trim());
break;
case 'LH':
item.lines.hit = Number(parts[1].trim());
break;
case 'DA':
lines = parts[1].split(',');
item.lines.details.push({
line: Number(lines[0]),
hit: Number(lines[1])
});
break;
case 'FN':
fn = parts[1].split(',');
item.functions.details.push({
name: fn[1],
line: Number(fn[0])
});
break;
case 'FNDA':
fn = parts[1].split(',');
item.functions.details.some(function(i, k) {
if (i.name === fn[1] && i.hit === undefined) {
item.functions.details[k].hit = Number(fn[0]);
return true;
}
});
break;
case 'BRDA':
fn = parts[1].split(',');
item.branches.details.push({
line: Number(fn[0]),
block: Number(fn[1]),
branch: Number(fn[2]),
taken: ((fn[3] === '-') ? 0 : Number(fn[3]))
});
break;
case 'BRF':
item.branches.found = Number(parts[1]);
break;
case 'BRH':
item.branches.hit = Number(parts[1]);
break;
}
if (line.indexOf('end_of_record') > -1) {
data.push(item);
item = {
lines: {
found: 0,
hit: 0,
details: []
},
functions: {
hit: 0,
found: 0,
details: []
},
branches: {
hit: 0,
found: 0,
details: []
}
};
}
});
data.shift();
if (data.length) {
cb(null, data);
} else {
cb('Failed to parse string');
}
};
var parse = function(file, cb) {
exists(file, function(x) {
if (!x) {
return walkFile(file, cb);
}
fs.readFile(file, 'utf8', function(err, str) {
walkFile(str, cb);
});
});
};
module.exports = parse;
module.exports.source = walkFile;
/***/ }), /***/ }),
/***/ 9662: /***/ 9662:
@@ -26750,21 +26887,31 @@ module.exports.CancelError = CancelError;
"use strict"; "use strict";
const os = __nccwpck_require__(2037);
const pico = __nccwpck_require__(3322); const pico = __nccwpck_require__(3322);
const utils = __nccwpck_require__(479);
const isWindows = os.platform() === 'win32';
function picomatch(glob, options, returnState = false) { function picomatch(glob, options, returnState = false) {
// default to os.platform() // default to os.platform()
if (options && (options.windows === null || options.windows === undefined)) { if (options && (options.windows === null || options.windows === undefined)) {
// don't mutate the original options object // don't mutate the original options object
options = { ...options, windows: utils.isWindows() }; options = { ...options, windows: isWindows };
} }
return pico(glob, options, returnState); return pico(glob, options, returnState);
} }
Object.assign(picomatch, pico);
module.exports = picomatch; module.exports = picomatch;
// public api
module.exports.test = pico.test;
module.exports.matchBase = pico.matchBase;
module.exports.isMatch = pico.isMatch;
module.exports.parse = pico.parse;
module.exports.scan = pico.scan;
module.exports.compileRe = pico.compileRe;
module.exports.toRegex = pico.toRegex;
// for tests
module.exports.makeRe = pico.makeRe;
/***/ }), /***/ }),
@@ -27171,8 +27318,8 @@ const parse = (input, options) => {
if (tok.value || tok.output) append(tok); if (tok.value || tok.output) append(tok);
if (prev && prev.type === 'text' && tok.type === 'text') { if (prev && prev.type === 'text' && tok.type === 'text') {
prev.output = (prev.output || prev.value) + tok.value;
prev.value += tok.value; prev.value += tok.value;
prev.output = (prev.output || '') + tok.value;
return; return;
} }
@@ -27660,6 +27807,10 @@ const parse = (input, options) => {
const next = peek(); const next = peek();
let output = value; let output = value;
if (next === '<' && !utils.supportsLookbehinds()) {
throw new Error('Node.js v10 or higher is required for regex lookbehinds');
}
if ((prev.value === '(' && !/[!=<:]/.test(next)) || (next === '<' && !/<([!=]|\w+>)/.test(remaining()))) { if ((prev.value === '(' && !/[!=<:]/.test(next)) || (next === '<' && !/<([!=]|\w+>)/.test(remaining()))) {
output = `\\${value}`; output = `\\${value}`;
} }
@@ -28801,7 +28952,6 @@ module.exports = scan;
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
"use strict"; "use strict";
/*global navigator*/
const { const {
@@ -28817,25 +28967,22 @@ exports.isRegexChar = str => str.length === 1 && exports.hasRegexChars(str);
exports.escapeRegex = str => str.replace(REGEX_SPECIAL_CHARS_GLOBAL, '\\$1'); exports.escapeRegex = str => str.replace(REGEX_SPECIAL_CHARS_GLOBAL, '\\$1');
exports.toPosixSlashes = str => str.replace(REGEX_BACKSLASH, '/'); exports.toPosixSlashes = str => str.replace(REGEX_BACKSLASH, '/');
exports.isWindows = () => {
if (typeof navigator !== 'undefined' && navigator.platform) {
const platform = navigator.platform.toLowerCase();
return platform === 'win32' || platform === 'windows';
}
if (typeof process !== 'undefined' && process.platform) {
return process.platform === 'win32';
}
return false;
};
exports.removeBackslashes = str => { exports.removeBackslashes = str => {
return str.replace(REGEX_REMOVE_BACKSLASH, match => { return str.replace(REGEX_REMOVE_BACKSLASH, match => {
return match === '\\' ? '' : match; return match === '\\' ? '' : match;
}); });
}; };
exports.supportsLookbehinds = () => {
if (typeof process !== 'undefined') {
const segs = process.version.slice(1).split('.').map(Number);
if (segs.length === 3 && segs[0] >= 9 || (segs[0] === 8 && segs[1] >= 10)) {
return true;
}
}
return false;
};
exports.escapeLast = (input, char, lastIdx) => { exports.escapeLast = (input, char, lastIdx) => {
const idx = input.lastIndexOf(char, lastIdx); const idx = input.lastIndexOf(char, lastIdx);
if (idx === -1) return input; if (idx === -1) return input;

29
dist/licenses.txt generated vendored
View File

@@ -1053,6 +1053,35 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keyv keyv
MIT MIT
lcov-parse
BSD-3-Clause
Copyright 2012 Yahoo! Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Yahoo! Inc. nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL YAHOO! INC. BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
lowercase-keys lowercase-keys
MIT MIT
MIT License MIT License

905
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{ {
"name": "test-reporter", "name": "test-check",
"version": "1.9.1", "version": "1.7.0",
"private": true, "private": true,
"description": "Presents test results from popular testing frameworks as Github check run", "description": "Presents test results from popular testing frameworks as Github check run",
"main": "lib/main.js", "main": "lib/main.js",
@@ -21,7 +21,7 @@
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/dorny/test-reporter.git" "url": "git+https://github.com/dorny/test-check.git"
}, },
"keywords": [ "keywords": [
"actions", "actions",
@@ -35,39 +35,41 @@
"@actions/core": "^1.10.1", "@actions/core": "^1.10.1",
"@actions/exec": "^1.1.1", "@actions/exec": "^1.1.1",
"@actions/github": "^6.0.0", "@actions/github": "^6.0.0",
"adm-zip": "^0.5.12", "adm-zip": "^0.5.10",
"fast-glob": "^3.3.2", "fast-glob": "^3.3.2",
"got": "^11.8.6", "got": "^11.8.2",
"picomatch": "^4.0.2", "lcov-parse": "^1.0.0",
"picomatch": "^3.0.1",
"xml2js": "^0.6.2" "xml2js": "^0.6.2"
}, },
"devDependencies": { "devDependencies": {
"@octokit/types": "^12.4.0", "@octokit/types": "^12.4.0",
"@octokit/webhooks": "^12.0.11", "@octokit/webhooks": "^12.0.10",
"@octokit/webhooks-types": "^7.3.1", "@octokit/webhooks-types": "^7.3.1",
"@types/adm-zip": "^0.5.5", "@types/adm-zip": "^0.5.5",
"@types/github-slugger": "^1.3.0", "@types/github-slugger": "^1.3.0",
"@types/jest": "^29.5.12", "@types/jest": "^29.5.11",
"@types/node": "^18.19.32", "@types/lcov-parse": "^1.0.2",
"@types/node": "^20.10.4",
"@types/picomatch": "^2.3.3", "@types/picomatch": "^2.3.3",
"@types/xml2js": "^0.4.14", "@types/xml2js": "^0.4.14",
"@typescript-eslint/eslint-plugin": "^7.8.0", "@typescript-eslint/eslint-plugin": "^6.14.0",
"@typescript-eslint/parser": "^7.8.0", "@typescript-eslint/parser": "^6.14.0",
"@vercel/ncc": "^0.38.1", "@vercel/ncc": "^0.38.1",
"eol-converter-cli": "^1.0.8", "eol-converter-cli": "^1.0.8",
"eslint": "^8.57.0", "eslint": "^8.55.0",
"eslint-import-resolver-typescript": "^3.6.1", "eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-github": "^4.10.2", "eslint-plugin-github": "^4.10.1",
"eslint-plugin-import": "^2.29.1", "eslint-plugin-import": "^2.29.0",
"eslint-plugin-jest": "^27.9.0", "eslint-plugin-jest": "^27.6.0",
"eslint-plugin-prettier": "^5.1.3", "eslint-plugin-prettier": "^5.0.1",
"jest": "^29.7.0", "jest": "^29.7.0",
"jest-circus": "^29.7.0", "jest-circus": "^29.7.0",
"jest-junit": "^16.0.0", "jest-junit": "^16.0.0",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"prettier": "^3.2.5", "prettier": "^3.1.1",
"ts-jest": "^29.1.2", "ts-jest": "^29.1.1",
"typescript": "^5.4.5" "typescript": "^5.3.3"
}, },
"jest-junit": { "jest-junit": {
"suiteName": "jest tests", "suiteName": "jest tests",

View File

@@ -5,377 +5,344 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: _fe_analyzer_shared name: _fe_analyzer_shared
sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "67.0.0" version: "11.0.0"
analyzer: analyzer:
dependency: transitive dependency: transitive
description: description:
name: analyzer name: analyzer
sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "6.4.1" version: "0.40.4"
args: args:
dependency: transitive dependency: transitive
description: description:
name: args name: args
sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.5.0" version: "1.6.0"
async: async:
dependency: transitive dependency: transitive
description: description:
name: async name: async
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.11.0" version: "2.4.2"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
name: boolean_selector name: boolean_selector
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.0.0"
charcode:
dependency: transitive
description:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.3"
cli_util:
dependency: transitive
description:
name: cli_util
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0"
collection: collection:
dependency: transitive dependency: transitive
description: description:
name: collection name: collection
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.18.0" version: "1.14.13"
convert: convert:
dependency: transitive dependency: transitive
description: description:
name: convert name: convert
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.1" version: "2.1.1"
coverage: coverage:
dependency: transitive dependency: transitive
description: description:
name: coverage name: coverage
sha256: "8acabb8306b57a409bf4c83522065672ee13179297a6bb0cb9ead73948df7c76" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.7.2" version: "0.14.1"
crypto: crypto:
dependency: transitive dependency: transitive
description: description:
name: crypto name: crypto
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.3" version: "2.1.5"
file:
dependency: transitive
description:
name: file
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
url: "https://pub.dev"
source: hosted
version: "7.0.0"
frontend_server_client:
dependency: transitive
description:
name: frontend_server_client
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
url: "https://pub.dev"
source: hosted
version: "4.0.0"
glob: glob:
dependency: transitive dependency: transitive
description: description:
name: glob name: glob
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.2" version: "1.2.0"
http:
dependency: transitive
description:
name: http
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.2"
http_multi_server: http_multi_server:
dependency: transitive dependency: transitive
description: description:
name: http_multi_server name: http_multi_server
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "3.2.1" version: "2.2.0"
http_parser: http_parser:
dependency: transitive dependency: transitive
description: description:
name: http_parser name: http_parser
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.2" version: "3.1.4"
io: io:
dependency: transitive dependency: transitive
description: description:
name: io name: io
sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.4" version: "0.3.4"
js: js:
dependency: transitive dependency: transitive
description: description:
name: js name: js
sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.1" version: "0.6.2"
logging: logging:
dependency: transitive dependency: transitive
description: description:
name: logging name: logging
sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.0" version: "0.11.4"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "0.12.16+1" version: "0.12.9"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: "25dfcaf170a0190f47ca6355bdd4552cb8924b430512ff0cafb8db9bd41fe33b" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.14.0" version: "1.2.3"
mime: mime:
dependency: transitive dependency: transitive
description: description:
name: mime name: mime
sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.5" version: "0.9.7"
node_interop:
dependency: transitive
description:
name: node_interop
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
node_io:
dependency: transitive
description:
name: node_io
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
node_preamble: node_preamble:
dependency: transitive dependency: transitive
description: description:
name: node_preamble name: node_preamble
sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.2" version: "1.4.12"
package_config: package_config:
dependency: transitive dependency: transitive
description: description:
name: package_config name: package_config
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.0" version: "1.9.3"
path: path:
dependency: transitive dependency: transitive
description: description:
name: path name: path
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.9.0" version: "1.7.0"
pedantic: pedantic:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: pedantic name: pedantic
sha256: "67fc27ed9639506c856c840ccce7594d0bdcd91bc8d53d6e52359449a1d50602" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.11.1" version: "1.9.2"
pool: pool:
dependency: transitive dependency: transitive
description: description:
name: pool name: pool
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.5.1" version: "1.4.0"
pub_semver: pub_semver:
dependency: transitive dependency: transitive
description: description:
name: pub_semver name: pub_semver
sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.4" version: "1.4.4"
shelf: shelf:
dependency: transitive dependency: transitive
description: description:
name: shelf name: shelf
sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.4.1" version: "0.7.9"
shelf_packages_handler: shelf_packages_handler:
dependency: transitive dependency: transitive
description: description:
name: shelf_packages_handler name: shelf_packages_handler
sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.2" version: "2.0.0"
shelf_static: shelf_static:
dependency: transitive dependency: transitive
description: description:
name: shelf_static name: shelf_static
sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.2" version: "0.2.8"
shelf_web_socket: shelf_web_socket:
dependency: transitive dependency: transitive
description: description:
name: shelf_web_socket name: shelf_web_socket
sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.4" version: "0.2.3"
source_map_stack_trace: source_map_stack_trace:
dependency: transitive dependency: transitive
description: description:
name: source_map_stack_trace name: source_map_stack_trace
sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.0.0"
source_maps: source_maps:
dependency: transitive dependency: transitive
description: description:
name: source_maps name: source_maps
sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "0.10.12" version: "0.10.9"
source_span: source_span:
dependency: transitive dependency: transitive
description: description:
name: source_span name: source_span
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.10.0" version: "1.7.0"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
name: stack_trace name: stack_trace
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.11.1" version: "1.9.5"
stream_channel: stream_channel:
dependency: transitive dependency: transitive
description: description:
name: stream_channel name: stream_channel
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.2" version: "2.0.0"
string_scanner: string_scanner:
dependency: transitive dependency: transitive
description: description:
name: string_scanner name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.0" version: "1.0.5"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:
name: term_glyph name: term_glyph
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.1" version: "1.1.0"
test: test:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: test name: test
sha256: d87214d19fb311997d8128ec501a980f77cb240ac4e7e219accf452813ff473c url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.25.3" version: "1.15.4"
test_api: test_api:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: "2419f20b0c8677b2d67c8ac4d1ac7372d862dc6c460cdbb052b40155408cd794" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.1" version: "0.2.18"
test_core: test_core:
dependency: transitive dependency: transitive
description: description:
name: test_core name: test_core
sha256: "2236f70be1e5ab405c675e88c36935a87dad9e05a506b57dd5c0f617f5aebcb2" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "0.6.1" version: "0.3.11+1"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
name: typed_data name: typed_data
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.2" version: "1.2.0"
vm_service: vm_service:
dependency: transitive dependency: transitive
description: description:
name: vm_service name: vm_service
sha256: a75f83f14ad81d5fe4b3319710b90dec37da0e22612326b696c9e1b8f34bbf48 url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "14.2.0" version: "4.2.0"
watcher: watcher:
dependency: transitive dependency: transitive
description: description:
name: watcher name: watcher
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "0.9.7+15"
web:
dependency: transitive
description:
name: web
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
url: "https://pub.dev"
source: hosted
version: "0.5.1"
web_socket_channel: web_socket_channel:
dependency: transitive dependency: transitive
description: description:
name: web_socket_channel name: web_socket_channel
sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.5" version: "1.1.0"
webkit_inspection_protocol: webkit_inspection_protocol:
dependency: transitive dependency: transitive
description: description:
name: webkit_inspection_protocol name: webkit_inspection_protocol
sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.1" version: "0.7.3"
yaml: yaml:
dependency: transitive dependency: transitive
description: description:
name: yaml name: yaml
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.2" version: "2.2.1"
sdks: sdks:
dart: ">=3.3.0 <4.0.0" dart: ">=2.8.1 <3.0.0"

View File

@@ -2,7 +2,7 @@ name: darttest
description: A simple command-line application. description: A simple command-line application.
environment: environment:
sdk: '>=2.12.0 <3.0.0' sdk: '>=2.8.1 <3.0.0'
dev_dependencies: dev_dependencies:
pedantic: ^1.9.0 pedantic: ^1.9.0

View File

@@ -15,11 +15,11 @@ import {DotnetTrxParser} from './parsers/dotnet-trx/dotnet-trx-parser'
import {JavaJunitParser} from './parsers/java-junit/java-junit-parser' import {JavaJunitParser} from './parsers/java-junit/java-junit-parser'
import {JestJunitParser} from './parsers/jest-junit/jest-junit-parser' import {JestJunitParser} from './parsers/jest-junit/jest-junit-parser'
import {MochaJsonParser} from './parsers/mocha-json/mocha-json-parser' import {MochaJsonParser} from './parsers/mocha-json/mocha-json-parser'
import {RspecJsonParser} from './parsers/rspec-json/rspec-json-parser'
import {SwiftXunitParser} from './parsers/swift-xunit/swift-xunit-parser' import {SwiftXunitParser} from './parsers/swift-xunit/swift-xunit-parser'
import {normalizeDirPath, normalizeFilePath} from './utils/path-utils' import {normalizeDirPath, normalizeFilePath} from './utils/path-utils'
import {getCheckRunContext} from './utils/github-utils' import {getCheckRunContext} from './utils/github-utils'
import {LcovParser} from './parsers/lcov/lcov-parser'
async function main(): Promise<void> { async function main(): Promise<void> {
try { try {
@@ -224,10 +224,10 @@ class TestReporter {
return new JestJunitParser(options) return new JestJunitParser(options)
case 'mocha-json': case 'mocha-json':
return new MochaJsonParser(options) return new MochaJsonParser(options)
case 'rspec-json':
return new RspecJsonParser(options)
case 'swift-xunit': case 'swift-xunit':
return new SwiftXunitParser(options) return new SwiftXunitParser(options)
case 'lcov':
return new LcovParser(options)
default: default:
throw new Error(`Input variable 'reporter' is set to invalid value '${reporter}'`) throw new Error(`Input variable 'reporter' is set to invalid value '${reporter}'`)
} }

View File

@@ -123,7 +123,7 @@ export class DartJsonParser implements TestParser {
const group = suite.groups[evt.test.groupIDs[evt.test.groupIDs.length - 1]] const group = suite.groups[evt.test.groupIDs[evt.test.groupIDs.length - 1]]
group.tests.push(test) group.tests.push(test)
tests[evt.test.id] = test tests[evt.test.id] = test
} else if (isTestDoneEvent(evt) && tests[evt.testID]) { } else if (isTestDoneEvent(evt) && !evt.hidden && tests[evt.testID]) {
tests[evt.testID].testDone = evt tests[evt.testID].testDone = evt
} else if (isErrorEvent(evt) && tests[evt.testID]) { } else if (isErrorEvent(evt) && tests[evt.testID]) {
tests[evt.testID].error = evt tests[evt.testID].error = evt
@@ -152,16 +152,14 @@ export class DartJsonParser implements TestParser {
return groups.map(group => { return groups.map(group => {
group.tests.sort((a, b) => (a.testStart.test.line ?? 0) - (b.testStart.test.line ?? 0)) group.tests.sort((a, b) => (a.testStart.test.line ?? 0) - (b.testStart.test.line ?? 0))
const tests = group.tests const tests = group.tests.map(tc => {
.filter(tc => !tc.testDone?.hidden) const error = this.getError(suite, tc)
.map(tc => { const testName =
const error = this.getError(suite, tc) group.group.name !== undefined && tc.testStart.test.name.startsWith(group.group.name)
const testName = ? tc.testStart.test.name.slice(group.group.name.length).trim()
group.group.name !== undefined && tc.testStart.test.name.startsWith(group.group.name) : tc.testStart.test.name.trim()
? tc.testStart.test.name.slice(group.group.name.length).trim() return new TestCaseResult(testName, tc.result, tc.time, error)
: tc.testStart.test.name.trim() })
return new TestCaseResult(testName, tc.result, tc.time, error)
})
return new TestGroupResult(group.group.name, tests) return new TestGroupResult(group.group.name, tests)
}) })
} }

View File

@@ -0,0 +1,59 @@
import {ParseOptions, TestParser} from '../../test-parser'
import {TestCaseResult, TestGroupResult, TestRunResult, TestSuiteResult} from '../../test-results'
import {parseProm} from './lcov-utils'
import {LcovBranch, LcovFile, LcovFunc, LcovLine, LcovPart} from 'lcov-parse'
export class LcovParser implements TestParser {
constructor(readonly options: ParseOptions) {}
async parse(path: string, content: string): Promise<TestRunResult> {
const report = await this.parseFile(path, content)
return this.getTestRunResult(path, report)
}
private async parseFile(path: string, content: string): Promise<LcovFile[]> {
try {
return parseProm(content)
//return JSON.parse(content) as LcovReport
} catch (e) {
throw new Error(`Invalid JSON at ${path}\n\n${e}`)
}
}
private async getTestRunResult(path: string, report: LcovFile[]): Promise<TestRunResult> {
const suites: TestSuiteResult[] = []
for (const reportElement of report) {
const fileName = reportElement.file
const statementCaseResult: TestCaseResult = {
name: `lines ${this.getPartInfo(reportElement.lines)}`,
time: 0,
result: this.getPercentage(reportElement.lines) >= 80 ? 'success' : 'failed'
}
const fonctionCaseResult: TestCaseResult = {
name: `functions ${this.getPartInfo(reportElement.functions)}`,
time: 0,
result: this.getPercentage(reportElement.functions) >= 80 ? 'success' : 'failed'
}
const brancheCaseResult: TestCaseResult = {
name: `branches ${this.getPartInfo(reportElement.branches)}`,
time: 0,
result: this.getPercentage(reportElement.branches) >= 80 ? 'success' : 'failed'
}
const testCases: TestCaseResult[] = [statementCaseResult, fonctionCaseResult, brancheCaseResult]
const groups: TestGroupResult[] = [new TestGroupResult(fileName, testCases)]
const suite: TestSuiteResult = new TestSuiteResult(fileName, groups)
suites.push(suite)
}
return new TestRunResult(path, suites)
}
private getPercentage(stat: LcovPart<LcovLine | LcovFunc | LcovBranch>): number {
return stat ? (stat.hit / stat.found) * 100 : 100
}
private getPartInfo(stat: LcovPart<LcovLine | LcovFunc | LcovBranch>): string {
return `${this.getPercentage(stat)}% (${stat.hit}/${stat.found})`
}
}

View File

@@ -0,0 +1,21 @@
export interface LcovReport {
[str: string]: {
path: string
statementMap: unknown
fnMap: unknown
branchMap: unknown
s: CovStats
f: CovStats
b: CovStats
}
}
export interface CovStats {
[str: string]: number
}
export interface CovParsedStat {
max: number
nonCovered: number
percentage: number
}

View File

@@ -0,0 +1,14 @@
import parse, {LcovFile} from 'lcov-parse'
const parseProm = async (pathOrStr: string): Promise<LcovFile[]> => {
return new Promise((resolve, reject) => {
parse(pathOrStr, (err, data) => {
if (err) {
reject(err)
}
resolve(data ?? [])
})
})
}
export {parseProm}

View File

@@ -1,113 +0,0 @@
import { Console } from 'console'
import {ParseOptions, TestParser} from '../../test-parser'
import {
TestCaseError,
TestCaseResult,
TestExecutionResult,
TestGroupResult,
TestRunResult,
TestSuiteResult
} from '../../test-results'
import {RspecJson, RspecExample} from './rspec-json-types'
export class RspecJsonParser implements TestParser {
assumedWorkDir: string | undefined
constructor(readonly options: ParseOptions) {}
async parse(path: string, content: string): Promise<TestRunResult> {
const mocha = this.getRspecJson(path, content)
const result = this.getTestRunResult(path, mocha)
result.sort(true)
return Promise.resolve(result)
}
private getRspecJson(path: string, content: string): RspecJson {
try {
return JSON.parse(content)
} catch (e) {
throw new Error(`Invalid JSON at ${path}\n\n${e}`)
}
}
private getTestRunResult(resultsPath: string, rspec: RspecJson): TestRunResult {
const suitesMap: {[path: string]: TestSuiteResult} = {}
const getSuite = (test: RspecExample): TestSuiteResult => {
const path = test.file_path
return suitesMap[path] ?? (suitesMap[path] = new TestSuiteResult(path, []))
}
for (const test of rspec.examples) {
const suite = getSuite(test)
if (test.status === 'failed') {
this.processTest(suite, test, 'failed')
} else if (test.status === 'passed') {
this.processTest(suite, test, 'success')
} else if (test.status === 'pending') {
this.processTest(suite, test, 'skipped')
}
}
const suites = Object.values(suitesMap)
return new TestRunResult(resultsPath, suites, rspec.summary.duration)
}
private processTest(suite: TestSuiteResult, test: RspecExample, result: TestExecutionResult): void {
const groupName =
test.full_description !== test.description
? test.full_description.substr(0, test.full_description.length - test.description.length).trimEnd()
: null
let group = suite.groups.find(grp => grp.name === groupName)
if (group === undefined) {
group = new TestGroupResult(groupName, [])
suite.groups.push(group)
}
const error = this.getTestCaseError(test)
const testCase = new TestCaseResult(test.full_description, result, test.run_time ?? 0, error)
group.tests.push(testCase)
}
private getTestCaseError(test: RspecExample): TestCaseError | undefined {
const backtrace = test.exception?.backtrace
const message = test.exception?.message
if (backtrace === undefined) {
return undefined
}
let path
let line
const details = backtrace.join('\n')
const src = this.getExceptionSource(backtrace)
if (src) {
path = src.path
line = src.line
}
return {
path,
line,
message,
details
}
}
private getExceptionSource(backtrace: string[]): {path: string; line: number} | undefined {
const re = /^(.*?):(\d+):/
for (const str of backtrace) {
const match = str.match(re)
if (match !== null) {
const [_, path, lineStr] = match
if (path.startsWith('./')) {
const line = parseInt(lineStr)
return {path, line}
}
}
}
return undefined
}
}

View File

@@ -1,34 +0,0 @@
export interface RspecJson {
version: number
examples: RspecExample[]
summary: RspecSummary
summary_line: string
}
export interface RspecExample {
id: string
description: string
full_description: string
status: TestStatus
file_path: string
line_number: number
run_time: number
pending_message: string | null
exception?: RspecException
}
type TestStatus = 'passed' | 'failed' | 'pending';
export interface RspecException {
class: string
message: string
backtrace: string[]
}
export interface RspecSummary {
duration: number
example_count: number
failure_count: number
pending_count: number
errors_outside_of_examples_count: number
}

View File

@@ -50,17 +50,33 @@ export async function downloadArtifact(
const headers = { const headers = {
Authorization: `Bearer ${token}` Authorization: `Bearer ${token}`
} }
const resp = await got(req.url, {
headers,
followRedirect: false
})
const downloadStream = got.stream(req.url, {headers}) core.info(`Fetch artifact URL: ${resp.statusCode} ${resp.statusMessage}`)
if (resp.statusCode !== 302) {
throw new Error('Fetch artifact URL failed: received unexpected status code')
}
const url = resp.headers.location
if (url === undefined) {
const receivedHeaders = Object.keys(resp.headers)
core.info(`Received headers: ${receivedHeaders.join(', ')}`)
throw new Error('Location header was not found in API response')
}
if (typeof url !== 'string') {
throw new Error(`Location header has unexpected value: ${url}`)
}
const downloadStream = got.stream(url, {headers})
const fileWriterStream = createWriteStream(fileName) const fileWriterStream = createWriteStream(fileName)
downloadStream.on('redirect', response => { core.info(`Downloading ${url}`)
core.info(`Downloading ${response.headers.location}`)
})
downloadStream.on('downloadProgress', ({transferred}) => { downloadStream.on('downloadProgress', ({transferred}) => {
core.info(`Progress: ${transferred} B`) core.info(`Progress: ${transferred} B`)
}) })
await asyncStream(downloadStream, fileWriterStream) await asyncStream(downloadStream, fileWriterStream)
} finally { } finally {
core.endGroup() core.endGroup()