feat(shorebird_cli): use specific Flutter revision (#307)
Co-authored-by: Felix Angelov <felix@shorebird.dev>
This commit is contained in:
@@ -0,0 +1 @@
|
||||
45fc514f1a9c347a3af76b02baf980a4d88b7879
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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!"
|
||||
|
||||
Reference in New Issue
Block a user