feat(shorebird_cli): use specific Flutter revision (#307)

Co-authored-by: Felix Angelov <felix@shorebird.dev>
This commit is contained in:
Eric Seidel
2023-04-19 14:12:28 -04:00
committed by GitHub
parent 4ae350bbe7
commit 603c1113e9
15 changed files with 138 additions and 53 deletions
+1
View File
@@ -0,0 +1 @@
45fc514f1a9c347a3af76b02baf980a4d88b7879
+1
View File
@@ -9,6 +9,7 @@ BIN_DIR=$(cd "$(dirname "$BASH_SOURCE")"; cd -P "$(dirname "$(readlink "$BASH_SO
PROG_NAME="$BIN_DIR/$(basename "$BASH_SOURCE")"
OS="$(uname -s)"
FLUTTER_VERSION=`cat "$BIN_DIR/internal/flutter.version"`
source "$BIN_DIR/../third_party/flutter/bin/internal/shared.sh"
# We currently depend on a forked (3.7.8 stable) Flutter shared.sh script
+1 -2
View File
@@ -5,7 +5,6 @@ import 'package:archive/archive_io.dart';
import 'package:http/http.dart' as http;
import 'package:path/path.dart' as p;
import 'package:platform/platform.dart';
import 'package:shorebird_cli/src/engine_revision.dart';
import 'package:shorebird_cli/src/shorebird_environment.dart';
typedef ArchiveExtracter = Future<void> Function(
@@ -137,6 +136,6 @@ class PatchArtifact extends CachedArtifact {
artifactName += 'windows-x64.zip';
}
return 'shorebird/$shorebirdEngineRevision/$artifactName';
return 'shorebird/${ShorebirdEnvironment.shorebirdEngineRevision}/$artifactName';
}
}
@@ -3,7 +3,7 @@ import 'package:args/command_runner.dart';
import 'package:cli_completion/cli_completion.dart';
import 'package:mason_logger/mason_logger.dart';
import 'package:shorebird_cli/src/commands/commands.dart';
import 'package:shorebird_cli/src/engine_revision.dart';
import 'package:shorebird_cli/src/shorebird_environment.dart';
import 'package:shorebird_cli/src/version.dart';
const executableName = 'shorebird';
@@ -99,7 +99,7 @@ class ShorebirdCliCommandRunner extends CompletionCommandRunner<int> {
_logger.info(
'''
Shorebird $packageVersion
Shorebird Engine • revision $shorebirdEngineRevision''',
Shorebird Engine • revision ${ShorebirdEnvironment.shorebirdEngineRevision}''',
);
exitCode = ExitCode.success.code;
} else {
@@ -1,6 +1,7 @@
import 'package:collection/collection.dart';
import 'package:mason_logger/mason_logger.dart';
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/shorebird_environment.dart';
import 'package:shorebird_cli/src/shorebird_version_mixin.dart';
import 'package:shorebird_cli/src/validators/validators.dart';
import 'package:shorebird_cli/src/version.dart';
@@ -40,7 +41,7 @@ class DoctorCommand extends ShorebirdCommand with ShorebirdVersionMixin {
logger.info('''
Shorebird v$packageVersion
''');
Shorebird Engine • revision ${ShorebirdEnvironment.shorebirdEngineRevision}''');
var numIssues = 0;
for (final validator in validators) {
@@ -1,2 +0,0 @@
/// The hash of the Shorebird engine used by this version of Shorebird CLI.
const shorebirdEngineRevision = '8b89f8bd9fc6982aa9c4557fd0e5e89db1ff9986';
@@ -17,6 +17,34 @@ abstract class ShorebirdEnvironment {
static Directory get shorebirdRoot =>
File(platform.script.toFilePath()).parent.parent.parent;
static String get shorebirdEngineRevision {
return _shorebirdEngineRevision ??
File(
p.join(flutterDirectory.path, 'bin', 'internal', 'engine.version'),
).readAsStringSync();
}
static String? _shorebirdEngineRevision;
@visibleForTesting
static set shorebirdEngineRevision(String revision) {
_shorebirdEngineRevision = revision;
}
static String? _flutterRevision;
@visibleForTesting
static set flutterRevision(String revision) {
_flutterRevision = revision;
}
static String get flutterRevision {
return _flutterRevision ??
File(
p.join(shorebirdRoot.path, 'bin', 'internal', 'flutter.version'),
).readAsStringSync();
}
/// The root of the Shorebird-vended Flutter git checkout.
static Directory get flutterDirectory => Directory(
p.join(
@@ -86,6 +86,8 @@ abstract class ShorebirdProcess {
required String executable,
}) {
if (executable == 'flutter') {
// If this ever changes we also need to update the `shorebird` shell
// wrapper which downloads runs Flutter to fetch artifacts the first time.
return {'FLUTTER_STORAGE_BASE_URL': 'https://download.shorebird.dev/'};
}
@@ -45,10 +45,9 @@ class ShorebirdFlutterValidator extends Validator {
);
}
if (!await _flutterDirectoryTracksStable()) {
if (!await _flutterDirectoryTracksCorrectRevision()) {
final message =
'${ShorebirdEnvironment.flutterDirectory} is not on the "stable" '
'branch';
'''${ShorebirdEnvironment.flutterDirectory} is not on the correct revision''';
issues.add(
ValidationIssue(
severity: ValidationIssueSeverity.warning,
@@ -102,13 +101,15 @@ This can cause unexpected behavior if you are switching between the tools and th
.contains('nothing to commit, working tree clean');
}
Future<bool> _flutterDirectoryTracksStable() async {
Future<bool> _flutterDirectoryTracksCorrectRevision() async {
final result = await runProcess(
'git',
['--no-pager', 'branch'],
['rev-parse', 'HEAD'],
workingDirectory: ShorebirdEnvironment.flutterDirectory.path,
);
return result.stdout.toString().contains('* stable');
return result.stdout
.toString()
.contains(ShorebirdEnvironment.flutterRevision);
}
Future<String> _shorebirdFlutterVersion() => _getFlutterVersion(
@@ -6,7 +6,6 @@ import 'package:mocktail/mocktail.dart';
import 'package:path/path.dart' as p;
import 'package:platform/platform.dart';
import 'package:shorebird_cli/src/cache.dart';
import 'package:shorebird_cli/src/engine_revision.dart';
import 'package:shorebird_cli/src/shorebird_environment.dart';
import 'package:test/test.dart';
@@ -43,6 +42,7 @@ void main() {
shorebirdRoot = Directory.systemTemp.createTempSync();
ShorebirdEnvironment.platform = platform;
ShorebirdEnvironment.shorebirdEngineRevision = 'test-revision';
when(() => platform.isMacOS).thenReturn(true);
when(() => platform.isWindows).thenReturn(false);
@@ -121,7 +121,7 @@ void main() {
request.url,
equals(
Uri.parse(
'${cache.storageBaseUrl}/${cache.storageBucket}/shorebird/$shorebirdEngineRevision/patch-darwin-x64.zip',
'${cache.storageBaseUrl}/${cache.storageBucket}/shorebird/${ShorebirdEnvironment.shorebirdEngineRevision}/patch-darwin-x64.zip',
),
),
);
@@ -141,7 +141,7 @@ void main() {
request.url,
equals(
Uri.parse(
'${cache.storageBaseUrl}/${cache.storageBucket}/shorebird/$shorebirdEngineRevision/patch-windows-x64.zip',
'${cache.storageBaseUrl}/${cache.storageBucket}/shorebird/${ShorebirdEnvironment.shorebirdEngineRevision}/patch-windows-x64.zip',
),
),
);
@@ -161,7 +161,7 @@ void main() {
request.url,
equals(
Uri.parse(
'${cache.storageBaseUrl}/${cache.storageBucket}/shorebird/$shorebirdEngineRevision/patch-linux-x64.zip',
'${cache.storageBaseUrl}/${cache.storageBucket}/shorebird/${ShorebirdEnvironment.shorebirdEngineRevision}/patch-linux-x64.zip',
),
),
);
@@ -5,7 +5,7 @@ import 'package:cli_completion/cli_completion.dart';
import 'package:mason_logger/mason_logger.dart';
import 'package:mocktail/mocktail.dart';
import 'package:shorebird_cli/src/command_runner.dart';
import 'package:shorebird_cli/src/engine_revision.dart';
import 'package:shorebird_cli/src/shorebird_environment.dart';
import 'package:shorebird_cli/src/version.dart';
import 'package:test/test.dart';
@@ -22,6 +22,7 @@ void main() {
setUp(() {
logger = _MockLogger();
ShorebirdEnvironment.shorebirdEngineRevision = 'test-revision';
processResult = _MockProcessResult();
when(() => processResult.exitCode).thenReturn(ExitCode.success.code);
commandRunner = ShorebirdCliCommandRunner(logger: logger);
@@ -72,7 +73,7 @@ void main() {
() => logger.info(
'''
Shorebird $packageVersion
Shorebird Engine • revision $shorebirdEngineRevision''',
Shorebird Engine • revision ${ShorebirdEnvironment.shorebirdEngineRevision}''',
),
).called(1);
});
@@ -1,6 +1,7 @@
import 'package:mason_logger/mason_logger.dart';
import 'package:mocktail/mocktail.dart';
import 'package:shorebird_cli/src/commands/commands.dart';
import 'package:shorebird_cli/src/shorebird_environment.dart';
import 'package:shorebird_cli/src/validators/validators.dart';
import 'package:test/test.dart';
@@ -30,6 +31,8 @@ void main() {
logger = _MockLogger();
progress = _MockProgress();
ShorebirdEnvironment.shorebirdEngineRevision = 'test-revision';
when(() => logger.progress(any())).thenReturn(progress);
when(() => logger.info(any())).thenReturn(null);
@@ -0,0 +1,58 @@
import 'dart:io';
import 'package:mocktail/mocktail.dart';
import 'package:path/path.dart' as p;
import 'package:platform/platform.dart';
import 'package:shorebird_cli/src/shorebird_environment.dart';
import 'package:test/test.dart';
class _MockPlatform extends Mock implements Platform {}
void main() {
group('ShorebirdEnvironment', () {
late Platform platform;
late Directory shorebirdRoot;
late Uri platformScript;
setUp(() {
shorebirdRoot = Directory.systemTemp.createTempSync();
platformScript = Uri.file(
p.join(shorebirdRoot.path, 'bin', 'cache', 'shorebird.snapshot'),
);
platform = _MockPlatform();
ShorebirdEnvironment.platform = platform;
when(() => platform.script).thenReturn(platformScript);
});
group('flutterRevision', () {
test('returns correct revision', () {
const revision = 'test-revision';
File(p.join(shorebirdRoot.path, 'bin', 'internal', 'flutter.version'))
..createSync(recursive: true)
..writeAsStringSync(revision, flush: true);
expect(ShorebirdEnvironment.flutterRevision, equals(revision));
});
});
group('shorebirdEngineRevision', () {
test('returns correct revision', () {
const revision = 'test-revision';
File(
p.join(
shorebirdRoot.path,
'bin',
'cache',
'flutter',
'bin',
'internal',
'engine.version',
),
)
..createSync(recursive: true)
..writeAsStringSync(revision, flush: true);
expect(ShorebirdEnvironment.shorebirdEngineRevision, equals(revision));
});
});
});
}
@@ -14,16 +14,14 @@ class _MockPlatform extends Mock implements Platform {}
void main() {
group('ShorebirdFlutterValidator', () {
const gitStatusMessage = """
On branch stable
Your branch is up to date with 'origin/stable'.
const flutterRevision = '45fc514f1a9c347a3af76b02baf980a4d88b7879';
const gitStatusMessage = '''
HEAD detached at 45fc514f
nothing to commit, working tree clean
""";
''';
const gitBranchMessage = '''
main
* stable
const gitRevParseHeadMessage = '''
$flutterRevision
''';
const pathFlutterVersionMessage = '''
@@ -44,7 +42,7 @@ Tools • Dart 2.19.6 • DevTools 2.20.1
late Directory tempDir;
late ProcessResult pathFlutterVersionProcessResult;
late ProcessResult shorebirdFlutterVersionProcessResult;
late ProcessResult gitBranchProcessResult;
late ProcessResult gitRevParseHeadProcessResult;
late ProcessResult gitStatusProcessResult;
Directory flutterDirectory(Directory root) =>
@@ -64,13 +62,14 @@ Tools • Dart 2.19.6 • DevTools 2.20.1
tempDir = setupTempDirectory();
ShorebirdEnvironment.platform = _MockPlatform();
ShorebirdEnvironment.flutterRevision = flutterRevision;
when(() => ShorebirdEnvironment.platform.script)
.thenReturn(shorebirdScriptFile(tempDir).uri);
when(() => ShorebirdEnvironment.platform.environment).thenReturn({});
pathFlutterVersionProcessResult = _MockProcessResult();
shorebirdFlutterVersionProcessResult = _MockProcessResult();
gitBranchProcessResult = _MockProcessResult();
gitRevParseHeadProcessResult = _MockProcessResult();
gitStatusProcessResult = _MockProcessResult();
validator = ShorebirdFlutterValidator(
@@ -85,8 +84,8 @@ Tools • Dart 2.19.6 • DevTools 2.20.1
if (executable == 'git') {
if (arguments.equals(['status'])) {
return gitStatusProcessResult;
} else if (arguments.equals(['--no-pager', 'branch'])) {
return gitBranchProcessResult;
} else if (arguments.equals(['rev-parse', 'HEAD'])) {
return gitRevParseHeadProcessResult;
}
} else if (executable == 'flutter') {
if (arguments.equals(['--version'])) {
@@ -109,7 +108,8 @@ Tools • Dart 2.19.6 • DevTools 2.20.1
.thenReturn(shorebirdFlutterVersionMessage);
when(() => shorebirdFlutterVersionProcessResult.stderr).thenReturn('');
when(() => shorebirdFlutterVersionProcessResult.exitCode).thenReturn(0);
when(() => gitBranchProcessResult.stdout).thenReturn(gitBranchMessage);
when(() => gitRevParseHeadProcessResult.stdout)
.thenReturn(gitRevParseHeadMessage);
when(() => gitStatusProcessResult.stdout).thenReturn(gitStatusMessage);
});
@@ -141,16 +141,15 @@ Tools • Dart 2.19.6 • DevTools 2.20.1
});
test('warns when Flutter does not track stable', () async {
when(() => gitBranchProcessResult.stdout).thenReturn('''
* main
stable
when(() => gitRevParseHeadProcessResult.stdout).thenReturn('''
62bd79521d
''');
final results = await validator.validate();
expect(results, hasLength(1));
expect(results.first.severity, ValidationIssueSeverity.warning);
expect(results.first.message, contains('is not on the "stable" branch'));
expect(results.first.message, contains('is not on the correct revision'));
});
test(
+10 -17
View File
@@ -11,10 +11,14 @@ unset CDPATH
# Either clones or pulls the Shorebird Flutter repository, depending on whether FLUTTER_PATH exists.
function update_flutter {
if [[ -d "$FLUTTER_PATH" ]]; then
git --git-dir="$FLUTTER_PATH/.git" --work-tree="$FLUTTER_PATH" pull
git -C "$FLUTTER_PATH" fetch
else
git clone --filter=tree:0 https://github.com/shorebirdtech/flutter.git -b stable "$FLUTTER_PATH"
git clone --filter=tree:0 https://github.com/shorebirdtech/flutter.git --no-checkout "$FLUTTER_PATH"
fi
# -c to avoid printing a warning about being in a detached head state.
git -C "$FLUTTER_PATH" -c advice.detachedHead=false checkout "$FLUTTER_VERSION"
SHOREBIRD_ENGINE_VERSION=`cat "$FLUTTER_PATH/bin/internal/engine.version"`
echo "Shorebird Engine • revision $SHOREBIRD_ENGINE_VERSION"
# Install Shorebird Flutter Artifacts
FLUTTER_STORAGE_BASE_URL=https://download.shorebird.dev/ $FLUTTER_PATH/bin/flutter --version
}
@@ -23,7 +27,7 @@ function pub_upgrade_with_retry {
local total_tries="10"
local remaining_tries=$((total_tries - 1))
while [[ "$remaining_tries" -gt 0 ]]; do
(cd "$SHOREBIRD_CLI_DIR" && dart pub upgrade) && break
(cd "$SHOREBIRD_CLI_DIR" && $DART_PATH pub upgrade) && break
>&2 echo "Error: Unable to 'pub upgrade' shorebird. Retrying in five seconds... ($remaining_tries tries left)"
remaining_tries=$((remaining_tries - 1))
sleep 5
@@ -161,7 +165,7 @@ function upgrade_shorebird () (
fi
# Compile...
dart --verbosity=error --disable-dart-dev --snapshot="$SNAPSHOT_PATH" --snapshot-kind="app-jit" --packages="$SHOREBIRD_CLI_DIR/.dart_tool/package_config.json" --no-enable-mirrors "$SCRIPT_PATH" > /dev/null
$DART_PATH --verbosity=error --disable-dart-dev --snapshot="$SNAPSHOT_PATH" --snapshot-kind="app-jit" --packages="$SHOREBIRD_CLI_DIR/.dart_tool/package_config.json" --no-enable-mirrors "$SCRIPT_PATH" > /dev/null
echo "$compilekey" > "$STAMP_PATH"
# Delete any temporary snapshot path.
@@ -185,6 +189,7 @@ function shared::execute() {
STAMP_PATH="$SHOREBIRD_ROOT/bin/cache/shorebird.stamp"
SCRIPT_PATH="$SHOREBIRD_CLI_DIR/bin/shorebird.dart"
FLUTTER_PATH="$SHOREBIRD_ROOT/bin/cache/flutter"
export DART_PATH="$FLUTTER_PATH/bin/cache/dart-sdk/bin/dart"
# Test if running as superuser but don't warn if running within Docker or CI.
if [[ "$EUID" == "0" && ! -f /.dockerenv && "$CI" != "true" && "$BOT" != "true" && "$CONTINUOUS_INTEGRATION" != "true" ]]; then
@@ -200,18 +205,6 @@ function shared::execute() {
exit 1
fi
# Test if Dart is available on the Host
if ! hash dart 2>/dev/null; then
>&2 echo "Error: Unable to find dart in your PATH."
exit 1
fi
# Test if Flutter is available on the Host
if ! hash flutter 2>/dev/null; then
>&2 echo "Error: Unable to find flutter in your PATH."
exit 1
fi
# Test if the shorebird directory is a git clone (otherwise git rev-parse HEAD
# would fail)
if [[ ! -e "$SHOREBIRD_ROOT/.git" ]]; then
@@ -227,7 +220,7 @@ function shared::execute() {
BIN_NAME="$(basename "$PROG_NAME")"
case "$BIN_NAME" in
shorebird*)
exec "dart" "$SNAPSHOT_PATH" "$@"
exec "$DART_PATH" "$SNAPSHOT_PATH" "$@"
;;
*)
>&2 echo "Error! Executable name $BIN_NAME not recognized!"