Skip to content
Open
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
70 changes: 67 additions & 3 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,73 @@ include: package:lints/recommended.yaml

# Uncomment the following section to specify additional rules.

# linter:
# rules:
# - camel_case_types
formatter:
page_width: 300

linter:
rules:
# Core Lint Rules
- avoid_print
- avoid_single_cascade_in_expression_statements
- camel_case_types
- constant_identifier_names
- curly_braces_in_flow_control_structures
- directives_ordering
- always_use_package_imports
- file_names
- prefer_final_fields
- prefer_is_not_empty
- sort_constructors_first
- type_annotate_public_apis

# Flutter Specific Lint Rules
- avoid_redundant_argument_values
- avoid_unnecessary_containers
- avoid_web_libraries_in_flutter
- prefer_const_constructors
- prefer_const_literals_to_create_immutables
- prefer_final_locals
- sized_box_for_whitespace
- unnecessary_const
- use_key_in_widget_constructors

# Style and Convention
- always_declare_return_types
- annotate_overrides
- avoid_annotating_with_dynamic
- avoid_empty_else
- avoid_init_to_null
- avoid_return_types_on_setters
- avoid_unused_constructor_parameters
- await_only_futures
- empty_catches
- prefer_typing_uninitialized_variables

# Documentation and Comments
- slash_for_doc_comments
- comment_references

# Code Efficiency and Performance
- avoid_function_literals_in_foreach_calls
- avoid_types_on_closure_parameters
- prefer_collection_literals
- unnecessary_new
- unnecessary_lambdas
- unnecessary_getters_setters
- use_function_type_syntax_for_parameters
- prefer_spread_collections

# Error Handling
# - avoid_catches_without_on_clauses

# Best Practices
- avoid_positional_boolean_parameters
- use_string_buffers
- use_rethrow_when_possible

# Miscellaneous
- avoid_returning_this
- use_full_hex_values_for_flutter_colors

# analyzer:
# exclude:
Expand Down
114 changes: 111 additions & 3 deletions lib/commands/comands.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ const _outputDir = 'output-dir';
const _projectPathKey = 'projectPath';
const _configFile = 'config';
const _reportFormat = 'report-format';
const _languageKey = 'lang';
const _analysisParserFileKey = 'analysisParserFile';


//TODO(kanniel-outis): move to git parser package folder
Expand Down Expand Up @@ -120,6 +122,7 @@ class LcovCliCommand extends Command<int> {
..addOption(_projectPathKey, abbr: _projectPathKey.split('').first, help: 'Path to the project root directory containing the source code for coverage analysis')
..addOption(_gitParserFileKey, abbr: _gitParserFileKey.split('').first, help: 'Path to the git parser file containing git change analysis results')
..addOption(_reportType, abbr: _reportType.split('').first, defaultsTo: 'html', help: 'Format of the output report (html, json, or console)')
..addOption(_analysisParserFileKey, abbr: _analysisParserFileKey.split('').first, help: 'Path to the analysis results file (e.g., `coverage/.analyzer.json`)')
..addOption(_configFile, abbr: _configFile.split('').first, help: 'Path to the config file containing configuration options for the analysis tool');
} catch (e) {
Logger.error(e);
Expand All @@ -143,6 +146,7 @@ class LcovCliCommand extends Command<int> {
final projectPath = config.projectPath;
final gitParserFile = config.gitParserFile;
final reportFormat = config.reportFormat;
final analysisParserFile = config.analysisParserFile;
final result = await Process.instance.start(
'dart',
[
Expand Down Expand Up @@ -170,7 +174,77 @@ class LcovCliCommand extends Command<int> {
if (reportFormat != null) ...[
'--reportType',
reportFormat,
]
],
if (analysisParserFile != null) ...[
'--analysisParserFile',
analysisParserFile,
],
],
runInShell: true,
);
result.stdout.transform(utf8.decoder).listen(stdout.write);
result.stderr.transform(utf8.decoder).listen(stderr.write);
return await result.exitCode;
} catch (e) {
Logger.error(e);
exit(-1);
}
}
}

//TODO: might move
class AnalyzerCommand extends Command<int> {
AnalyzerCommand() {
addArgParser();
}

void addArgParser() {
try {
argParser
..addOption(_outputDir, abbr: _outputDir.split('').first, help: 'Path to the output directory where the processed analysis report will be saved. result is processed to json file')
..addOption(_projectPathKey, abbr: _projectPathKey.split('').first, help: 'Path to the project root directory containing the source code for code analysis')
..addOption(_languageKey, abbr: _languageKey.split('').first.toUpperCase(), help: 'Language of the project')
..addOption(_configFile, abbr: _configFile.split('').first, help: 'Path to the configuration file');
} catch (e) {
Logger.error(e);
exit(-1);
}
}

@override
String get description => 'Analyzer CLI Command Line Tool - Runs static code analysis and retrieves results';

@override
String get name => 'analyze';

@override
FutureOr<int>? run() async {
try {
final config = Config.analyzerParserFromArgs(argResults);
final configFile = config.config;
final outputDir = config.output;
final projectPath = config.projectPath;
final language = config.language;
final result = await Process.instance.start(
'dart',
[
path.join(Utils.root, 'packages', 'analysis_parser_cli', 'bin', 'analysis_parser_cli.dart'),
if (outputDir != null) ...[
'--output-dir',
outputDir,
],
if (projectPath != null) ...[
'--project-dir',
projectPath,
],
if (configFile != null) ...[
'--config',
configFile,
],
if (language != null) ...[
'--lang',
language,
],
],
runInShell: true,
);
Expand Down Expand Up @@ -203,6 +277,8 @@ class MainRunnerCommand extends Command<int> {
..addOption(_gitParserFileKey, abbr: _gitParserFileKey.split('').first, help: 'Path to the git parser file containing the results of git change analysis')
..addOption(_outputDir, help: 'Path to the output directory where the analysis results will be saved.')
..addOption(_reportFormat, abbr: _reportFormat.split('').first, defaultsTo: 'html', help: 'Format of the output report (html, json, or console)')
..addOption(_languageKey, abbr: _languageKey.split('').first.toUpperCase(), defaultsTo: 'dart', help: 'Language of the project')
..addOption(_analysisParserFileKey, abbr: _analysisParserFileKey.split('').first, help: 'Path to the analysis results file (e.g., `coverage/.analyzer.json`)')
..addOption(_configFile, abbr: _configFile.split('').first, help: 'Path to the config file containing configuration options for the analysis tool');
} catch (e) {
Logger.error(e);
Expand Down Expand Up @@ -270,10 +346,34 @@ class MainRunnerCommand extends Command<int> {
if (config.reportFormat != null) ...[
'--reportType',
config.reportFormat!,
]
],
if (config.analysisParserFile != null) ...[
'--analysisParserFile',
config.analysisParserFile!,
],
];

await main.run(['git', ...gitOptions]);
final analyzerOptions = [
if (config.output != null) ...[
'--output-dir',
config.output!,
],
if (config.projectPath != null) ...[
'--project-dir',
config.projectPath!,
],
if (config.config != null) ...[
'--config',
config.config!,
],
if (config.language != null) ...[
'--lang',
config.language!,
],
];

final invoke = Future.wait([main.run(['git', ...gitOptions]), main.run(['analyze', ...analyzerOptions])]);
await _runSafely(invoke);
await main.run(['lcov', ...lcovOptions]);
Logger.success('Analysis completed successfully.');
return 0;
Expand All @@ -282,4 +382,12 @@ class MainRunnerCommand extends Command<int> {
exit(-1);
}
}

Future<void> _runSafely(Future invoke) async {
try {
await invoke;
} catch (e) {
Logger.error(e);
}
}
}
1 change: 1 addition & 0 deletions lib/commands/runner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class CoverOpsRunner extends CommandRunner<int> {
}

void init() {
addCommand(AnalyzerCommand());
addCommand(GitCliCommand());
addCommand(LcovCliCommand());
addCommand(MainRunnerCommand(this));
Expand Down
41 changes: 41 additions & 0 deletions lib/utils/config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ const _configFile = 'config';
const _reportFormat = 'report-format';
const _reportType = 'reportType';
const _projectDir = 'project-dir';
const _analysisParserFileKey = 'analysisParserFile';
const _languageKey = 'lang';

/// Stores configuration options for the CoverOps CLI tool.
///
Expand All @@ -35,6 +37,9 @@ class Config {
/// Path to the Git analysis results file (e.g., `coverage/.gitparser.json`).
final String? gitParserFile;

/// Path to the analysis results file (e.g., `coverage/.analysis.json`).
final String? analysisParserFile;

/// Target branch for Git comparison (e.g., `main`).
final String? targetBranch;

Expand All @@ -53,6 +58,12 @@ class Config {
/// Report format (e.g., `html`, `json`, `console`).
final String? reportFormat;

/// Language of the project.
final String? language;

/// Path to the configuration file.
final String? config;

/// Creates a [Config] instance with the specified options.
///
/// All parameters are optional and can be null if not specified.
Expand All @@ -61,22 +72,27 @@ class Config {
/// - `lcovFile` Path to the LCOV coverage file.
/// - `jsonCoverage` Path to the JSON coverage file.
/// - `gitParserFile` Path to the Git analysis results file.
/// - `analyzerParserFile` Path to the analyzer results file.
/// - `targetBranch` Target branch for Git comparison.
/// - `targetBranchFallback` Fallback branch if target is unavailable.
/// - `sourceBranch` Source branch with changes.
/// - `output` Output directory for reports.
/// - `projectPath` Project root directory.
/// - `reportFormat` Report format (e.g., `html`, `json`, `console`).
/// - `language` Language of the project.
Config({
this.lcovFile,
this.jsonCoverage,
this.gitParserFile,
this.analysisParserFile,
this.targetBranch,
this.targetBranchFallback,
this.sourceBranch,
this.output,
this.projectPath,
this.language,
this.reportFormat,
this.config,
});

/// Creates a [Config] instance from command-line arguments.
Expand All @@ -95,12 +111,15 @@ class Config {
lcovFile: fileConfig?.lcovFile ?? args?[_lcovFileKey],
jsonCoverage: fileConfig?.jsonCoverage ?? args?[_jsonCoverageKey],
gitParserFile: fileConfig?.gitParserFile ?? args?[_gitParserFileKey],
analysisParserFile: fileConfig?.analysisParserFile ?? args?[_analysisParserFileKey],
targetBranch: fileConfig?.targetBranch ?? args?[_targetBranchKey],
targetBranchFallback: fileConfig?.targetBranchFallback ?? args?[_targetBranchFallbackKey],
sourceBranch: fileConfig?.sourceBranch ?? args?[_sourceBranchKey],
output: fileConfig?.output ?? args?[_output] ?? args?[_outputDir],
projectPath: fileConfig?.projectPath ?? args?[_projectPathKey],
reportFormat: fileConfig?.reportFormat ?? args?[_reportFormat],
language: fileConfig?.language ?? args?[_languageKey],
config: configPath,
);
}

Expand Down Expand Up @@ -141,12 +160,33 @@ class Config {
lcovFile: fileConfig?.lcovFile ?? args?[_lcovFileKey],
jsonCoverage: fileConfig?.jsonCoverage ?? args?[_jsonCoverageKey],
gitParserFile: fileConfig?.gitParserFile ?? args?[_gitParserFileKey],
analysisParserFile: fileConfig?.analysisParserFile ?? args?[_analysisParserFileKey],
output: fileConfig?.output ?? args?[_output],
projectPath: fileConfig?.projectPath ?? args?[_projectPathKey],
reportFormat: fileConfig?.reportFormat ?? args?[_reportType],
);
}

/// Creates a [Config] instance for analyzer parsing from command-line arguments.
///
/// This factory constructor merges settings from [args] with those from a JSON
/// configuration file specified by the `--config` flag. File-based settings
/// take precedence for keys defined in the JSON file.
///
/// Parameters:
/// - `args` The parsed command-line arguments from [ArgResults].
/// returns A [Config] instance with merged settings for analyzer parsing.
factory Config.analyzerParserFromArgs(ArgResults? args) {
final configPath = args?[_configFile] as String?;
final fileConfig = _FileConfig(configFilePath: configPath).getConfig();
return Config(
output: fileConfig?.output ?? args?[_outputDir] ?? args?[_output],
projectPath: fileConfig?.projectPath ?? args?[_projectPathKey],
language: fileConfig?.language ?? args?[_languageKey],
config: configPath,
);
}

/// Parses a JSON file into a map.
///
/// Reads the content of [file] synchronously and decodes it as JSON. Returns an
Expand Down Expand Up @@ -209,6 +249,7 @@ class _FileConfig extends Config {
output: args[_output],
projectPath: args[_projectPathKey],
reportFormat: (args[_reportFormat.toCamelCase] as List<dynamic>?)?.join(','),
analysisParserFile: args[_analysisParserFileKey],
);
} catch (e) {
Logger.error(e);
Expand Down
4 changes: 4 additions & 0 deletions packages/analysis_parser_cli/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# https://dart.dev/guides/libraries/private-files
# Created by `dart pub`
.dart_tool/
/coverage/
3 changes: 3 additions & 0 deletions packages/analysis_parser_cli/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 1.0.0

- Initial version.
2 changes: 2 additions & 0 deletions packages/analysis_parser_cli/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
A sample command-line application with an entrypoint in `bin/`, library code
in `lib/`, and example unit test in `test/`.
Loading
Loading