feat(shorebird_cli): shorebird init (#72)

This commit is contained in:
Felix Angelov
2023-03-15 11:32:59 -05:00
committed by GitHub
parent f2d70032e6
commit d9a4ce2ecd
10 changed files with 489 additions and 266 deletions
+52 -4
View File
@@ -14,9 +14,37 @@ dart pub global activate --source git https://github.com/shorebirdtech/shorebird
## Commands
### Init
Get started by initializing shorebird in your current project.
```bash
shorebird init
```
**Sample**
```
shorebird init
✓ Initialized Shorebird (27ms)
🐦 Shorebird initialized successfully!
✅ A "shorebird.yaml" has been created.
✅ The "pubspec.yaml" has been updated to include "shorebird.yaml" as an asset.
Reference the following commands to get started:
🚙 To run your project use: "shorebird run".
📦 To build your project use: "shorebird build".
🚀 To publish a new update use: "shorebird publish".
For more information, visit https://shorebird.dev
```
### Login
Get started by requesting an API key and using `shorebird login` to authenticate:
Request an API key and use `shorebird login` to authenticate:
```bash
shorebird login
@@ -24,7 +52,7 @@ shorebird login
**Sample**
```bash
```
shorebird login
? Please enter your API Key: <API-KEY>
✓ Logging into shorebird.dev (7ms)
@@ -41,11 +69,27 @@ shorebird logout
**Sample**
```bash
```
shorebird logout
✓ Logging out of shorebird.dev (1ms)
```
### List Apps
List all existing apps in Shorebird using the `shorebird apps list` command:
```bash
shorebird apps list
```
**Sample**
```
shorebird apps list
my-counter: v1.0.0 (patch #1)
my-example: v2.1.0 (patch #2)
```
### Run
Run an existing application using the Shorebird Engine via the `shorebird run` command:
@@ -54,7 +98,7 @@ Run an existing application using the Shorebird Engine via the `shorebird run` c
shorebird run
```
**❗️Note**: If it's the first time, `shorebird run` will download and build the shorebird engine which may take some time. The shorebird engine will be cached for subsequent runs.
**❗️Note**: If it's the first time using shorebird, `shorebird run` will download and build the shorebird engine which may take some time. The shorebird engine will be cached for subsequent runs.
### Build
@@ -64,6 +108,8 @@ Build a new release of your application using the `shorebird build` command:
shorebird build
```
**❗️Note**: If it's the first time using shorebird, `shorebird build` will download and build the shorebird engine which may take some time. The shorebird engine will be cached for subsequent runs.
### Publish
The publish command allows developers to publish new releases of their Flutter application to the Shorebird CodePush API. These updates are then pushed directly to users' devices.
@@ -89,7 +135,9 @@ Global options:
--[no-]verbose Noisy logging, including all shell commands executed.
Available commands:
apps Manage your Shorebird apps.
build Build a new release of your application.
init Initialize Shorebird.
login Login as a new Shorebird user.
logout Logout of the current Shorebird user
publish Publish an update.
@@ -37,6 +37,7 @@ class ShorebirdCliCommandRunner extends CompletionCommandRunner<int> {
addCommand(AppsCommand(logger: _logger));
addCommand(BuildCommand(logger: _logger));
addCommand(InitCommand(logger: _logger));
addCommand(LoginCommand(logger: _logger));
addCommand(LogoutCommand(logger: _logger));
addCommand(PublishCommand(logger: _logger));
@@ -1,5 +1,6 @@
export 'apps/apps.dart';
export 'build_command.dart';
export 'init_command.dart';
export 'login_command.dart';
export 'logout_command.dart';
export 'publish_command.dart';
@@ -0,0 +1,127 @@
import 'dart:io';
import 'package:mason_logger/mason_logger.dart';
import 'package:path/path.dart' as p;
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/config/config.dart';
import 'package:shorebird_cli/src/shorebird_config_mixin.dart';
import 'package:yaml/yaml.dart';
import 'package:yaml_edit/yaml_edit.dart';
/// {@template init_command}
///
/// `shorebird init`
/// Initialize Shorebird.
/// {@endtemplate}
class InitCommand extends ShorebirdCommand with ShorebirdConfigMixin {
/// {@macro init_command}
InitCommand({required super.logger, super.buildUuid});
@override
String get description => 'Initialize Shorebird.';
@override
String get name => 'init';
@override
Future<int> run() async {
final progress = logger.progress('Initializing Shorebird');
try {
if (!hasPubspecYaml) {
logger.err('Could not find a "pubspec.yaml".');
return ExitCode.noInput.code;
}
} catch (error) {
logger.err('Error parsing "pubspec.yaml": $error');
return ExitCode.software.code;
}
progress.update('Creating "shorebird.yaml"');
try {
if (hasShorebirdYaml) {
progress.update('"shorebird.yaml" already exists.');
} else {
_addShorebirdYamlToProject();
progress.update('Generated a "shorebird.yaml".');
}
} catch (error) {
progress.fail();
logger.err('Error creating "shorebird.yaml".\n$error');
return ExitCode.software.code;
}
progress.update('Adding "shorebird.yaml" to "pubspec.yaml" assets');
if (pubspecContainsShorebirdYaml) {
progress.update('"shorebird.yaml" already in "pubspec.yaml" assets.');
} else {
_addShorebirdYamlToPubspecAssets();
}
progress.complete('Initialized Shorebird');
logger.info(
'''
${lightGreen.wrap('🐦 Shorebird initialized successfully!')}
✅ A "shorebird.yaml" has been created.
✅ The "pubspec.yaml" has been updated to include "shorebird.yaml" as an asset.
Reference the following commands to get started:
🚙 To run your project use: "${lightCyan.wrap('shorebird run')}".
📦 To build your project use: "${lightCyan.wrap('shorebird build')}".
🚀 To publish a new update use: "${lightCyan.wrap('shorebird publish')}".
For more information about Shorebird, visit ${link(uri: Uri.parse('https://shorebird.dev'))}''',
);
return ExitCode.success.code;
}
ShorebirdYaml _addShorebirdYamlToProject() {
final productId = buildUuid();
File(
p.join(Directory.current.path, 'shorebird.yaml'),
).writeAsStringSync('''
# This file is used to configure the Shorebird CLI.
# Learn more at https://shorebird.dev
# This is the unique identifier for your app.
product_id: $productId
''');
return ShorebirdYaml(productId: productId);
}
void _addShorebirdYamlToPubspecAssets() {
final pubspecFile = File(p.join(Directory.current.path, 'pubspec.yaml'));
final pubspecContents = pubspecFile.readAsStringSync();
final yaml = loadYaml(pubspecContents, sourceUrl: pubspecFile.uri) as Map;
final editor = YamlEditor(pubspecContents);
if (!yaml.containsKey('flutter')) {
editor.update(
['flutter'],
{
'assets': ['shorebird.yaml']
},
);
} else {
if (!(yaml['flutter'] as Map).containsKey('assets')) {
editor.update(['flutter', 'assets'], ['shorebird.yaml']);
} else {
final assets = (yaml['flutter'] as Map)['assets'] as List;
if (!assets.contains('shorebird.yaml')) {
editor.update(['flutter', 'assets'], [...assets, 'shorebird.yaml']);
}
}
}
if (editor.edits.isEmpty) return;
pubspecFile.writeAsStringSync(editor.toString());
}
}
@@ -1,20 +1,16 @@
import 'dart:io';
import 'package:checked_yaml/checked_yaml.dart';
import 'package:mason_logger/mason_logger.dart';
import 'package:path/path.dart' as p;
import 'package:pubspec_parse/pubspec_parse.dart';
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/config/shorebird_yaml.dart';
import 'package:yaml/yaml.dart';
import 'package:yaml_edit/yaml_edit.dart';
import 'package:shorebird_cli/src/shorebird_config_mixin.dart';
/// {@template publish_command}
///
/// `shorebird publish <path/to/artifact>`
/// Publish new releases to the Shorebird CodePush server.
/// {@endtemplate}
class PublishCommand extends ShorebirdCommand {
class PublishCommand extends ShorebirdCommand with ShorebirdConfigMixin {
/// {@macro publish_command}
PublishCommand({
required super.logger,
@@ -31,6 +27,13 @@ class PublishCommand extends ShorebirdCommand {
@override
Future<int> run() async {
if (!isShorebirdInitialized) {
logger.err(
'Shorebird is not initialized. Did you run "shorebird init"?',
);
return ExitCode.config.code;
}
final session = auth.currentSession;
if (session == null) {
logger.err('You must be logged in to publish.');
@@ -42,45 +45,6 @@ class PublishCommand extends ShorebirdCommand {
usageException('A single file path must be specified.');
}
late final Pubspec? pubspecYaml;
try {
pubspecYaml = _readPubspecYaml();
if (pubspecYaml == null) {
logger.err('Could not find a "pubspec.yaml".');
return ExitCode.noInput.code;
}
} catch (error) {
logger.err('Error parsing "pubspec.yaml": $error');
return ExitCode.software.code;
}
late final String productId;
late final ShorebirdYaml? shorebirdYaml;
try {
shorebirdYaml = _readShorebirdYaml();
} catch (error) {
logger.err('Error parsing "shorebird.yaml": $error');
return ExitCode.software.code;
}
if (shorebirdYaml == null) {
productId = buildUuid();
File(
p.join(Directory.current.path, 'shorebird.yaml'),
).writeAsStringSync('''
# This file is used to configure the Shorebird CLI.
# Learn more at https://shorebird.dev
# This is the unique identifier for your app.
product_id: $productId
''');
logger.info('Generated a "shorebird.yaml".');
} else {
productId = shorebirdYaml.productId;
}
_addShorebirdYamlToAssets();
final artifactPath = args.isEmpty
? p.join(
Directory.current.path,
@@ -103,15 +67,17 @@ product_id: $productId
}
try {
final pubspecYaml = getPubspecYaml()!;
final shorebirdYaml = getShorebirdYaml()!;
final codePushClient = buildCodePushClient(apiKey: session.apiKey);
logger.detail(
'Deploying ${artifact.path} to $productId (${pubspecYaml.version})',
'''Deploying ${artifact.path} to ${shorebirdYaml.productId} (${pubspecYaml.version})''',
);
final version = pubspecYaml.version!;
await codePushClient.createPatch(
artifactPath: artifact.path,
baseVersion: '${version.major}.${version.minor}.${version.patch}',
productId: productId,
productId: shorebirdYaml.productId,
channel: 'stable',
);
} catch (error) {
@@ -122,48 +88,4 @@ product_id: $productId
logger.success('Successfully deployed.');
return ExitCode.success.code;
}
ShorebirdYaml? _readShorebirdYaml() {
final file = File(p.join(Directory.current.path, 'shorebird.yaml'));
if (!file.existsSync()) return null;
final yaml = file.readAsStringSync();
return checkedYamlDecode(yaml, (m) => ShorebirdYaml.fromJson(m!));
}
Pubspec? _readPubspecYaml() {
final file = File(p.join(Directory.current.path, 'pubspec.yaml'));
if (!file.existsSync()) return null;
final yaml = file.readAsStringSync();
return Pubspec.parse(yaml);
}
void _addShorebirdYamlToAssets() {
final pubspecFile = File(p.join(Directory.current.path, 'pubspec.yaml'));
final pubspecContents = pubspecFile.readAsStringSync();
final yaml = loadYaml(pubspecContents, sourceUrl: pubspecFile.uri) as Map;
final editor = YamlEditor(pubspecContents);
if (!yaml.containsKey('flutter')) {
editor.update(
['flutter'],
{
'assets': ['shorebird.yaml']
},
);
} else {
if (!(yaml['flutter'] as Map).containsKey('assets')) {
editor.update(['flutter', 'assets'], ['shorebird.yaml']);
} else {
final assets = (yaml['flutter'] as Map)['assets'] as List;
if (!assets.contains('shorebird.yaml')) {
editor.update(['flutter', 'assets'], [...assets, 'shorebird.yaml']);
}
}
}
if (editor.edits.isNotEmpty) {
pubspecFile.writeAsStringSync(editor.toString());
logger.info('Added "shorebird.yaml" to "pubspec.yaml".');
}
}
}
@@ -0,0 +1 @@
export 'shorebird_yaml.dart';
@@ -0,0 +1,42 @@
import 'dart:io';
import 'package:checked_yaml/checked_yaml.dart';
import 'package:path/path.dart' as p;
import 'package:pubspec_parse/pubspec_parse.dart';
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/config/config.dart';
import 'package:yaml/yaml.dart';
mixin ShorebirdConfigMixin on ShorebirdCommand {
bool get hasShorebirdYaml => getShorebirdYaml() != null;
bool get hasPubspecYaml => getPubspecYaml() != null;
bool get isShorebirdInitialized {
return hasShorebirdYaml && pubspecContainsShorebirdYaml;
}
bool get pubspecContainsShorebirdYaml {
final file = File(p.join(Directory.current.path, 'pubspec.yaml'));
final pubspecContents = file.readAsStringSync();
final yaml = loadYaml(pubspecContents, sourceUrl: file.uri) as Map;
if (!yaml.containsKey('flutter')) return false;
if (!(yaml['flutter'] as Map).containsKey('assets')) return false;
final assets = (yaml['flutter'] as Map)['assets'] as List;
return assets.contains('shorebird.yaml');
}
ShorebirdYaml? getShorebirdYaml() {
final file = File(p.join(Directory.current.path, 'shorebird.yaml'));
if (!file.existsSync()) return null;
final yaml = file.readAsStringSync();
return checkedYamlDecode(yaml, (m) => ShorebirdYaml.fromJson(m!));
}
Pubspec? getPubspecYaml() {
final file = File(p.join(Directory.current.path, 'pubspec.yaml'));
if (!file.existsSync()) return null;
final yaml = file.readAsStringSync();
return Pubspec.parse(yaml);
}
}
@@ -8,5 +8,6 @@ void main() {
test(
'ensure_build',
() => expectBuildClean(packageRelativeDirectory: 'packages/shorebird_cli'),
timeout: const Timeout.factor(2),
);
}
@@ -0,0 +1,206 @@
import 'dart:io';
import 'package:mason_logger/mason_logger.dart';
import 'package:mocktail/mocktail.dart';
import 'package:path/path.dart' as p;
import 'package:shorebird_cli/src/commands/init_command.dart';
import 'package:test/test.dart';
class _MockLogger extends Mock implements Logger {}
class _MockProgress extends Mock implements Progress {}
void main() {
group('init', () {
const version = '1.2.3';
const pubspecYamlContent = '''
name: example
version: $version
environment:
sdk: ">=2.19.0 <3.0.0"''';
const productId = 'test-product-id';
late Logger logger;
late Progress progress;
late InitCommand command;
setUp(() {
logger = _MockLogger();
progress = _MockProgress();
command = InitCommand(
logger: logger,
buildUuid: () => productId,
);
when(() => logger.progress(any())).thenReturn(progress);
});
test('throws no input error when pubspec.yaml is not found.', () async {
final tempDir = Directory.systemTemp.createTempSync();
final exitCode = await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
);
verify(() => logger.err('Could not find a "pubspec.yaml".')).called(1);
expect(exitCode, ExitCode.noInput.code);
});
test('throws software error when pubspec.yaml is malformed.', () async {
final tempDir = Directory.systemTemp.createTempSync();
File(p.join(tempDir.path, 'pubspec.yaml')).createSync();
final exitCode = await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
);
verify(
() => logger.err(any(that: contains('Error parsing "pubspec.yaml":'))),
).called(1);
expect(exitCode, ExitCode.software.code);
});
test('throws software error when shorebird.yaml is malformed.', () async {
final tempDir = Directory.systemTemp.createTempSync();
File(
p.join(tempDir.path, 'pubspec.yaml'),
).writeAsStringSync(pubspecYamlContent);
File(p.join(tempDir.path, 'shorebird.yaml')).createSync();
final exitCode = await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
);
verify(
() => logger.err(
any(that: contains('Error creating "shorebird.yaml".')),
),
).called(1);
expect(exitCode, ExitCode.software.code);
});
test('detects existing shorebird.yaml', () async {
const existingProductId = 'existing-product-id';
final tempDir = Directory.systemTemp.createTempSync();
File(
p.join(tempDir.path, 'pubspec.yaml'),
).writeAsStringSync(pubspecYamlContent);
File(
p.join(tempDir.path, 'shorebird.yaml'),
).writeAsStringSync('product_id: $existingProductId');
await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
);
expect(
File(p.join(tempDir.path, 'shorebird.yaml')).readAsStringSync(),
contains('product_id: $existingProductId'),
);
verify(() => progress.update('"shorebird.yaml" already exists.'));
});
test('creates shorebird.yaml', () async {
final tempDir = Directory.systemTemp.createTempSync();
File(
p.join(tempDir.path, 'pubspec.yaml'),
).writeAsStringSync(pubspecYamlContent);
await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
);
expect(
File(p.join(tempDir.path, 'shorebird.yaml')).readAsStringSync(),
contains('product_id: $productId'),
);
});
test('detects existing shorebird.yaml in pubspec.yaml assets', () async {
final tempDir = Directory.systemTemp.createTempSync();
File(
p.join(tempDir.path, 'pubspec.yaml'),
).writeAsStringSync('''
$pubspecYamlContent
flutter:
assets:
- shorebird.yaml
''');
await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
);
expect(
File(p.join(tempDir.path, 'shorebird.yaml')).readAsStringSync(),
contains('product_id: $productId'),
);
verify(
() => progress.update(
'"shorebird.yaml" already in "pubspec.yaml" assets.',
),
);
});
test('creates flutter.assets and adds shorebird.yaml', () async {
final tempDir = Directory.systemTemp.createTempSync();
File(
p.join(tempDir.path, 'pubspec.yaml'),
).writeAsStringSync(pubspecYamlContent);
await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
);
expect(
File(p.join(tempDir.path, 'pubspec.yaml')).readAsStringSync(),
equals('''
$pubspecYamlContent
flutter:
assets:
- shorebird.yaml
'''),
);
});
test('creates assets and adds shorebird.yaml', () async {
final tempDir = Directory.systemTemp.createTempSync();
File(p.join(tempDir.path, 'pubspec.yaml')).writeAsStringSync('''
$pubspecYamlContent
flutter:
uses-material-design: true
''');
await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
);
expect(
File(p.join(tempDir.path, 'pubspec.yaml')).readAsStringSync(),
equals('''
$pubspecYamlContent
flutter:
assets:
- shorebird.yaml
uses-material-design: true
'''),
);
});
test('adds shorebird.yaml to assets', () async {
final tempDir = Directory.systemTemp.createTempSync();
File(p.join(tempDir.path, 'pubspec.yaml')).writeAsStringSync('''
$pubspecYamlContent
flutter:
assets:
- some/asset.txt
''');
await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
);
expect(
File(p.join(tempDir.path, 'pubspec.yaml')).readAsStringSync(),
equals('''
$pubspecYamlContent
flutter:
assets:
- some/asset.txt
- shorebird.yaml
'''),
);
});
});
}
@@ -38,7 +38,11 @@ void main() {
name: example
version: $version
environment:
sdk: ">=2.19.0 <3.0.0"''';
sdk: ">=2.19.0 <3.0.0"
flutter:
assets:
- shorebird.yaml''';
late ArgResults argResults;
late Auth auth;
@@ -46,6 +50,17 @@ environment:
late CodePushClient codePushClient;
late PublishCommand command;
Directory setUpTempDir() {
final tempDir = Directory.systemTemp.createTempSync();
File(
p.join(tempDir.path, 'pubspec.yaml'),
).writeAsStringSync(pubspecYamlContent);
File(
p.join(tempDir.path, 'shorebird.yaml'),
).writeAsStringSync('product_id: $productId');
return tempDir;
}
setUp(() {
argResults = _MockArgResults();
auth = _MockAuth();
@@ -72,67 +87,45 @@ environment:
).thenAnswer((_) async {});
});
test('throws no user error when session does not exist', () async {
when(() => auth.currentSession).thenReturn(null);
final exitCode = await command.run();
expect(exitCode, equals(ExitCode.noUser.code));
});
test('throws usage error when multiple args are passed.', () async {
when(() => argResults.rest).thenReturn(['arg1', 'arg2']);
await expectLater(command.run, throwsA(isA<UsageException>()));
});
test('throws no input error when pubspec.yaml is not found.', () async {
test('throws config error when shorebird is not initialized', () async {
final tempDir = Directory.systemTemp.createTempSync();
final exitCode = await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
);
verify(() => logger.err('Could not find a "pubspec.yaml".')).called(1);
expect(exitCode, ExitCode.noInput.code);
});
test('throws software error when pubspec.yaml is malformed.', () async {
final tempDir = Directory.systemTemp.createTempSync();
File(p.join(tempDir.path, 'pubspec.yaml')).createSync();
final exitCode = await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
);
verify(
() => logger.err(any(that: contains('Error parsing "pubspec.yaml":'))),
).called(1);
expect(exitCode, ExitCode.software.code);
});
test('throws software error when shorebird.yaml is malformed.', () async {
final tempDir = Directory.systemTemp.createTempSync();
File(
p.join(tempDir.path, 'pubspec.yaml'),
).writeAsStringSync(pubspecYamlContent);
File(p.join(tempDir.path, 'shorebird.yaml')).createSync();
final exitCode = await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
);
verify(
() => logger.err(
any(that: contains('Error parsing "shorebird.yaml":')),
'Shorebird is not initialized. Did you run "shorebird init"?',
),
).called(1);
expect(exitCode, ExitCode.software.code);
expect(exitCode, ExitCode.config.code);
});
test('throws no user error when session does not exist', () async {
when(() => auth.currentSession).thenReturn(null);
final tempDir = setUpTempDir();
final exitCode = await IOOverrides.runZoned(
() => command.run(),
getCurrentDirectory: () => tempDir,
);
expect(exitCode, equals(ExitCode.noUser.code));
});
test('throws usage error when multiple args are passed.', () async {
when(() => argResults.rest).thenReturn(['arg1', 'arg2']);
final tempDir = setUpTempDir();
await expectLater(
IOOverrides.runZoned(
() => command.run(),
getCurrentDirectory: () => tempDir,
),
throwsA(isA<UsageException>()),
);
});
test('throws no input error when artifact is not found (default).',
() async {
final tempDir = Directory.systemTemp.createTempSync();
File(
p.join(tempDir.path, 'pubspec.yaml'),
).writeAsStringSync(pubspecYamlContent);
File(
p.join(tempDir.path, 'shorebird.yaml'),
).writeAsStringSync('product_id: $productId');
final tempDir = setUpTempDir();
final exitCode = await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
@@ -145,15 +138,9 @@ environment:
test('throws no input error when artifact is not found (custom).',
() async {
final tempDir = Directory.systemTemp.createTempSync();
final tempDir = setUpTempDir();
final artifact = File(p.join(tempDir.path, 'patch.txt'));
when(() => argResults.rest).thenReturn([artifact.path]);
File(
p.join(tempDir.path, 'pubspec.yaml'),
).writeAsStringSync(pubspecYamlContent);
File(
p.join(tempDir.path, 'shorebird.yaml'),
).writeAsStringSync('product_id: $productId');
final exitCode = await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
@@ -178,15 +165,9 @@ environment:
productId: any(named: 'productId'),
),
).thenThrow(error);
final tempDir = Directory.systemTemp.createTempSync();
final tempDir = setUpTempDir();
final artifact = File(p.join(tempDir.path, 'patch.txt'))..createSync();
when(() => argResults.rest).thenReturn([artifact.path]);
File(
p.join(tempDir.path, 'pubspec.yaml'),
).writeAsStringSync(pubspecYamlContent);
File(
p.join(tempDir.path, 'shorebird.yaml'),
).writeAsStringSync('product_id: $productId');
final exitCode = await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
@@ -197,15 +178,9 @@ environment:
test('succeeds when publish is successful using existing product id',
() async {
final tempDir = Directory.systemTemp.createTempSync();
final tempDir = setUpTempDir();
final artifact = File(p.join(tempDir.path, 'patch.txt'))..createSync();
when(() => argResults.rest).thenReturn([artifact.path]);
File(
p.join(tempDir.path, 'pubspec.yaml'),
).writeAsStringSync(pubspecYamlContent);
File(
p.join(tempDir.path, 'shorebird.yaml'),
).writeAsStringSync('product_id: $productId');
final exitCode = await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
@@ -221,106 +196,5 @@ environment:
).called(1);
expect(exitCode, ExitCode.success.code);
});
test('succeeds when publish is successful using newly generated product id',
() async {
final tempDir = Directory.systemTemp.createTempSync();
final artifact = File(p.join(tempDir.path, 'patch.txt'))..createSync();
when(() => argResults.rest).thenReturn([artifact.path]);
File(
p.join(tempDir.path, 'pubspec.yaml'),
).writeAsStringSync(pubspecYamlContent);
final exitCode = await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
);
verify(() => logger.success('Successfully deployed.')).called(1);
verify(
() => codePushClient.createPatch(
baseVersion: version,
productId: any(named: 'productId', that: isNotEmpty),
artifactPath: artifact.path,
channel: 'stable',
),
).called(1);
expect(
File(p.join(tempDir.path, 'shorebird.yaml')).existsSync(),
isTrue,
);
expect(exitCode, ExitCode.success.code);
});
test('creates flutter.assets and adds shorebird.yaml', () async {
final tempDir = Directory.systemTemp.createTempSync();
final artifact = File(p.join(tempDir.path, 'patch.txt'))..createSync();
when(() => argResults.rest).thenReturn([artifact.path]);
File(
p.join(tempDir.path, 'pubspec.yaml'),
).writeAsStringSync(pubspecYamlContent);
await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
);
expect(
File(p.join(tempDir.path, 'pubspec.yaml')).readAsStringSync(),
equals('''
$pubspecYamlContent
flutter:
assets:
- shorebird.yaml
'''),
);
});
test('creates assets and adds shorebird.yaml', () async {
final tempDir = Directory.systemTemp.createTempSync();
final artifact = File(p.join(tempDir.path, 'patch.txt'))..createSync();
when(() => argResults.rest).thenReturn([artifact.path]);
File(p.join(tempDir.path, 'pubspec.yaml')).writeAsStringSync('''
$pubspecYamlContent
flutter:
uses-material-design: true
''');
await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
);
expect(
File(p.join(tempDir.path, 'pubspec.yaml')).readAsStringSync(),
equals('''
$pubspecYamlContent
flutter:
assets:
- shorebird.yaml
uses-material-design: true
'''),
);
});
test('adds shorebird.yaml to assets', () async {
final tempDir = Directory.systemTemp.createTempSync();
final artifact = File(p.join(tempDir.path, 'patch.txt'))..createSync();
when(() => argResults.rest).thenReturn([artifact.path]);
File(p.join(tempDir.path, 'pubspec.yaml')).writeAsStringSync('''
$pubspecYamlContent
flutter:
assets:
- some/asset.txt
''');
await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
);
expect(
File(p.join(tempDir.path, 'pubspec.yaml')).readAsStringSync(),
equals('''
$pubspecYamlContent
flutter:
assets:
- some/asset.txt
- shorebird.yaml
'''),
);
});
});
}