Skip to content

Commit

Permalink
Flutter support among other things
Browse files Browse the repository at this point in the history
Prepare to publish v3

Fixes #12
  • Loading branch information
kevmoo committed Dec 6, 2021
1 parent 612d08f commit 98e212e
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 61 deletions.
62 changes: 40 additions & 22 deletions .github/workflows/ci.yml
Expand Up @@ -36,30 +36,48 @@ jobs:
run: dart analyze --fatal-infos
if: always() && steps.install.outcome == 'success'

# Run tests on a matrix consisting of two dimensions:
# 1. OS: ubuntu-latest, (macos-latest, windows-latest)
# 2. release channel: dev
test:
needs: analyze
test_dart:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
# Add macos-latest and/or windows-latest if relevant for this package.
os: [ubuntu-latest]
sdk: [2.12.0, dev]
os: [ubuntu-latest, macos-latest, windows-latest]
sdk: [2.12.3, dev]
steps:
- uses: actions/checkout@v2
- uses: dart-lang/setup-dart@v1.0
with:
sdk: ${{ matrix.sdk }}
- id: install
run: dart pub get
- name: make git happy
run: |
git config --global user.email "you@example.com"
git config --global user.name "Your Name"
- run: dart test -x presubmit-only
if: always() && steps.install.outcome == 'success'
- run: dart test --run-skipped -t presubmit-only
if: always() && steps.install.outcome == 'success'
- uses: actions/checkout@v2
- uses: dart-lang/setup-dart@v1.0
with:
sdk: ${{ matrix.sdk }}
- id: install
run: dart pub get
- name: make git happy
run: |
git config --global user.email "you@example.com"
git config --global user.name "Your Name"
- run: dart test -x presubmit-only
if: always() && steps.install.outcome == 'success'
- run: dart test --run-skipped -t presubmit-only
if: always() && steps.install.outcome == 'success'

test_flutter:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
flutter-channel: [beta, stable]
steps:
- uses: actions/checkout@v2
- uses: subosito/flutter-action@v1.5.3
with:
flutter-channel: ${{ matrix.flutter-channel }}
- id: install
run: dart pub get
- name: make git happy
run: |
git config --global user.email "you@example.com"
git config --global user.name "Your Name"
- run: flutter test -x presubmit-only
if: always() && steps.install.outcome == 'success'
- run: flutter test --run-skipped -t presubmit-only
if: always() && steps.install.outcome == 'success'
8 changes: 7 additions & 1 deletion CHANGELOG.md
@@ -1,4 +1,10 @@
## 2.0.1-dev
## 3.0.0

- `expectBuildClean` is now async. (Returns `Future<void>` instead of `void`.)
- `defaultCommand` now uses `dart run build_runner...`.
- Now supports `flutter test`.
- Executed commands are now printed to the console.
- Require Dart `2.12.3`.

## 2.0.0

Expand Down
5 changes: 3 additions & 2 deletions lib/build_verify.dart
Expand Up @@ -2,8 +2,9 @@ import 'dart:io';

import 'src/impl.dart';

/// The default value for `customCommand` in [expectBuildClean].
const defaultCommand = [
pubPlaceHolder,
dartPlaceHolder,
'run',
'build_runner',
'build',
Expand All @@ -18,7 +19,7 @@ const defaultCommand = [
/// If the first value is `PUB` or `DART` (case-sensitive), it will be replaced
/// with the full, platform-specific path to the corresponding executable in the
/// currently executing SDK.
void expectBuildClean({
Future<void> expectBuildClean({
String? packageRelativeDirectory,
List<String> customCommand = defaultCommand,
}) =>
Expand Down
65 changes: 46 additions & 19 deletions lib/src/impl.dart
@@ -1,23 +1,25 @@
import 'dart:convert';
import 'dart:io';

import 'package:io/ansi.dart' as ansi;
import 'package:path/path.dart' as p;
import 'package:test/test.dart';

import 'utils.dart';

const pubPlaceHolder = 'PUB';
const dartPlaceHolder = 'DART';

void expectBuildCleanImpl(
Future<void> expectBuildCleanImpl(
String workingDir,
List<String> command, {
String? packageRelativeDirectory,
}) {
}) async {
if (command.isEmpty) {
throw ArgumentError.value(command, 'customCommand', 'Cannot be empty');
}

final repoRoot =
_runProc('git', ['rev-parse', '--show-toplevel'], workingDir);
await _runProc('git', ['rev-parse', '--show-toplevel'], workingDir);
final pkgDir = p.join(repoRoot, packageRelativeDirectory);
if (!p.equals(pkgDir, workingDir)) {
throw StateError('Expected the git root ($repoRoot) '
Expand All @@ -26,45 +28,70 @@ void expectBuildCleanImpl(

// 1 - get a list of modified files files - should be empty
expect(
_changedGeneratedFiles(workingDir),
await _changedGeneratedFiles(workingDir),
isEmpty,
reason: 'The working directory should be clean before running build.',
);

var executable = command.first;
if (executable == pubPlaceHolder) {
executable = pubPath;
} else if (executable == 'DART') {
if (executable == 'DART') {
executable = dartPath;
}

final arguments = command.skip(1).toList();

// 2 - run build - should be no output, since nothing should change
final result = _runProc(executable, arguments, workingDir);
final result = await _runProc(executable, arguments, workingDir);

expectResultOutputSucceeds(result);

// 3 - get a list of modified files after the build - should still be empty
expect(_changedGeneratedFiles(workingDir), isEmpty);
expect(await _changedGeneratedFiles(workingDir), isEmpty);
}

void expectResultOutputSucceeds(String result) {
expect(result,
contains(RegExp(r'\[INFO\] Succeeded after .+ with \d+ outputs')));
}

String _changedGeneratedFiles(String workingDir) =>
Future<String> _changedGeneratedFiles(String workingDir) =>
_runProc('git', ['diff'], workingDir);

String _runProc(String proc, List<String> args, String workingDir) {
final result = Process.runSync(proc, args, workingDirectory: workingDir);

if (result.exitCode != 0) {
print(result.stdout);
print(result.stderr);
throw ProcessException(proc, args, 'Process failed', result.exitCode);
Future<String> _runProc(
String proc, List<String> args, String workingDir) async {
print('Running: `${ansi.cyan.wrap([
proc,
...args
].join(' '))}` in `${ansi.cyan.wrap(workingDir)}`');

final process = await Process.start(proc, args, workingDirectory: workingDir);

Future<void> transform(
Stream<List<int>> standardChannel,
List<String> lines,
) =>
standardChannel
.transform(const SystemEncoding().decoder)
.transform(const LineSplitter())
.forEach((element) {
print(element);
lines.add(element);
});

final stdoutContent = <String>[];
final stderrContent = <String>[];

final result = await Future.wait([
process.exitCode,
transform(process.stderr, stderrContent),
transform(process.stdout, stdoutContent),
]);

final exitCode = result.first as int;

if (exitCode != 0) {
throw ProcessException(proc, args, 'Process failed', exitCode);
}

return (result.stdout as String).trim();
return stdoutContent.join('\n').trim();
}
22 changes: 12 additions & 10 deletions lib/src/utils.dart
Expand Up @@ -3,15 +3,17 @@ import 'dart:io';
import 'package:path/path.dart' as p;

/// The path to the root directory of the SDK.
final String _sdkDir = (() {
// The Dart executable is in "/path/to/sdk/bin/dart", so two levels up is
// "/path/to/sdk".
final aboveExecutable = p.dirname(p.dirname(Platform.resolvedExecutable));
assert(FileSystemEntity.isFileSync(p.join(aboveExecutable, 'version')));
return aboveExecutable;
})();
final String dartPath = (() {
final executableBaseName = p.basename(Platform.resolvedExecutable);

final String pubPath =
p.join(_sdkDir, 'bin', Platform.isWindows ? 'pub.bat' : 'pub');
if (executableBaseName == 'flutter_tester') {
final flutterRoot = Platform.environment['FLUTTER_ROOT']!;

final String dartPath = p.join(_sdkDir, 'bin', 'dart');
return p.join(flutterRoot, 'bin', 'cache', 'dart-sdk', 'bin', 'dart');
} else {
assert(executableBaseName == 'dart');
// The Dart executable is in "/path/to/sdk/bin/dart", so two levels up is
// "/path/to/sdk".
return Platform.resolvedExecutable;
}
})();
2 changes: 1 addition & 1 deletion lib/src/version.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions pubspec.yaml
Expand Up @@ -2,13 +2,14 @@ name: build_verify
description: >-
Test utility to ensure generated Dart code within a package is up-to-date
when using package:build.
version: 2.0.1-dev
version: 3.0.0
repository: https://github.com/kevmoo/build_verify

environment:
sdk: '>=2.12.0 <3.0.0'
sdk: '>=2.12.3 <3.0.0'

dependencies:
io: ^1.0.0
path: ^1.0.0
test: ^1.0.0

Expand Down
6 changes: 5 additions & 1 deletion test/ensure_build_test.dart
Expand Up @@ -4,5 +4,9 @@ import 'package:build_verify/build_verify.dart';
import 'package:test/test.dart';

void main() {
test('ensure_build', expectBuildClean);
test(
'ensure_build',
expectBuildClean,
timeout: const Timeout.factor(2),
);
}
8 changes: 5 additions & 3 deletions test/integration_test.dart
Expand Up @@ -35,13 +35,15 @@ const packageVersion = '1.2.3';
await gitDir.runCommand(['commit', '-am', 'test']);

final process = await TestProcess.start(
pubPath, ['get', '--offline', '--no-precompile'],
workingDirectory: d.sandbox);
dartPath,
['pub', 'get'],
workingDirectory: d.sandbox,
);

await process.shouldExit(0);
});

test('success unit test', () async {
expectBuildCleanImpl(d.sandbox, defaultCommand);
await expectBuildCleanImpl(d.sandbox, defaultCommand);
});
}

0 comments on commit 98e212e

Please sign in to comment.