Skip to content

feat: adding package command #47

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion .github/workflows/shorebird_ci.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,30 @@
name: shorebird_ci
name: shorebird_tests

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

on:
pull_request:
paths:
- ".github/workflows/shorebird_tests.yaml"
- "packages/shorebird_tests/lib/**"
- "packages/shorebird_tests/test/**"
- "packages/shorebird_tests/pubspec.yaml"
- "packages/flutter_tools/lib/**"
- "packages/flutter_tools/test/**"
- "packages/flutter_tools/pubspec.yaml"
push:
branches:
- main
paths:
- ".github/workflows/shorebird_tests.yaml"
- "packages/shorebird_tests/lib/**"
- "packages/shorebird_tests/test/**"
- "packages/shorebird_tests/pubspec.yaml"
- "packages/flutter_tools/lib/**"
- "packages/flutter_tools/test/**"
- "packages/flutter_tools/pubspec.yaml"

jobs:
test:
Expand Down
30 changes: 30 additions & 0 deletions .github/workflows/shorebird_tools.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Shorebird Tools 💻

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

on:
pull_request:
paths:
- ".github/workflows/shorebird_tools.yaml"
- "packages/shorebird_tools/lib/**"
- "packages/shorebird_tools/test/**"
- "packages/shorebird_tools/pubspec.yaml"
push:
branches:
- main
paths:
- ".github/workflows/shorebird_tools.yaml"
- "packages/shorebird_tools/lib/**"
- "packages/shorebird_tools/test/**"
- "packages/shorebird_tools/pubspec.yaml"

jobs:
semantic-pull-request:
uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/semantic_pull_request.yml@v1

build:
uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/dart_package.yml@v1
with:
working_directory: packages/shorebird_tools
1 change: 1 addition & 0 deletions packages/shorebird_tools/lib/src/command_runner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class ShorebirdToolsCommandRunner extends CommandRunner<int> {

// Add sub commands
addCommand(SampleCommand(logger: _logger));
addCommand(PackageCommand(logger: _logger));
}

@override
Expand Down
1 change: 1 addition & 0 deletions packages/shorebird_tools/lib/src/commands/commands.dart
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export 'package_command.dart';
export 'sample_command.dart';
70 changes: 70 additions & 0 deletions packages/shorebird_tools/lib/src/commands/package_command.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import 'dart:io';

import 'package:archive/archive_io.dart';
import 'package:args/command_runner.dart';
import 'package:mason_logger/mason_logger.dart';
import 'package:path/path.dart' as p;

/// {@template package_command}
///
/// `shorebird_tools package`
/// A [Command] that packages a generated patch into an archive
/// {@endtemplate}
class PackageCommand extends Command<int> {
/// {@macro package_command}
PackageCommand({
required Logger logger,
}) : _logger = logger {
argParser
..addOption(
'patch',
abbr: 'p',
mandatory: true,
help: 'The path to the patch artifact which will be packaged',
)
..addOption(
'output',
abbr: 'o',
mandatory: true,
help: 'Where to write the packaged patch archive',
);
}

@override
String get description => 'Packages a patch artifact into an archive';

@override
String get name => 'package';

final Logger _logger;

@override
Future<int> run() async {
final patchFilePath = argResults!['patch'] as String;
final outFilePath = argResults!['output'] as String;

final patchFile = File(patchFilePath);
if (!patchFile.existsSync()) {
_logger.err('Patch file not found at $patchFilePath');
return ExitCode.software.code;
}

final outFile = File(outFilePath);

final bytes = patchFile.readAsBytesSync();
final archiveFile = ArchiveFile(
p.basename(patchFilePath),
bytes.length,
bytes,
);

ZipEncoder()
..startEncode(OutputFileStream(outFile.absolute.path))
..addFile(archiveFile)
..endEncode();

_logger.info('Packaged patch at $patchFilePath to $outFilePath');

return ExitCode.success.code;
}
}
2 changes: 2 additions & 0 deletions packages/shorebird_tools/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ environment:
sdk: "^3.3.0"

dependencies:
archive: ^3.5.1
args: ^2.4.2
mason_logger: ^0.2.12
path: ^1.9.0

dev_dependencies:
build_runner: ^2.4.8
Expand Down
6 changes: 0 additions & 6 deletions packages/shorebird_tools/test/src/command_runner_test.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import 'dart:io';

import 'package:args/command_runner.dart';
import 'package:mason_logger/mason_logger.dart';
import 'package:mocktail/mocktail.dart';
Expand All @@ -9,12 +7,8 @@ import 'package:test/test.dart';

class _MockLogger extends Mock implements Logger {}

class _MockProgress extends Mock implements Progress {}


const latestVersion = '0.0.0';


void main() {
group('ShorebirdToolsCommandRunner', () {
late Logger logger;
Expand Down
126 changes: 126 additions & 0 deletions packages/shorebird_tools/test/src/commands/package_command_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import 'dart:io';

import 'package:archive/archive_io.dart';
import 'package:mason_logger/mason_logger.dart';
import 'package:mocktail/mocktail.dart';
import 'package:path/path.dart' as p;
import 'package:shorebird_tools/src/command_runner.dart';
import 'package:test/test.dart';

class _MockLogger extends Mock implements Logger {}

void main() {
group('package', () {
late Logger logger;
late ShorebirdToolsCommandRunner commandRunner;
late Directory testDir;

setUp(() {
logger = _MockLogger();
commandRunner = ShorebirdToolsCommandRunner(logger: logger);
testDir = Directory.systemTemp.createTempSync('shorebird_tools_test');
});

test('packages the received patch', () async {
File(p.join(testDir.path, 'patch.txt')).writeAsStringSync('banana');

final exitCode = await commandRunner.run(
[
'package',
'-p',
p.join(testDir.path, 'patch.txt'),
'-o',
p.join(testDir.path, 'patch.zip'),
],
);

expect(exitCode, ExitCode.success.code);

verify(
() => logger.info(
'Packaged patch at ${p.join(testDir.path, 'patch.txt')} '
'to ${p.join(testDir.path, 'patch.zip')}',
),
).called(1);

final patchFile = File(p.join(testDir.path, 'patch.zip'));
expect(patchFile.existsSync(), isTrue);

final extractedFolder = Directory(p.join(testDir.path, 'extracted'))
..createSync();
await extractFileToDisk(patchFile.path, extractedFolder.path);

// Making sure it was correctly archived and can be extracted
final extractedFile = File(p.join(extractedFolder.path, 'patch.txt'));
expect(extractedFile.existsSync(), isTrue);
expect(extractedFile.readAsStringSync(), 'banana');
});

group('when the patch file does not exists', () {
test('error and logs', () async {
final exitCode = await commandRunner.run(
[
'package',
'-p',
p.join(testDir.path, 'patch.txt'),
'-o',
p.join(testDir.path, 'patch.zip'),
],
);

expect(exitCode, ExitCode.software.code);

verify(
() => logger.err(
'Patch file not found at ${p.join(testDir.path, 'patch.txt')}',
),
).called(1);
});
});

group('when missing option for -p', () {
test('shows errors and print the correct usage', () async {
final exitCode = await commandRunner.run(['package', '-p']);

expect(exitCode, ExitCode.usage.code);

verify(() => logger.err('Missing argument for "patch".')).called(1);
verify(
() => logger.info('''
Usage: shorebird_tools package [arguments]
-h, --help Print this usage information.
-p, --patch (mandatory) The path to the patch artifact which will be packaged
-o, --output (mandatory) Where to write the packaged patch archive

Run "shorebird_tools help" to see global options.'''),
).called(1);
});
});

group('when missing option for -o', () {
test('shows errors and print the correct usage', () async {
final exitCode = await commandRunner.run(
[
'package',
'-p',
'bla',
'-o',
],
);

expect(exitCode, ExitCode.usage.code);

verify(() => logger.err('Missing argument for "output".')).called(1);
verify(
() => logger.info('''
Usage: shorebird_tools package [arguments]
-h, --help Print this usage information.
-p, --patch (mandatory) The path to the patch artifact which will be packaged
-o, --output (mandatory) Where to write the packaged patch archive

Run "shorebird_tools help" to see global options.'''),
).called(1);
});
});
});
}
Loading