diff --git a/qlty-cli/src/commands/coverage/publish.rs b/qlty-cli/src/commands/coverage/publish.rs index 52aca7de..6c97a01c 100644 --- a/qlty-cli/src/commands/coverage/publish.rs +++ b/qlty-cli/src/commands/coverage/publish.rs @@ -80,6 +80,10 @@ pub struct Publish { // Paths to coverage reports pub paths: Vec, + + #[arg(long)] + /// Check if the files in the coverage report actually exist on the file system + pub files_exist: bool, } impl Publish { @@ -108,6 +112,7 @@ impl Publish { tag: self.tag.clone(), report_format: self.report_format, paths: self.paths.clone(), + files_exist: self.files_exist, }, ) .compute()?; @@ -310,6 +315,7 @@ mod tests { json: false, quiet: true, paths: vec![], + files_exist: false, } } diff --git a/qlty-cli/tests/cmd/coverage/files_exist.in/.gitattributes b/qlty-cli/tests/cmd/coverage/files_exist.in/.gitattributes new file mode 100644 index 00000000..fcadb2cf --- /dev/null +++ b/qlty-cli/tests/cmd/coverage/files_exist.in/.gitattributes @@ -0,0 +1 @@ +* text eol=lf diff --git a/qlty-cli/tests/cmd/coverage/files_exist.in/.gitignore b/qlty-cli/tests/cmd/coverage/files_exist.in/.gitignore new file mode 100644 index 00000000..73ce7051 --- /dev/null +++ b/qlty-cli/tests/cmd/coverage/files_exist.in/.gitignore @@ -0,0 +1,5 @@ +.qlty/results +.qlty/logs +.qlty/out +.qlty/sources +tmp diff --git a/qlty-cli/tests/cmd/coverage/files_exist.in/lcov.info b/qlty-cli/tests/cmd/coverage/files_exist.in/lcov.info new file mode 100644 index 00000000..c48858ee --- /dev/null +++ b/qlty-cli/tests/cmd/coverage/files_exist.in/lcov.info @@ -0,0 +1,76 @@ +TN: +SF:src/formatter.js +FN:10,Formatter +FN:14,(anonymous_2) +FN:18,(anonymous_3) +FN:28,(anonymous_4) +FN:31,(anonymous_5) +FN:51,(anonymous_6) +FN:65,(anonymous_7) +FN:68,(anonymous_8) +FN:83,(anonymous_9) +FN:86,(anonymous_10) +FNF:10 +FNH:10 +FNDA:1,Formatter +FNDA:5,(anonymous_2) +FNDA:2,(anonymous_3) +FNDA:2,(anonymous_4) +FNDA:2,(anonymous_5) +FNDA:2,(anonymous_6) +FNDA:2,(anonymous_7) +FNDA:5,(anonymous_8) +FNDA:5,(anonymous_9) +FNDA:817,(anonymous_10) +DA:1,1 +DA:2,1 +DA:3,1 +DA:4,1 +DA:5,1 +DA:6,1 +DA:7,1 +DA:8,1 +DA:10,1 +DA:11,1 +DA:14,1 +DA:15,5 +DA:18,1 +DA:19,2 +DA:20,1 +DA:21,1 +DA:22,1 +DA:24,0 +DA:28,1 +DA:29,2 +DA:31,2 +DA:32,2 +DA:33,0 +DA:36,2 +DA:46,2 +DA:52,2 +LF:52 +LH:47 +BRDA:11,1,0,1 +BRDA:11,1,1,0 +BRDA:15,2,0,5 +BRDA:15,2,1,0 +BRDA:19,3,0,1 +BRDA:19,3,1,1 +BRDA:21,4,0,1 +BRDA:21,4,1,0 +BRDA:32,5,0,0 +BRDA:32,5,1,2 +BRDA:52,6,0,0 +BRDA:52,6,1,2 +BRDA:73,7,0,5 +BRDA:73,7,1,0 +BRDA:91,8,0,0 +BRDA:91,8,1,5 +BRF:16 +BRH:9 +end_of_record +SF:src/doesnt_exist.js +DA:1,1 +DA:2,0 +DA:5,10 +end_of_record diff --git a/qlty-cli/tests/cmd/coverage/files_exist.in/src/formatter.js b/qlty-cli/tests/cmd/coverage/files_exist.in/src/formatter.js new file mode 100644 index 00000000..e69de29b diff --git a/qlty-cli/tests/cmd/coverage/files_exist.stderr b/qlty-cli/tests/cmd/coverage/files_exist.stderr new file mode 100644 index 00000000..a9aff5fa --- /dev/null +++ b/qlty-cli/tests/cmd/coverage/files_exist.stderr @@ -0,0 +1,11 @@ +qlty [..] [..]-[..] ([..] debug [..]) +https://qlty.sh/d/coverage + + Retrieving CI metadata... + → unknown CI commit "2ca1bc45a94e37c8dbae6fd9e19fc069ba64bd67" on branch "" + + Reading code coverage data... + → Found 1 files with code coverage data + + Exporting code coverage data... + → Exported to "tmp/qlty-coverage" diff --git a/qlty-cli/tests/cmd/coverage/files_exist.stdout b/qlty-cli/tests/cmd/coverage/files_exist.stdout new file mode 100644 index 00000000..8250353f --- /dev/null +++ b/qlty-cli/tests/cmd/coverage/files_exist.stdout @@ -0,0 +1,91 @@ +{ + "metadata": { + "buildId": "123", + "ci": "unknown", + "commitSha": "2ca1bc45a94e37c8dbae6fd9e19fc069ba64bd67", + "commitMessage": "initial/n", + "authorName": "TEST", + "authorEmail": "test@codeclimate.com", + "authorTime": "2024-01-01T00:00:00+00:00", + "committerName": "TEST", + "committerEmail": "test@codeclimate.com", + "commitTime": "2024-01-01T00:00:00+00:00", + "uploadedAt": "[..]", + "cliVersion": "[..]" + }, + "report_files": [ + { + "buildId": "123", + "format": "lcov", + "path": "lcov.info" + } + ], + "file_coverages": [ + { + "buildId": "123", + "path": "src/formatter.js", + "summary": { + "covered": "24", + "missed": "2", + "omit": "26", + "total": "52" + }, + "hits": [ + "1", + "1", + "1", + "1", + "1", + "1", + "1", + "1", + "-1", + "1", + "1", + "-1", + "-1", + "1", + "5", + "-1", + "-1", + "1", + "2", + "1", + "1", + "1", + "-1", + "0", + "-1", + "-1", + "-1", + "1", + "2", + "-1", + "2", + "2", + "0", + "-1", + "-1", + "2", + "-1", + "-1", + "-1", + "-1", + "-1", + "-1", + "-1", + "-1", + "-1", + "2", + "-1", + "-1", + "-1", + "-1", + "-1", + "2" + ], + "commitSha": "2ca1bc45a94e37c8dbae6fd9e19fc069ba64bd67", + "uploadedAt": "[..]" + } + ] +} diff --git a/qlty-cli/tests/cmd/coverage/files_exist.toml b/qlty-cli/tests/cmd/coverage/files_exist.toml new file mode 100644 index 00000000..e8da8406 --- /dev/null +++ b/qlty-cli/tests/cmd/coverage/files_exist.toml @@ -0,0 +1,20 @@ +args = [ + "coverage", + "publish", + "--dry-run", + "--override-commit-sha", + "2ca1bc45a94e37c8dbae6fd9e19fc069ba64bd67", + "--override-build-id", + "123", + "lcov.info", + "--print", + "--json", + "--files-exist" +] +bin.name = "qlty" + +[env] +remove = ["GITHUB_ACTIONS"] + +[env.add] +QLTY_COVERAGE_TOKEN = "123" diff --git a/qlty-cli/tests/cmd/coverage/ignore_patterns.in/lcov.info b/qlty-cli/tests/cmd/coverage/ignore_patterns.in/lcov.info index 5908cf30..2ac24695 100644 --- a/qlty-cli/tests/cmd/coverage/ignore_patterns.in/lcov.info +++ b/qlty-cli/tests/cmd/coverage/ignore_patterns.in/lcov.info @@ -68,6 +68,7 @@ BRDA:91,8,0,0 BRDA:91,8,1,5 BRF:16 BRH:9 +end_of_record SF:src/ignore.js DA:1,1 DA:2,0 diff --git a/qlty-coverage/src/publish/planner.rs b/qlty-coverage/src/publish/planner.rs index 9bdab669..7104d2ac 100644 --- a/qlty-coverage/src/publish/planner.rs +++ b/qlty-coverage/src/publish/planner.rs @@ -4,6 +4,7 @@ use crate::publish::Settings; use crate::transformer::AddPrefix; use crate::transformer::AppendMetadata; use crate::transformer::ComputeSummary; +use crate::transformer::FileExistanceCheck; use crate::transformer::IgnorePaths; use crate::transformer::StripDotSlashPrefix; use crate::transformer::StripPrefix; @@ -145,6 +146,11 @@ impl Planner { transformers.push(Box::new(AddPrefix::new(&prefix))); } + // Should be placed after AddPrefix/StripPrefix or any path changes + if self.settings.files_exist { + transformers.push(Box::new(FileExistanceCheck)); + } + transformers.push(Box::new(AppendMetadata::new(metadata))); Ok(transformers) } diff --git a/qlty-coverage/src/publish/settings.rs b/qlty-coverage/src/publish/settings.rs index b21025c0..66b550bc 100644 --- a/qlty-coverage/src/publish/settings.rs +++ b/qlty-coverage/src/publish/settings.rs @@ -16,4 +16,6 @@ pub struct Settings { pub add_prefix: Option, pub strip_prefix: Option, + + pub files_exist: bool, } diff --git a/qlty-coverage/src/transformer.rs b/qlty-coverage/src/transformer.rs index a4bfb116..fc260733 100644 --- a/qlty-coverage/src/transformer.rs +++ b/qlty-coverage/src/transformer.rs @@ -200,6 +200,22 @@ impl Transformer for StripDotSlashPrefix { } } +#[derive(Debug, Clone)] +pub struct FileExistanceCheck; + +impl Transformer for FileExistanceCheck { + fn transform(&self, file_coverage: FileCoverage) -> Option { + match PathBuf::from(&file_coverage.path).try_exists() { + Ok(true) => Some(file_coverage), + _ => None, + } + } + + fn clone_box(&self) -> Box { + Box::new(Self) + } +} + #[cfg(test)] mod tests { use super::*;