Skip to content
This repository was archived by the owner on Jul 16, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unreleased

* feat: support report to the json file option for the `analyze` command.
* feat: make CliRunner a part of public API in order to support transitive executable calls use-case.
* feat: add static code diagnostic [`avoid-cascade-after-if-null`](https://dartcodemetrics.dev/docs/rules/common/avoid-cascade-after-if-null).

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:convert';
import 'dart:io';

import 'package:path/path.dart';
import 'package:source_span/source_span.dart';

import '../../../../../reporters/models/json_reporter.dart';
Expand All @@ -20,6 +21,15 @@ class LintJsonReporter extends JsonReporter<LintFileReport,
SummaryLintReportRecord<Object>, LintReportParams> {
const LintJsonReporter(IOSink output) : super(output, 2);

factory LintJsonReporter.toFile(String path, String rootFolder) {
final isAbsolutePath = isAbsolute(path);
final filePath = isAbsolutePath ? path : normalize(join(rootFolder, path));

final file = File(filePath.endsWith('.json') ? filePath : '$filePath.json');

return LintJsonReporter(file.openWrite());
}

@override
Future<void> report(
Iterable<LintFileReport> records, {
Expand Down
33 changes: 24 additions & 9 deletions lib/src/cli/commands/analyze_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import 'package:collection/collection.dart';
import '../../analyzers/lint_analyzer/lint_analyzer.dart';
import '../../analyzers/lint_analyzer/metrics/metrics_factory.dart';
import '../../analyzers/lint_analyzer/metrics/models/metric_value_level.dart';
import '../../analyzers/lint_analyzer/models/lint_file_report.dart';
import '../../analyzers/lint_analyzer/models/severity.dart';
import '../../analyzers/lint_analyzer/reporters/lint_report_params.dart';
import '../../analyzers/lint_analyzer/reporters/reporters_list/json/lint_json_reporter.dart';
import '../../analyzers/lint_analyzer/utils/report_utils.dart';
import '../../config_builder/config_builder.dart';
import '../../config_builder/models/deprecated_option.dart';
Expand Down Expand Up @@ -44,26 +46,29 @@ class AnalyzeCommand extends BaseCommand {
..isVerbose = isVerbose
..progress.start('Analyzing');

final parsedArgs = ParsedArguments(
excludePath: argResults[FlagNames.exclude] as String,
metricsConfig: {
for (final metric in getMetrics(config: {}))
if (argResults.wasParsed(metric.id))
metric.id: argResults[metric.id] as Object,
},
);
final parsedArgs = ParsedArguments.fromArgs(argResults);

final config = ConfigBuilder.getLintConfigFromArgs(parsedArgs);

final lintAnalyzerResult = await _analyzer.runCliAnalysis(
argResults.rest,
argResults[FlagNames.rootFolder] as String,
parsedArgs.rootFolder,
config,
sdkPath: findSdkPath(),
);

_logger.progress.complete('Analysis is completed. Preparing the results:');

final jsonReportPath = parsedArgs.jsonReportPath;
if (jsonReportPath != null) {
final jsonReporter =
LintJsonReporter.toFile(jsonReportPath, parsedArgs.rootFolder);
await jsonReporter.report(
lintAnalyzerResult,
summary: _analyzer.getSummary(lintAnalyzerResult),
);
}

await _analyzer
.getReporter(
name: argResults[FlagNames.reporter] as String,
Expand All @@ -76,6 +81,10 @@ class AnalyzeCommand extends BaseCommand {
additionalParams: LintReportParams(congratulate: !isNoCongratulate),
);

_checkSeverity(lintAnalyzerResult);
}

void _checkSeverity(Iterable<LintFileReport> lintAnalyzerResult) {
if (hasIssueWithSeverity(lintAnalyzerResult, Severity.error)) {
exit(3);
} else if ((argResults[FlagNames.fatalWarnings] as bool) &&
Expand Down Expand Up @@ -133,6 +142,12 @@ class AnalyzeCommand extends BaseCommand {
help: 'Write HTML output to OUTPUT.',
valueHelp: 'OUTPUT',
defaultsTo: 'metrics',
)
..addOption(
FlagNames.jsonReportPath,
help: 'Path to the JSON file with the output of the analysis.',
valueHelp: 'path/to/file.json',
defaultsTo: null,
);
}

Expand Down
1 change: 1 addition & 0 deletions lib/src/cli/models/flag_names.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class FlagNames {
static const gitlabCodeClimateReporter = CodeClimateReporter.alternativeId;

static const reportFolder = 'output-directory';
static const jsonReportPath = 'json-path';
static const setExitOnViolationLevel = 'set-exit-on-violation-level';
static const fatalStyle = 'fatal-style';
static const fatalPerformance = 'fatal-performance';
Expand Down
20 changes: 20 additions & 0 deletions lib/src/cli/models/parsed_arguments.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,30 @@
import 'package:args/args.dart';

import '../../analyzers/lint_analyzer/metrics/metrics_factory.dart';
import 'flag_names.dart';

/// Represents the arguments parsed from raw cli arguments.
class ParsedArguments {
final String excludePath;
final String rootFolder;
final String? jsonReportPath;
final Map<String, Object> metricsConfig;

const ParsedArguments({
required this.excludePath,
required this.rootFolder,
required this.metricsConfig,
this.jsonReportPath,
});

factory ParsedArguments.fromArgs(ArgResults argResults) => ParsedArguments(
excludePath: argResults[FlagNames.exclude] as String,
rootFolder: argResults[FlagNames.rootFolder] as String,
jsonReportPath: argResults[FlagNames.jsonReportPath] as String?,
metricsConfig: {
for (final metric in getMetrics(config: {}))
if (argResults.wasParsed(metric.id))
metric.id: argResults[metric.id] as Object,
},
);
}
7 changes: 6 additions & 1 deletion test/src/analyzers/lint_analyzer/lint_config_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,11 @@ void main() {
group('fromArgs constructs instance from passed', () {
test('empty arguments', () {
final config = LintConfig.fromArgs(
const ParsedArguments(excludePath: '', metricsConfig: {}),
const ParsedArguments(
excludePath: '',
metricsConfig: {},
rootFolder: '',
),
);

expect(config.excludePatterns, isEmpty);
Expand All @@ -159,6 +163,7 @@ void main() {
'maximum-nesting-level': '5',
'metric-id4': '0',
},
rootFolder: '',
),
);

Expand Down
1 change: 1 addition & 0 deletions test/src/cli/commands/analyze_command_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const _usage = 'Collect code metrics, rules and anti-patterns violations.\n'
' [console (default), console-verbose, checkstyle, codeclimate, github, gitlab, html, json]\n'
'-o, --output-directory=<OUTPUT> Write HTML output to OUTPUT.\n'
' (defaults to "metrics")\n'
' --json-path=<path/to/file.json> Path to the JSON file with the output of the analysis.\n'
'\n'
'\n'
' --cyclomatic-complexity=<20> Cyclomatic Complexity threshold.\n'
Expand Down
1 change: 1 addition & 0 deletions website/docs/cli/analyze.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Usage: metrics analyze [arguments...] <directories>
[console (default), console-verbose, checkstyle, codeclimate, github, gitlab, html, json]
-o, --output-directory=<OUTPUT> Write HTML output to OUTPUT
(defaults to "metrics/")
--json-path=<path/to/file.json> Path to the JSON file with the output of the analysis.


--cyclomatic-complexity=<20> Cyclomatic Complexity threshold.
Expand Down