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

Add CI and issue templates #35

Merged
merged 28 commits into from
Nov 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
013075b
Add CI and issue templates
rrousselGit Sep 27, 2022
e1be727
Remove deprecated lint
rrousselGit Sep 27, 2022
43c568a
Fix lint name in example
rrousselGit Sep 27, 2022
11e8c00
Fix deprecated warnings
rrousselGit Sep 27, 2022
ffbc708
Merge branch 'main' of https://github.com/invertase/unamed_dart_analy…
rrousselGit Oct 7, 2022
3534e9a
Merge branch 'main' of https://github.com/invertase/unamed_dart_analy…
rrousselGit Nov 17, 2022
175dc8f
Rename master -> main
rrousselGit Nov 17, 2022
a549e92
Test
rrousselGit Nov 17, 2022
4e22b0a
Print test
rrousselGit Nov 17, 2022
99f9fde
Try adding pubspec_overrides
rrousselGit Nov 17, 2022
3a06288
Test echo
rrousselGit Nov 17, 2022
3a2ff51
Add override file dynamically
rrousselGit Nov 17, 2022
762b76f
Log env
rrousselGit Nov 17, 2022
2838511
Use Platform.environment to exclude the CI
rrousselGit Nov 17, 2022
ba1c593
Use package:ci
rrousselGit Nov 17, 2022
04e8286
Fix typo
rrousselGit Nov 17, 2022
a55d9c4
Remove cron
rrousselGit Nov 17, 2022
1d10aca
Format
rrousselGit Nov 17, 2022
8b73c83
Remove typo
rrousselGit Nov 17, 2022
17bf369
Fix missing !
rrousselGit Nov 17, 2022
1a7c340
use equalsIgnoringAnsi
rrousselGit Nov 17, 2022
9393f81
Update equalsIgnoringAnsi
rrousselGit Nov 17, 2022
efc7a99
Improve error
rrousselGit Nov 17, 2022
b14322a
Debug
rrousselGit Nov 21, 2022
d7c9d21
Debug
rrousselGit Nov 21, 2022
81e88c3
Test
rrousselGit Nov 21, 2022
745afab
Add missing close
rrousselGit Nov 21, 2022
205653a
Disable tests
rrousselGit Nov 23, 2022
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
16 changes: 16 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
name: Bug report
about: There is a problem in how provider behaves
title: ""
labels: bug, needs triage
---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**

<Please add a small sample to that can be executed to reproduce the problem. As a general rule, 100 lines is the maximum>

**Expected behavior**
A clear and concise description of what you expected to happen.
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
blank_issues_enabled: false
18 changes: 18 additions & 0 deletions .github/ISSUE_TEMPLATE/example_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
name: Documentation improvement request
about: >-
Suggest a new example/documentation or ask for clarification about an
existing one.
title: ""
labels: documentation, needs triage
---

**Describe what scenario you think is uncovered by the existing examples/articles**
A clear and concise description of the problem that you want explained.

**Describe why existing examples/articles do not cover this case**
Explain which examples/articles you have seen before making this request, and
why they did not help you with your problem.

**Additional context**
Add any other context or screenshots about the documentation request here.
18 changes: 18 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
name: Feature request
about: Suggest an idea for this project
title: ""
labels: enhancement, needs triage
---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.
56 changes: 56 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: Build

on:
pull_request:
paths-ignore:
- "**.md"
push:
branches:
- main
paths-ignore:
- "**.md"
schedule:
# runs the CI everyday at 10AM
- cron: "0 10 * * *"

jobs:
build:
runs-on: ubuntu-latest

strategy:
matrix:
channel:
- stable

steps:
- uses: actions/checkout@v2

- uses: subosito/flutter-action@v2
with:
channel: ${{ matrix.channel }}

- name: Add pub cache bin to PATH
run: echo "$HOME/.pub-cache/bin" >> $GITHUB_PATH

- name: Add pub cache to PATH
run: echo "PUB_CACHE="$HOME/.pub-cache"" >> $GITHUB_ENV

- name: Add pubspec_overrides to the analyzer_plugin starter
run: "echo \"dependency_overrides:\n custom_lint:\n path: ${{github.workspace}}/packages/custom_lint\" > packages/custom_lint/tools/analyzer_plugin/pubspec_overrides.yaml"

- run: dart pub global activate melos

- name: Install dependencies
run: melos bootstrap

- name: Check format
run: flutter format --set-exit-if-changed .

- name: Analyze
run: flutter analyze

# - name: Run tests
# run: melos exec --dir-exists=test "dart test"

# - name: Upload coverage to codecov
# run: curl -s https://codecov.io/bash | bash
22 changes: 18 additions & 4 deletions packages/custom_lint/lib/basic_runner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Future<void> customLint({
bool watchMode = true,
required Directory workingDirectory,
}) async {
var isDone = false;
await runZonedGuarded(() async {
final runner = CustomLintRunner(
CustomLintPlugin(
Expand Down Expand Up @@ -66,16 +67,29 @@ Future<void> customLint({
}
});

await runner.initialize();
await _runPlugins(runner, reload: false);
try {
await runner.initialize();
await _runPlugins(runner, reload: false);

if (watchMode) {
await _startWatchMode(runner);
if (watchMode) {
await _startWatchMode(runner);
}
} finally {
await runner.close();
}
}, (err, stack) {
if (isDone) {
throw StateError(
'Received an error after `runZonedGuarded` should have complete. Is an async process leaking?'
'\nThe error was: $err'
'\nat:\n$stack',
);
}
exitCode = -1;
stderr.writeln('$err\n$stack');
});

isDone = true;
}

Future<void> _runPlugins(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ class CustomLintPlugin extends ServerPlugin {

final _overlays = <String, String>{};

bool _isDisposed = false;

late final ProviderContainer _container;

/// An imperative anchor for reading the current list of plugins
Expand Down Expand Up @@ -89,6 +91,7 @@ class CustomLintPlugin extends ServerPlugin {
(previousPlugins, currentPlugins) async {
final previousLinks = await previousPlugins;
final links = await currentPlugins;
if (_isDisposed) return;

for (final linkEntry in links.entries) {
final previousLinkResult = previousLinks?[linkEntry.key];
Expand Down Expand Up @@ -465,11 +468,14 @@ class CustomLintPlugin extends ServerPlugin {
FutureOr<plugin.PluginShutdownResult> handlePluginShutdown(
plugin.PluginShutdownParams parameters,
) async {
assert(!_isDisposed, 'The plugin is already disposed');
try {
// TODO what if a plugin initialized, then context root changed and is now failing
await _requestAllPlugins(parameters);

return plugin.PluginShutdownResult();
} finally {
_isDisposed = true;
_container.dispose();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import 'dart:async';
import 'dart:io';
import 'dart:isolate';

import 'package:ci/ci.dart' as ci;

import 'analyzer_plugin.dart';
import 'client_isolate_channel.dart';
import 'plugin_delegate.dart';
Expand All @@ -15,9 +17,13 @@ void start(Iterable<String> _, SendPort sendPort) {
final channel = ClientIsolateChannel(sendPort);
server = CustomLintPlugin(
delegate: AnalyzerPluginCustomLintDelegate(),
// Disable "loading" lints custom_lint is spawned from a terminal command;
// such as when using `dart analyze`
includeBuiltInLints: !stdin.hasTerminal,
includeBuiltInLints:
// Disable "loading" lints custom_lint is spawned from a terminal command;
// such as when using `dart analyze`
!stdin.hasTerminal &&
// In the CI, hasTerminal is often false. So let's explicitly disable
// "loading" lints for the CI too
!ci.isCI,
// The necessary flags for hot-reload to work aren't set by analyzer_plugin
watchMode: false,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,11 @@ class CommandCustomLintDelegate
err,
stackTrace,
);
stderr.writeln('$err\n$stackTrace');
try {
stderr.writeln('$err\n$stackTrace');
} catch (_) {
throw Exception('Threw while trying to print message: $err\n$stackTrace');
}
}

@override
Expand Down
53 changes: 30 additions & 23 deletions packages/custom_lint/lib/src/analyzer_plugin/plugin_link.dart
Original file line number Diff line number Diff line change
Expand Up @@ -110,31 +110,38 @@ final _pluginLinkProvider = FutureProvider.autoDispose
p.join(pluginRootPath, 'bin', 'custom_lint.dart'),
);

final isolate = await Isolate.spawnUri(
mainUri,
const [],
receivePort.sendPort,
// WHen published on pub or git, the plugin source often does not have a
// package_config.json. As such, we manually specify one based on the
// application that depends on the custom lint plugin.
// Since the application that uses the plugin depends on said plugin,
// the applications' package_config should contain everything that the plugin
// needs to work.
packageConfig: packageConfig,
// TODO test error in main (outside of runZonedGuarded)
debugName: pluginName,
onError: receivePort.sendPort,
);
try {
final isolate = await Isolate.spawnUri(
mainUri,
const [],
receivePort.sendPort,
// WHen published on pub or git, the plugin source often does not have a
// package_config.json. As such, we manually specify one based on the
// application that depends on the custom lint plugin.
// Since the application that uses the plugin depends on said plugin,
// the applications' package_config should contain everything that the plugin
// needs to work.
packageConfig: packageConfig,
// TODO test error in main (outside of runZonedGuarded)
debugName: pluginName,
onError: receivePort.sendPort,
);

final link = PluginLink._(
isolate,
ServerIsolateChannel(receivePort),
pluginRootUri.uri,
pluginName,
);
ref.onDispose(link.close);
final link = PluginLink._(
isolate,
ServerIsolateChannel(receivePort),
pluginRootUri.uri,
pluginName,
);
ref.onDispose(link.close);

return link;
return link;
} on IsolateSpawnException catch (err, stack) {
Error.throwWithStackTrace(
'Failed to spawn plugin $pluginName: $err',
stack,
);
}
});

/// The interface for interacting with a plugin
Expand Down
2 changes: 2 additions & 0 deletions packages/custom_lint/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ dependencies:
analyzer_plugin: ^0.10.0
args: ^2.3.1
async: ^2.8.2
ci: ^0.1.0
cli_util: ^0.3.5
collection: ^1.15.0
meta: ^1.7.0
Expand All @@ -25,6 +26,7 @@ dependencies:
yaml: ^3.1.0

dev_dependencies:
ansi_styles: ^0.3.2+1
test: ^1.20.2

executables:
Expand Down
15 changes: 9 additions & 6 deletions packages/custom_lint/test/cli_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:test/test.dart';

import '../bin/custom_lint.dart' as cli;
import 'create_project.dart';
import 'equals_ignoring_ansi.dart';
import 'mock_fs.dart';

const oyPluginSource = '''
Expand Down Expand Up @@ -113,13 +114,13 @@ No issues found!
await cli.main();

expect(exitCode, -1);
expect(err.join(), completion('''
IsolateSpawnException: Unable to spawn isolate: ${plugin.path}/bin/custom_lint.dart:1:1: \x1B[31mError: Variables must be declared using the keywords 'const', 'final', 'var' or a type name.
Try adding the name of the type of the variable or the keyword 'var'.\x1B[39;49m
expect(err.join(), completion(equalsIgnoringAnsi('''
IsolateSpawnException: Unable to spawn isolate: ${plugin.path}/bin/custom_lint.dart:1:1: Error: Variables must be declared using the keywords 'const', 'final', 'var' or a type name.
Try adding the name of the type of the variable or the keyword 'var'.
invalid;
^^^^^^^

'''));
''')));
expect(out, emitsDone);
},
currentDirectory: app,
Expand Down Expand Up @@ -180,12 +181,14 @@ invalid;
expect(
err.join(),
completion(
'''
IsolateSpawnException: Unable to spawn isolate: ${plugin2.path}/bin/custom_lint.dart:1:9: \x1B[31mError: A value of type 'String' can't be assigned to a variable of type 'int'.\x1B[39;49m
equalsIgnoringAnsi(
'''
IsolateSpawnException: Unable to spawn isolate: ${plugin2.path}/bin/custom_lint.dart:1:9: Error: A value of type 'String' can't be assigned to a variable of type 'int'.
int x = 'oy';
^

''',
),
),
);
expect(out.join(), completion('''
Expand Down
50 changes: 50 additions & 0 deletions packages/custom_lint/test/equals_ignoring_ansi.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import 'package:ansi_styles/extension.dart';
import 'package:test/test.dart';

/// Returns a matcher which matches if the match argument is a string and
/// is equal to [value] after removing ansi codes
Matcher equalsIgnoringAnsi(String value) => _IsEqualIgnoringAnsi(value);

class _IsEqualIgnoringAnsi extends Matcher {
_IsEqualIgnoringAnsi(this._value);

static final Object _mismatchedValueKey = Object();

final String _value;

@override
bool matches(Object? object, Map<Object?, Object?> matchState) {
final description = (object! as String).strip.replaceAll(';49m', '');
if (_value != description) {
matchState[_mismatchedValueKey] = description;
return false;
}
return true;
}

@override
Description describe(Description description) {
return description.addDescriptionOf(_value).add(' ignoring ansi codes');
}

@override
Description describeMismatch(
Object? item,
Description mismatchDescription,
Map<Object?, Object?> matchState,
bool verbose,
) {
if (matchState.containsKey(_mismatchedValueKey)) {
final actualValue = matchState[_mismatchedValueKey]! as String;
// Leading whitespace is added so that lines in the multiline
// description returned by addDescriptionOf are all indented equally
// which makes the output easier to read for this case.
return mismatchDescription
.add('expected normalized value\n ')
.addDescriptionOf(_value)
.add('\nbut got\n ')
.addDescriptionOf(actualValue);
}
return mismatchDescription;
}
}
Loading