Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Account for removal of analysis_options_user.yaml from Flutter #1329

Merged
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
85 changes: 18 additions & 67 deletions lib/src/analysis_options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,93 +8,44 @@ import 'dart:isolate';

import 'package:http/http.dart' as http;
import 'package:logging/logging.dart';
import 'package:path/path.dart' as p;
import 'package:retry/retry.dart';
import 'package:yaml/yaml.dart' as yaml;

final _logger = Logger('analysis_options');

String? _cachedFlutterOptionsOnGithub;
String? _cachedLintsCoreInResolvedReferences;
String? _cachedLintsCoreOptionsOnGithub;
String? _cachedCoreLints;

/// Returns the default analysis options (in yaml format).
Future<String> getDefaultAnalysisOptionsYaml({
required bool usesFlutter,
required String? flutterSdkDir,
}) async {
if (usesFlutter) {
return await _getFlutterAnalysisOptions(flutterSdkDir);
} else {
return await _getLintsCoreAnalysisOptions();
}
}

Future<String> _getFlutterAnalysisOptions(String? flutterSdkDir) async {
// try to load local file
flutterSdkDir ??= Platform.environment['FLUTTER_ROOT'];
if (flutterSdkDir != null &&
flutterSdkDir.isNotEmpty &&
await Directory(flutterSdkDir).exists()) {
final file = File(p.join(flutterSdkDir, 'packages', 'flutter', 'lib',
'analysis_options_user.yaml'));
if (await file.exists()) {
return await file.readAsString();
}
}

// try to load latest from github
if (_cachedFlutterOptionsOnGithub != null) {
return _cachedFlutterOptionsOnGithub!;
}
try {
final rs = await _httpGetWithRetry(Uri.parse(
'https://raw.githubusercontent.com/flutter/flutter/master/packages/flutter/lib/analysis_options_user.yaml'));
if (rs.statusCode == 200) {
_cachedFlutterOptionsOnGithub = rs.body;
return _cachedFlutterOptionsOnGithub!;
}
} catch (_) {
// no-op
}

// fallback empty options
_logger.warning('Unable to load default Flutter analysis options.');
return '';
}
/// The default analysis options configuration (in its raw yaml format).
Future<String> getDefaultAnalysisOptionsYaml() async =>
_cachedCoreLints ??= await _getLintsCoreAnalysisOptions();

Future<String> _getLintsCoreAnalysisOptions() async {
// try to load local lints from the resolved package references
if (_cachedLintsCoreInResolvedReferences != null) {
return _cachedLintsCoreInResolvedReferences!;
}
// Try to load local lints from the resolved package references.
try {
final resource =
await Isolate.resolvePackageUri(Uri.parse('package:lints/core.yaml'));
final file = File.fromUri(resource!);
_cachedLintsCoreInResolvedReferences = await file.readAsString();
return _cachedLintsCoreInResolvedReferences!;
final coreLintsUri = Uri(scheme: 'package', path: 'lints/core.yaml');
final resource = await Isolate.resolvePackageUri(coreLintsUri);
if (resource != null) {
final file = File.fromUri(resource);
return await file.readAsString();
}
} on Exception catch (_) {
// no-op
// Gracefully handle exception to fall back to an empty config.
}

// try to load latest from github
if (_cachedLintsCoreOptionsOnGithub != null) {
return _cachedLintsCoreOptionsOnGithub!;
}
// Try to load latest version of the core lints from GitHub.
try {
final rs = await _httpGetWithRetry(Uri.parse(
'https://raw.githubusercontent.com/dart-lang/lints/main/lib/core.yaml'));
if (rs.statusCode == 200 && rs.body.contains('rules:')) {
_cachedLintsCoreOptionsOnGithub = rs.body;
return _cachedLintsCoreOptionsOnGithub!;
return rs.body;
}
} on Exception catch (_) {
// no-op
// Gracefully handle exception to fall back to an empty config.
}

// fallback empty options
_logger.warning('Unable to load default analysis options.');
// If we couldn't load the core lints,
// log a warning and fall back to an empty analysis config.
_logger.warning('Unable to load the core set of analysis options.');
return '';
}

Expand Down
5 changes: 1 addition & 4 deletions lib/src/sdk_env.dart
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,7 @@ class ToolEnvironment {
if (await analysisOptionsFile.exists()) {
originalOptions = await analysisOptionsFile.readAsString();
}
final rawOptionsContent = await getDefaultAnalysisOptionsYaml(
usesFlutter: usesFlutter,
flutterSdkDir: _flutterSdk._config.rootPath,
);
final rawOptionsContent = await getDefaultAnalysisOptionsYaml();
final customOptionsContent = updatePassthroughOptions(
original: originalOptions, custom: rawOptionsContent);
try {
Expand Down
18 changes: 1 addition & 17 deletions test/analysis_options_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ import 'package:yaml/yaml.dart' as yaml;

void main() {
test('default options', () async {
final content = await getDefaultAnalysisOptionsYaml(
usesFlutter: false, flutterSdkDir: null);
final content = await getDefaultAnalysisOptionsYaml();
expect(content, contains('linter:'));
expect(content, contains('rules:'));
expect(content, contains('avoid_empty_else'));
Expand All @@ -23,21 +22,6 @@ void main() {
});
});

test('default Flutter options', () async {
final content = await getDefaultAnalysisOptionsYaml(
usesFlutter: true, flutterSdkDir: null);
expect(json.decode(json.encode(yaml.loadYaml(content))), {
'analyzer': {
'errors': {
'missing_required_param': 'warning',
},
},
'linter': {
'rules': hasLength(greaterThan(10)),
},
});
});

test('passthrough for empty options', () {
final content = updatePassthroughOptions(original: '', custom: '');
expect(json.decode(content), <String, Object?>{});
Expand Down
8 changes: 4 additions & 4 deletions test/goldens/end2end/audio_service-0.18.10.json
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,10 @@
{
"id": "analysis",
"title": "Pass static analysis",
"grantedPoints": 40,
"grantedPoints": 50,
"maxPoints": 50,
"status": "partial",
"summary": "### [~] 40/50 points: code has no errors, warnings, lints, or formatting issues\n\nFound 16 issues. Showing the first 2:\n\n<details>\n<summary>\nINFO: Unclosed instance of 'Sink'.\n</summary>\n\n`lib/audio_service.dart:1943:40`\n\n```\n ╷\n1943 │ final BehaviorSubject<PlaybackState> _playbackState = BehaviorSubject();\n │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n ╵\n```\n\nTo reproduce make sure you are using the [lints_core](https://pub.dev/packages/lints) and run `flutter analyze lib/audio_service.dart`\n</details>\n<details>\n<summary>\nINFO: Unclosed instance of 'Sink'.\n</summary>\n\n`lib/audio_service.dart:1944:42`\n\n```\n ╷\n1944 │ final BehaviorSubject<List<MediaItem>> _queue = BehaviorSubject();\n │ ^^^^^^^^^^^^^^^^^^^^^^^^^^\n ╵\n```\n\nTo reproduce make sure you are using the [lints_core](https://pub.dev/packages/lints) and run `flutter analyze lib/audio_service.dart`\n</details>"
"status": "passed",
"summary": "### [*] 50/50 points: code has no errors, warnings, lints, or formatting issues\n"
},
{
"id": "dependency",
Expand All @@ -186,7 +186,7 @@
"path": "audio_service"
},
"contributingUrl": "https://github.com/ryanheise/audio_service/blob/minor/CONTRIBUTING.md",
"grantedPoints": 120,
"grantedPoints": 130,
"maxPoints": 130
},
"urlProblems": []
Expand Down
38 changes: 2 additions & 36 deletions test/goldens/end2end/audio_service-0.18.10.json_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,44 +61,10 @@ Because:
* `package:path_provider/path_provider.dart` that declares support for platforms: `Android`, `iOS`, `Windows`, `Linux`, `macOS`.
</details>

## 40/50 Pass static analysis
## 50/50 Pass static analysis

### [~] 40/50 points: code has no errors, warnings, lints, or formatting issues
### [*] 50/50 points: code has no errors, warnings, lints, or formatting issues

Found 16 issues. Showing the first 2:

<details>
<summary>
INFO: Unclosed instance of 'Sink'.
</summary>

`lib/audio_service.dart:1943:40`

```
1943 │ final BehaviorSubject<PlaybackState> _playbackState = BehaviorSubject();
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
```

To reproduce make sure you are using the [lints_core](https://pub.dev/packages/lints) and run `flutter analyze lib/audio_service.dart`
</details>
<details>
<summary>
INFO: Unclosed instance of 'Sink'.
</summary>

`lib/audio_service.dart:1944:42`

```
1944 │ final BehaviorSubject<List<MediaItem>> _queue = BehaviorSubject();
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^
```

To reproduce make sure you are using the [lints_core](https://pub.dev/packages/lints) and run `flutter analyze lib/audio_service.dart`
</details>

## 20/20 Support up-to-date dependencies

Expand Down