Skip to content
This repository has been archived by the owner on Nov 20, 2024. It is now read-only.

Commit

Permalink
Scorecard (work in progress). (#1344)
Browse files Browse the repository at this point in the history
* scoring wip

* date adjust

* fmt
  • Loading branch information
pq authored Jan 4, 2019
1 parent 61d5281 commit 5800aeb
Show file tree
Hide file tree
Showing 3 changed files with 211 additions and 0 deletions.
5 changes: 5 additions & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ dependencies:
dev_dependencies:
cli_util: ^0.1.2
dart_style: ^1.1.0
github:
git:
# todo(pq): update when 4.0.1 is released (https://github.com/DirectMyFile/github.dart/issues/128)
url: git://github.com/DirectMyFile/github.dart.git
ref: 0a04ae19e06f95b8afe018d666eea96585869492
grinder: ^0.8.0
markdown: ^2.0.0
matcher: ^0.12.0
Expand Down
47 changes: 47 additions & 0 deletions tool/crawl.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:analyzer/src/lint/config.dart';
import 'package:http/http.dart' as http;

const _flutterOptionsUrl =
'https://raw.githubusercontent.com/flutter/flutter/master/packages/flutter/lib/analysis_options_user.yaml';
const _flutterRepoOptionsUrl =
'https://raw.githubusercontent.com/flutter/flutter/master/analysis_options.yaml';
const _pedanticOptionsUrl =
'https://raw.githubusercontent.com/dart-lang/pedantic/master/lib/analysis_options.yaml';
const _stagehandOptionsUrl =
'https://raw.githubusercontent.com/dart-lang/stagehand/master/templates/analysis_options.yaml';

List<String> _flutterRules;
List<String> _flutterRepoRules;
List<String> _pedanticRules;
List<String> _stagehandRules;

Future<List<String>> get flutterRules async =>
_flutterRules ??= await _fetchRules(_flutterOptionsUrl);

Future<List<String>> get flutterRepoRules async =>
_flutterRepoRules ??= await _fetchRules(_flutterRepoOptionsUrl);

Future<List<String>> get pedanticRules async =>
_pedanticRules ??= await _fetchRules(_pedanticOptionsUrl);

Future<List<String>> get stagehandRules async =>
_stagehandRules ??= await _fetchRules(_stagehandOptionsUrl);

Future<LintConfig> _fetchConfig(String url) async {
var client = new http.Client();
var req = await client.get(url);
return processAnalysisOptionsFile(req.body);
}

Future<List<String>> _fetchRules(String optionsUrl) async {
var config = await _fetchConfig(optionsUrl);
var rules = <String>[];
for (var ruleConfig in config.ruleConfigs) {
rules.add(ruleConfig.name);
}
return rules;
}
159 changes: 159 additions & 0 deletions tool/scorecard.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:async';

import 'package:analyzer/src/lint/registry.dart';
import 'package:github/server.dart';
import 'package:http/http.dart' as http;
import 'package:linter/src/analyzer.dart';
import 'package:linter/src/rules.dart';

import 'crawl.dart';

const bulb = '💡';
const checkMark = '✅';

Iterable<LintRule> _registeredLints;

Iterable<LintRule> get registeredLints {
if (_registeredLints == null) {
registerLintRules();
_registeredLints = Registry.ruleRegistry;
}
return _registeredLints;
}

main() async {
var scorecard = await ScoreCard.calculate();

//printAll(scorecard);
printMarkdownTable(scorecard);
}

void printAll(ScoreCard scorecard) {
print('-- ALL -----------------------------------------');
scorecard.forEach(print);
}

void printMarkdownTable(ScoreCard scorecard) {
print(
'| name | fix | flutter user | flutter repo | pedantic | stagehand | status | bug refs |');
print('| :--- | :---: | :---:| :---: | :---: | :---: | :---: | :--- |');
scorecard.forEach((lint) {
var sb = StringBuffer('| `${lint.name}` |');
sb.write('${lint.hasFix ? " $bulb" : ""} |');
sb.write('${lint.ruleSets.contains('flutter') ? " $checkMark" : ""} |');
sb.write(
'${lint.ruleSets.contains('flutter_repo') ? " $checkMark" : ""} |');
sb.write('${lint.ruleSets.contains('pedantic') ? " $checkMark" : ""} |');
sb.write('${lint.ruleSets.contains('stagehand') ? " $checkMark" : ""} |');
sb.write('${lint.maturity != 'stable' ? ' **${lint.maturity}** ' : ""} |');
sb.write(' ${lint.bugReferences.join(", ")} |');
print(sb.toString());
});
}

class ScoreCard {
int get lintCount => registeredLints.length;

List<LintScore> scores = <LintScore>[];

void add(LintScore score) {
scores.add(score);
}

void forEach(void f(LintScore element)) {
scores.forEach(f);
}

static Future<List<String>> _getLintsWithFixes() async {
var client = http.Client();
var req = await client.get(
'https://raw.githubusercontent.com/dart-lang/sdk/master/pkg/analysis_server/lib/src/services/correction/fix_internal.dart');
var lintsWithFixes = <String>[];
for (var word in req.body.split(RegExp('\\s+'))) {
if (word.startsWith('LintNames.')) {
var lintName = word.substring(10);
if (lintName.endsWith(')')) {
lintName = lintName.substring(0, lintName.length - 1);
}
lintsWithFixes.add(lintName);
}
}
return lintsWithFixes;
}

static Future<List<Issue>> _getIssues() async {
var github = createGitHubClient();
var slug = RepositorySlug('dart-lang', 'linter');
return github.issues.listByRepo(slug).toList();
}

static Future<ScoreCard> calculate() async {
var lintsWithFixes = await _getLintsWithFixes();
var flutterRuleset = await flutterRules;
var flutterRepoRuleset = await flutterRepoRules;
var pedanticRuleset = await pedanticRules;
var stagehandRuleset = await stagehandRules;

var issues = await _getIssues();
var bugs = issues.where(_isBug).toList();

var scorecard = ScoreCard();
for (var lint in registeredLints) {
var ruleSets = <String>[];
if (flutterRuleset.contains(lint.name)) {
ruleSets.add('flutter');
}
if (flutterRepoRuleset.contains(lint.name)) {
ruleSets.add('flutter_repo');
}
if (pedanticRuleset.contains(lint.name)) {
ruleSets.add('pedantic');
}
if (stagehandRuleset.contains(lint.name)) {
ruleSets.add('stagehand');
}
var bugReferences = <String>[];
for (var bug in bugs) {
if (bug.title.contains(lint.name)) {
bugReferences.add('#${bug.number.toString()}');
}
}

scorecard.add(LintScore(
name: lint.name,
hasFix: lintsWithFixes.contains(lint.name),
maturity: lint.maturity.name,
ruleSets: ruleSets,
bugReferences: bugReferences));
}

return scorecard;
}
}

bool _isBug(Issue issue) => issue.labels.map((l) => l.name).contains('bug');

class LintScore {
String name;
bool hasFix;
String maturity;

List<String> ruleSets;
List<String> bugReferences;

LintScore(
{this.name,
this.hasFix,
this.maturity,
this.ruleSets,
this.bugReferences});

String get _ruleSets => ruleSets.isNotEmpty ? ' ${ruleSets.toString()}' : '';

@override
String toString() => '$name$_ruleSets${hasFix ? " 💡" : ""}';
}

0 comments on commit 5800aeb

Please sign in to comment.