diff --git a/dev/snippets/lib/main.dart b/dev/snippets/lib/main.dart index a9d2dd6adee..6fa01276980 100644 --- a/dev/snippets/lib/main.dart +++ b/dev/snippets/lib/main.dart @@ -2,10 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:io'; +import 'dart:io' show exit, stderr, stdout, File, ProcessResult; import 'package:args/args.dart'; +import 'package:meta/meta.dart'; import 'package:path/path.dart' as path; +import 'package:platform/platform.dart'; +import 'package:process/process.dart'; import 'configuration.dart'; import 'snippets.dart'; @@ -30,9 +33,22 @@ class GitStatusFailed implements Exception { String toString() => 'git status exited with a non-zero exit code: ${gitResult.exitCode}:\n${gitResult.stderr}\n${gitResult.stdout}'; } -String getChannelName() { +/// Get the name of the channel these docs are from. +/// +/// First check env variable LUCI_BRANCH, then refer to the currently +/// checked out git branch. +String getChannelName({ + @visibleForTesting + Platform platform = const LocalPlatform(), + @visibleForTesting + ProcessManager processManager = const LocalProcessManager(), +}) { + final String? envReleaseChannel = platform.environment['LUCI_BRANCH']?.trim(); + if (['master', 'stable'].contains(envReleaseChannel)) { + return envReleaseChannel!; + } final RegExp gitBranchRegexp = RegExp(r'^## (?.*)'); - final ProcessResult gitResult = Process.runSync('git', ['status', '-b', '--porcelain'], + final ProcessResult gitResult = processManager.runSync(['git', 'status', '-b', '--porcelain'], environment: { 'GIT_TRACE': '2', 'GIT_TRACE_SETUP': '2' @@ -64,7 +80,8 @@ String getChannelNameWithRetries() { /// Generates snippet dartdoc output for a given input, and creates any sample /// applications needed by the snippet. void main(List argList) { - final Map environment = Platform.environment; + const Platform platform = LocalPlatform(); + final Map environment = platform.environment; final ArgParser parser = ArgParser(); final List snippetTypes = SnippetType.values.map((SnippetType type) => getEnumName(type)).toList(); diff --git a/dev/snippets/pubspec.yaml b/dev/snippets/pubspec.yaml index 8184ca46ec3..e51796cdeeb 100644 --- a/dev/snippets/pubspec.yaml +++ b/dev/snippets/pubspec.yaml @@ -15,6 +15,7 @@ dependencies: dart_style: 2.0.2 meta: 1.7.0 platform: 3.0.0 + process: 4.2.1 _fe_analyzer_shared: 23.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -95,4 +96,4 @@ executables: vm_service_client: 0.2.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 1.0.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 38c6 +# PUBSPEC CHECKSUM: ba17 diff --git a/dev/snippets/test/snippets_test.dart b/dev/snippets/test/snippets_test.dart index 88c88debae2..7e54896d6e8 100644 --- a/dev/snippets/test/snippets_test.dart +++ b/dev/snippets/test/snippets_test.dart @@ -3,10 +3,12 @@ // found in the LICENSE file. import 'dart:convert'; -import 'dart:io' hide Platform; - +import 'dart:io' show Directory, File, Process, ProcessResult, ProcessSignal, ProcessStartMode, SystemEncoding; import 'package:path/path.dart' as path; +import 'package:platform/platform.dart'; +import 'package:process/process.dart'; import 'package:snippets/configuration.dart'; +import 'package:snippets/main.dart' show getChannelName; import 'package:snippets/snippets.dart'; import 'package:test/test.dart' hide TypeMatcher, isInstanceOf; @@ -215,4 +217,118 @@ void main() { expect(json['sourcePath'], equals('some/path.dart')); }); }); + + group('getChannelName()', () { + test('does not call git if LUCI_BRANCH env var provided', () { + const String branch = 'stable'; + final FakePlatform platform = FakePlatform( + environment: {'LUCI_BRANCH': branch}, + ); + final FakeProcessManager processManager = FakeProcessManager([]); + expect( + getChannelName( + platform: platform, + processManager: processManager, + ), + branch, + ); + expect(processManager.hasRemainingExpectations, false); + }); + + test('calls git if LUCI_BRANCH env var is not provided', () { + const String branch = 'stable'; + final FakePlatform platform = FakePlatform( + environment: {}, + ); + final ProcessResult result = ProcessResult(0, 0, '## $branch...refs/heads/master', ''); + final FakeProcessManager processManager = FakeProcessManager( + [FakeCommand('git status -b --porcelain', result)], + ); + expect( + getChannelName( + platform: platform, + processManager: processManager, + ), + branch, + ); + expect(processManager.hasRemainingExpectations, false); + }); + }); +} + +const SystemEncoding systemEncoding = SystemEncoding(); + +class FakeCommand { + FakeCommand(this.command, [ProcessResult? result]) : _result = result; + final String command; + + final ProcessResult? _result; + ProcessResult get result => _result ?? ProcessResult(0, 0, '', ''); +} + +class FakeProcessManager implements ProcessManager { + FakeProcessManager(this.remainingExpectations); + + final List remainingExpectations; + + @override + bool canRun(dynamic command, {String? workingDirectory}) => true; + + @override + Future start( + List command, { + String? workingDirectory, + Map? environment, + bool includeParentEnvironment = true, + bool runInShell = false, + ProcessStartMode mode = ProcessStartMode.normal, + }) { + throw Exception('not implemented'); + } + + @override + Future run( + List command, { + String? workingDirectory, + Map? environment, + bool includeParentEnvironment = true, + bool runInShell = false, + Encoding stdoutEncoding = systemEncoding, + Encoding stderrEncoding = systemEncoding, + }) { + throw Exception('not implemented'); + } + + @override + ProcessResult runSync( + List command, { + String? workingDirectory, + Map? environment, + bool includeParentEnvironment = true, + bool runInShell = false, + Encoding stdoutEncoding = systemEncoding, + Encoding stderrEncoding = systemEncoding, + }) { + if (remainingExpectations.isEmpty) { + fail( + 'Called FakeProcessManager with $command when no further commands were expected!', + ); + } + final FakeCommand expectedCommand = remainingExpectations.removeAt(0); + final String expectedName = expectedCommand.command; + final String actualName = command.join(' '); + if (expectedName != actualName) { + fail( + 'FakeProcessManager expected the command $expectedName but received $actualName', + ); + } + return expectedCommand.result; + } + + bool get hasRemainingExpectations => remainingExpectations.isNotEmpty; + + @override + bool killPid(int pid, [ProcessSignal signal = ProcessSignal.sigterm]) { + throw Exception('not implemented'); + } }