Skip to content
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

fix(shorebird_cli): always respect build-name and build-number args #2302

Merged
merged 8 commits into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
Changes from 6 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: 8 additions & 10 deletions packages/shorebird_cli/lib/src/commands/patch/patch_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,16 @@ class PatchCommand extends ShorebirdCommand {
abbr: 'p',
help: 'The platform(s) to to build this release for.',
allowed: ReleaseType.values.map((e) => e.cliName).toList(),
// TODO(bryanoltman): uncomment this once https://github.com/dart-lang/args/pull/273 lands
// mandatory: true.
)
..addOption(
'build-number',
help: '''
An identifier used as an internal version number.
Each build must have a unique identifier to differentiate it from previous builds.
It is used to determine whether one build is more recent than another, with higher numbers indicating more recent build.
On Android it is used as "versionCode".
On Xcode builds it is used as "CFBundleVersion".''',
defaultsTo: '1.0',
CommonArguments.buildNameArg.name,
help: CommonArguments.buildNameArg.description,
defaultsTo: CommonArguments.buildNameArg.defaultValue,
)
..addOption(
CommonArguments.buildNumberArg.name,
help: CommonArguments.buildNumberArg.description,
defaultsTo: CommonArguments.buildNumberArg.defaultValue,
)
..addOption(
'target',
Expand Down
15 changes: 13 additions & 2 deletions packages/shorebird_cli/lib/src/commands/patch/patcher.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import 'package:args/args.dart';
import 'package:mason_logger/mason_logger.dart';
import 'package:path/path.dart' as p;
import 'package:shorebird_cli/src/code_push_client_wrapper.dart';
import 'package:shorebird_cli/src/common_arguments.dart';
import 'package:shorebird_cli/src/extensions/iterable.dart';
import 'package:shorebird_cli/src/patch_diff_checker.dart';
import 'package:shorebird_cli/src/platform/platform.dart';
import 'package:shorebird_cli/src/release_type.dart';
Expand Down Expand Up @@ -139,8 +141,17 @@ https://docs.shorebird.dev/status#link-percentage-ios
return [];
}

// If the user already provided --build-name or --build-number, we don't
// want to override them.
// If the user provided --build-name or --build-number before the --, we
// don't want to override them.
if (argResults.options.containsAnyOf([
CommonArguments.buildNameArg.name,
CommonArguments.buildNumberArg.name,
])) {
return [];
}

// If the user provided --build-name or --build-number after the --, we
// don't want to override them.
bryanoltman marked this conversation as resolved.
Show resolved Hide resolved
if (argResults.rest.any(
(a) => a.startsWith('--build-name') || a.startsWith('--build-number'),
)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ class ReleaseCommand extends ShorebirdCommand {
help: 'The product flavor to use when building the app.',
)
..addOption(
'build-number',
help: '''
An identifier used as an internal version number.
Each build must have a unique identifier to differentiate it from previous builds.
It is used to determine whether one build is more recent than another, with higher numbers indicating more recent build.
On Android it is used as "versionCode".
On Xcode builds it is used as "CFBundleVersion".''',
defaultsTo: '1.0',
CommonArguments.buildNameArg.name,
help: CommonArguments.buildNameArg.description,
defaultsTo: CommonArguments.buildNameArg.defaultValue,
)
..addOption(
CommonArguments.buildNumberArg.name,
help: CommonArguments.buildNumberArg.description,
defaultsTo: CommonArguments.buildNumberArg.defaultValue,
)
..addFlag(
'codesign',
Expand Down
30 changes: 30 additions & 0 deletions packages/shorebird_cli/lib/src/common_arguments.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,48 @@ class ArgumentDescriber {
const ArgumentDescriber({
required this.name,
required this.description,
this.defaultValue,
});

/// Argument name as how the user writes it.
final String name;

/// Argument description that will be shown in the help of the command.
final String description;

/// Default value for this argument. Only provide this if the default value
/// holds across all commands.
final String? defaultValue;
}

/// A class that houses the name of arguments that are shared between different
/// commands and layers.
class CommonArguments {
/// The Flutter --build-name argument.
static const buildNameArg = ArgumentDescriber(
name: 'build-name',
description: '''
An identifier used as an internal version number.
Each build must have a unique identifier to differentiate it from previous builds.
It is used to determine whether one build is more recent than another, with higher numbers indicating more recent build.
On Android it is used as "versionCode".
On Xcode builds it is used as "CFBundleVersion".''',
);

/// The Flutter --build-number argument.
static const buildNumberArg = ArgumentDescriber(
name: 'build-number',
description: '''
A "x.y.z" string used as the version number shown to users.
For each new version of your app, you will provide a version number to differentiate it
from previous versions.
On Android it is used as "versionName".
On Xcode builds it is used as "CFBundleShortVersionString".
On Windows it is used as the major, minor, and patch parts of the product and file
versions.''',
defaultValue: '1.0',
);

/// A multioption argument that defines constants for the built application.
/// These are forwarded to Flutter.
static const dartDefineArg = ArgumentDescriber(
Expand Down
40 changes: 26 additions & 14 deletions packages/shorebird_cli/lib/src/extensions/arg_results.dart
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,24 @@ extension ForwardedArgs on ArgResults {
bool _isPositionalArgPlatform(String arg) =>
ReleaseType.values.any((target) => target.cliName == arg);

/// All parsed args with the given name. Because of multioptions, there may
/// be multiple values for a single name, so we return a potentially empty
/// [Iterable<String>] instead of a [String?].
Iterable<String> _argsNamed(String name) {
if (!wasParsed(name)) {
return [];
}

final value = this[name];
if (value is List) {
return value.map((a) => '--$name=$a');
} else {
return ['--$name=$value'];
}
}

/// A list of arguments parsed by Shorebird commands that will be forwarded
/// to the underlying Flutter commands (that is, placed after `--`).
List<String> get forwardedArgs {
final List<String> forwarded;
if (rest.isNotEmpty && _isPositionalArgPlatform(rest.first)) {
Expand All @@ -113,20 +131,14 @@ extension ForwardedArgs on ArgResults {
forwarded = rest.toList();
}

if (wasParsed(CommonArguments.dartDefineArg.name)) {
forwarded.addAll(
(this[CommonArguments.dartDefineArg.name] as List<String>).map(
(a) => '--${CommonArguments.dartDefineArg.name}=$a',
),
);
}

if (wasParsed(CommonArguments.dartDefineFromFileArg.name)) {
forwarded.addAll(
(this[CommonArguments.dartDefineFromFileArg.name] as List<String>)
.map((a) => '--${CommonArguments.dartDefineFromFileArg.name}=$a'),
);
}
forwarded.addAll(
[
..._argsNamed(CommonArguments.dartDefineArg.name),
..._argsNamed(CommonArguments.dartDefineFromFileArg.name),
..._argsNamed(CommonArguments.buildNameArg.name),
..._argsNamed(CommonArguments.buildNumberArg.name),
],
);

return forwarded;
}
Expand Down
5 changes: 5 additions & 0 deletions packages/shorebird_cli/lib/src/extensions/iterable.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// Provides the [containsAnyOf] method to all [Iterable]s.
extension ContainsAnyOf<T> on Iterable<T> {
/// Returns `true` if any of the elements in [elements] are in this iterable.
bool containsAnyOf(Iterable<T> elements) => elements.any(contains);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What’s the benefit of this extension? Seems like it’s a one liner either way

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks a bit nicer with list literals:

argResults.options.containsAnyOf([a,b]);

instead of

[a,b].any((e) => argResults.options.contains(e));

Mostly just a minor readability improvement, happy to remove if you feel strongly.

}
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ void main() {
shorebirdValidator = MockShorebirdValidator();
shorebirdAndroidArtifacts = MockShorebirdAndroidArtifacts();

when(() => argResults.options).thenReturn([]);
when(() => argResults.rest).thenReturn([]);
when(() => argResults.wasParsed(any())).thenReturn(false);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ void main() {
shorebirdValidator = MockShorebirdValidator();
xcodeBuild = MockXcodeBuild();

when(() => argResults['build-number']).thenReturn('1.0');
when(() => argResults.options).thenReturn([]);
when(() => argResults.rest).thenReturn([]);
when(() => argResults.wasParsed(any())).thenReturn(false);

Expand Down
30 changes: 30 additions & 0 deletions packages/shorebird_cli/test/src/commands/patch/patcher_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:args/args.dart';
import 'package:mocktail/mocktail.dart';
import 'package:shorebird_cli/src/code_push_client_wrapper.dart';
import 'package:shorebird_cli/src/commands/commands.dart';
import 'package:shorebird_cli/src/common_arguments.dart';
import 'package:shorebird_cli/src/patch_diff_checker.dart';
import 'package:shorebird_cli/src/platform/platform.dart';
import 'package:shorebird_cli/src/release_type.dart';
Expand Down Expand Up @@ -45,6 +46,7 @@ void main() {
late ArgResults argResults;
setUp(() {
argResults = MockArgResults();
when(() => argResults.options).thenReturn([]);
});

group('when releaseVersion is not specified', () {
Expand Down Expand Up @@ -108,6 +110,34 @@ void main() {
);
});
});

group('when build-name and build-number were parsed as options', () {
setUp(() {
when(
() => argResults.wasParsed(CommonArguments.buildNameArg.name),
).thenReturn(true);
when(
() => argResults.wasParsed(CommonArguments.buildNumberArg.name),
).thenReturn(true);
when(() => argResults.options).thenReturn([
'release-version',
'build-name',
'build-number',
'platforms',
]);
});

test('returns an empty list', () {
expect(
_TestPatcher(
argResults: argResults,
flavor: null,
target: null,
).buildNameAndNumberArgsFromReleaseVersion('1.2.3+4'),
isEmpty,
);
});
});
});
});
});
Expand Down
51 changes: 51 additions & 0 deletions packages/shorebird_cli/test/src/extensions/arg_results_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,14 @@ void main() {
CommonArguments.dartDefineFromFileArg.name,
help: CommonArguments.dartDefineFromFileArg.description,
)
..addOption(
CommonArguments.buildNameArg.name,
help: CommonArguments.buildNameArg.description,
)
..addOption(
CommonArguments.buildNumberArg.name,
help: CommonArguments.buildNumberArg.description,
)
..addMultiOption(
'platforms',
allowed: ReleaseType.values.map((e) => e.cliName),
Expand Down Expand Up @@ -178,5 +186,48 @@ void main() {
);
});
});

group('when build-name and build-number are provided', () {
test('forwards build-name and build-number', () {
final args = [
'--verbose',
'--',
'--build-name=1.2.3',
'--build-number=4',
];
final result = parser.parse(args);
expect(result.forwardedArgs, hasLength(2));
expect(
result.forwardedArgs,
containsAll(
[
'--build-name=1.2.3',
'--build-number=4',
],
),
);
});
});

group('when build-name and build-number are before the --', () {
test('forwards build-name and build-number', () {
final args = [
'--verbose',
'--build-name=1.2.3',
'--build-number=4',
];
final result = parser.parse(args);
expect(result.forwardedArgs, hasLength(2));
expect(
result.forwardedArgs,
containsAll(
[
'--build-name=1.2.3',
'--build-number=4',
],
),
);
});
});
});
}
18 changes: 18 additions & 0 deletions packages/shorebird_cli/test/src/extensions/iterable_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import 'package:shorebird_cli/src/extensions/iterable.dart';
import 'package:test/test.dart';

void main() {
group('containsAnyOf', () {
test('returns true when any element is in the iterable', () {
final iterable = [1, 2, 3];
final elements = [3, 4, 5];
expect(iterable.containsAnyOf(elements), isTrue);
});

test('returns false when no element is in the iterable', () {
final iterable = [1, 2, 3];
final elements = [4, 5, 6];
expect(iterable.containsAnyOf(elements), isFalse);
});
});
}
Loading