Skip to content

Commit

Permalink
feat(coverde): use optional filterd paths prefix (#69)
Browse files Browse the repository at this point in the history
* feat(coverde): prefix for filtered tested paths

* test(coverde): update `filter` command test

* chore: update scripts

* docs(coverde): update `filter` docs

* test(coverde): use mixed fixture root paths

* test(coverde): cross-platform-compatible test

* test(coverde): check stdout interaction

* refactor(coverde): absolute checking
  • Loading branch information
mrverdant13 committed Aug 17, 2023
1 parent ee3613b commit 22b6b5b
Show file tree
Hide file tree
Showing 15 changed files with 3,166 additions and 29 deletions.
10 changes: 5 additions & 5 deletions melos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ packages:
command:
clean:
hooks:
pre: melos exec -- "coverde rm .dart_tool pubspec_overrides.yaml pubspec.lock coverage"
pre: coverde rm .dart_tool coverage && melos exec -- "coverde rm .dart_tool pubspec_overrides.yaml pubspec.lock coverage"

scripts:
d:
Expand Down Expand Up @@ -74,7 +74,7 @@ scripts:
description: Run tests and generate coverage trace file for a selected package in random order.
run: >
dart test -x ci-only --coverage=coverage -r expanded --test-randomize-ordering-seed random --color &&
dart pub global run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info --packages=.dart_tool/package_config.json --report-on=lib
dart pub global run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info --report-on=lib -b MELOS_PACKAGE_PATH
exec:
concurrency: 1
orderDependents: true
Expand All @@ -85,21 +85,21 @@ scripts:
run: melos run t --no-select
T:ci:
description: Run tests and generate coverage trace files for all packages in random order.
run: melos exec --fail-fast --order-dependents --dir-exists=test -- "dart test -x ci-only --coverage=coverage -r expanded --test-randomize-ordering-seed random && dart pub global run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info --packages=.dart_tool/package_config.json --report-on=lib"
run: melos exec --fail-fast --order-dependents --dir-exists=test -- "dart test -x ci-only --coverage=coverage -r expanded --test-randomize-ordering-seed random && dart pub global run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info --report-on=lib -b MELOS_PACKAGE_PATH"

MC:
description: Merge all packages coverage trace files ignoring data related to generated files.
run: >
dart pub global activate --source path MELOS_ROOT_PATH/packages/coverde_cli/ &&
coverde rm MELOS_ROOT_PATH/coverage/filtered.lcov.info &&
melos exec --file-exists=coverage/lcov.info -- "coverde filter --input ./coverage/lcov.info --output MELOS_ROOT_PATH/coverage/filtered.lcov.info --filters '\.asset\.dart'" &&
melos exec --file-exists=coverage/lcov.info -- "coverde filter --input ./coverage/lcov.info --output MELOS_ROOT_PATH/coverage/filtered.lcov.info --paths-parent MELOS_PACKAGE_PATH --filters '\.asset\.dart'" &&
coverde check -i coverage/filtered.lcov.info 100
R:
description: Generate HTML coverage report.
run: >
dart pub global activate --source path MELOS_ROOT_PATH/packages/coverde_cli/ &&
coverde report --input ./coverage/lcov.info
coverde report --input ./coverage/filtered.lcov.info
FA:
description: Format and analyze.
Expand Down
19 changes: 10 additions & 9 deletions packages/coverde_cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,13 @@ $ dart pub global activate coverde

### Options

| Option | Description | Default value |
| :-----------------: | ------------------------------------------------------------------------------------------------------------------------- | :---------------------------: |
| `--input`<br>`-i` | Coverage trace file to be filtered. | `coverage/lcov.info` |
| `--output`<br>`-o` | Filtered coverage trace file (automatically created if it is absent). | `coverage/filtered.lcov.info` |
| `--filters`<br>`-f` | Set of comma-separated patterns of the files to be opted out of coverage. | |
| `--mode`<br>`-m` | The mode in which the filtered trace file content should be generated.<br>`a`: append content.<br>`w`: overwrite content. | `a` (append content) |
| Option | Description | Default value |
| :----------------------: | ------------------------------------------------------------------------------------------------------------------------- | :---------------------------: |
| `--input`<br>`-i` | Coverage trace file to be filtered. | `coverage/lcov.info` |
| `--output`<br>`-o` | Filtered coverage trace file (automatically created if it is absent). | `coverage/filtered.lcov.info` |
| `--paths-parent`<br>`-p` | Prefix of the resulting filtered paths. | |
| `--filters`<br>`-f` | Set of comma-separated patterns of the files to be opted out of coverage. | |
| `--mode`<br>`-m` | The mode in which the filtered trace file content should be generated.<br>`a`: append content.<br>`w`: overwrite content. | `a` (append content) |

### Examples

Expand Down Expand Up @@ -175,14 +176,14 @@ If your project uses melos to manage its multi-package structure, it could be ha
This can be achieved by defining a melos script as follows:

```yaml
M:
merge-trace-files:
description: Merge all packages coverage trace files ignoring data related to generated files.
run: >
coverde rm MELOS_ROOT_PATH/coverage/filtered.lcov.info &&
melos exec --file-exists=coverage/lcov.info -- coverde filter --input ./coverage/lcov.info --output MELOS_ROOT_PATH/coverage/filtered.lcov.info --filters '\.g\.dart'
melos exec --file-exists=coverage/lcov.info -- "coverde filter --input ./coverage/lcov.info --output MELOS_ROOT_PATH/coverage/filtered.lcov.info --paths-parent MELOS_PACKAGE_PATH --filters '\.g\.dart'"
```

`M` is the melos script that merges the coverage trace file of all tested packages contained within the project
`merge-trace-files` is the melos script that merges the coverage trace file of all tested packages contained within the project

This melos script ignores generated source files with the `.g.dart` extension but this behavior could be adjusted by setting the `--filters` option.

Expand Down
46 changes: 39 additions & 7 deletions packages/coverde_cli/lib/src/commands/filter/filter.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'package:args/command_runner.dart';
import 'package:coverde/src/entities/cov_file.dart';
import 'package:coverde/src/entities/trace_file.dart';
import 'package:coverde/src/utils/command.dart';
import 'package:coverde/src/utils/path.dart';
import 'package:meta/meta.dart';
import 'package:universal_io/io.dart';

Expand All @@ -27,6 +27,14 @@ Destination coverage info file to dump the resulting coverage data into.''',
defaultsTo: 'coverage/filtered.lcov.info',
valueHelp: _outputHelpValue,
)
..addOption(
pathsParentOption,
abbr: pathsParentOption[0],
help: '''
Path to be used to prefix all the paths in the resulting coverage trace file.''',
valueHelp: _pathsParentHelpValue,
mandatory: false,
)
..addMultiOption(
filtersOption,
abbr: filtersOption[0],
Expand All @@ -50,6 +58,7 @@ Set of comma-separated path patterns of the files to be ignored.''',

static const _inputHelpValue = 'INPUT_LCOV_FILE';
static const _outputHelpValue = 'OUTPUT_LCOV_FILE';
static const _pathsParentHelpValue = 'PATHS_PARENT';
static const _filtersHelpValue = 'FILTERS';
static const _modeHelpValue = 'MODE';
static const _outModeAllowedHelp = {
Expand All @@ -71,6 +80,13 @@ Override the $_outputHelpValue content, if any, with the filtered content.''',
@visibleForTesting
static const outputOption = 'output';

/// Option name for the paths parent to be used to prefix all the paths in the
/// resulting coverage trace file.
///
/// This option is optional.
@visibleForTesting
static const pathsParentOption = 'paths-parent';

/// Option name for the resulting filtered trace file.
@visibleForTesting
static const modeOption = 'mode';
Expand All @@ -80,7 +96,10 @@ Override the $_outputHelpValue content, if any, with the filtered content.''',
Filter a coverage trace file.
Filter the coverage info by ignoring data related to files with paths that matches the given $_filtersHelpValue.
The coverage data is taken from the $_inputHelpValue file and the result is appended to the $_outputHelpValue file.''';
The coverage data is taken from the $_inputHelpValue file and the result is appended to the $_outputHelpValue file.
All the relative paths in the resulting coverage trace file will be prefixed with $_pathsParentHelpValue, if provided.
If an absolute path is found in the coverage trace file, the process will fail.''';

@override
String get name => 'filter';
Expand All @@ -102,6 +121,9 @@ The coverage data is taken from the $_inputHelpValue file and the result is appe
optionKey: outputOption,
optionName: 'output trace file',
);
final pathsParent = checkOptionalOption(
optionKey: pathsParentOption,
);
final ignorePatterns = checkMultiOption(
multiOptionKey: filtersOption,
multiOptionName: 'ignored patterns list',
Expand All @@ -124,7 +146,7 @@ The coverage data is taken from the $_inputHelpValue file and the result is appe

// Parse trace file.
final traceFile = TraceFile.parse(initialContent);
final acceptedSrcFilesCovData = <CovFile>{};
final acceptedSrcFilesRawData = <String>{};

// For each file coverage data.
for (final fileCovData in traceFile.sourceFilesCovData) {
Expand All @@ -140,13 +162,23 @@ The coverage data is taken from the $_inputHelpValue file and the result is appe
if (shouldBeIgnored) {
_out.writeln('<${fileCovData.source.path}> coverage data ignored.');
} else {
acceptedSrcFilesCovData.add(fileCovData);
if (path.isAbsolute(fileCovData.source.path) && pathsParent != null) {
usageException(
'The `$pathsParentOption` option cannot be used with trace files'
'that contain absolute paths.',
);
}
final raw = pathsParent == null
? fileCovData.raw
: fileCovData.raw.replaceFirst(
RegExp(r'^SF:(.*)$', multiLine: true),
'SF:${path.join(pathsParent, fileCovData.source.path)}',
);
acceptedSrcFilesRawData.add(raw);
}
}

final finalContent = acceptedSrcFilesCovData
.map((srcFileCovData) => srcFileCovData.raw)
.join('\n');
final finalContent = acceptedSrcFilesRawData.join('\n');

// Generate destination file and its content.
destination
Expand Down
10 changes: 10 additions & 0 deletions packages/coverde_cli/lib/src/utils/command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ extension ExtendedCommand on Command {
return maybeOption;
}

/// Validate optional command option.
String? checkOptionalOption({
required String optionKey,
}) {
if (argResults == null) usageException('Missing arguments.');
final maybeOption = argResults![optionKey] as String?;
if (maybeOption == null || maybeOption.isEmpty) return null;
return maybeOption;
}

/// Validate command flag.
bool checkFlag({
required String flagKey,
Expand Down
Loading

0 comments on commit 22b6b5b

Please sign in to comment.