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

feat!: make run script use melos_packages env variable scope #640

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
3 changes: 2 additions & 1 deletion docs/environment-variables.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ package' name ends with `example`
### `MELOS_PACKAGES`

Define a comma delimited list of package names that Melos should focus on. This
bypasses all filtering flags if defined.
will act as the `scope` global package filter, and it will override the `scope`
for all the filtering options defined in the `packageFilters` section.

### `MELOS_SDK_PATH`

Expand Down
8 changes: 3 additions & 5 deletions packages/melos/lib/src/commands/run.dart
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,12 @@ mixin _RunMixin on _Melos {
bool noSelect = false,
List<String> extraArgs = const [],
}) async {
final workspace = await MelosWorkspace.fromConfig(
config,
final workspace = await createWorkspace(
global: global,
packageFilters: script.packageFilters?.copyWithUpdatedIgnore([
...script.packageFilters!.ignore,
...config.ignore,
]),
logger: logger,
)
..validate();

Expand Down Expand Up @@ -148,8 +146,8 @@ mixin _RunMixin on _Melos {
? packages.map((e) => e.name).toList().join(',')
: packages[selectedPackageIndex - 1].name;
// MELOS_PACKAGES environment is detected by melos itself when through
// a defined script, this comma delimited list of package names is used
// instead of any filters if detected.
// a defined script, this comma delimited list of package names used to
// scope the `packageFilters` if it is present.
environment[envKeyMelosPackages] = packagesEnv;
}

Expand Down
21 changes: 12 additions & 9 deletions packages/melos/lib/src/commands/runner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,17 +84,20 @@ abstract class _Melos {

if (currentPlatform.environment.containsKey(envKeyMelosPackages)) {
// MELOS_PACKAGES environment variable is a comma delimited list of
// package names - used instead of filters if it is present.
// package names - used to scope the `packageFilters` if it is present.
// This can be user defined or can come from package selection in
// `melos run`.
filterWithEnv = PackageFilters(
scope: currentPlatform.environment[envKeyMelosPackages]!
.split(',')
.map(
(e) => createGlob(e, currentDirectoryPath: config.path),
)
.toList(),
);
final filteredPackagesScopeFromEnv =
currentPlatform.environment[envKeyMelosPackages]!
.split(',')
.map(
(e) => createGlob(e, currentDirectoryPath: config.path),
)
.toList();

filterWithEnv = packageFilters == null
? PackageFilters(scope: filteredPackagesScopeFromEnv)
: packageFilters.copyWith(scope: filteredPackagesScopeFromEnv);
}

return (await MelosWorkspace.fromConfig(
Expand Down
2 changes: 1 addition & 1 deletion packages/melos/lib/src/common/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ extension Let<T> on T? {
String multiLine(List<String> lines) => lines.join('\n');

// MELOS_PACKAGES environment variable is a comma delimited list of
// package names - used instead of filters if it is present.
// package names - used to scope the `packageFilters` if it is present.
// This can be user defined or can come from package selection in `melos run`.
const envKeyMelosPackages = 'MELOS_PACKAGES';

Expand Down
31 changes: 31 additions & 0 deletions packages/melos/lib/src/package.dart
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,37 @@ class PackageFilters {
);
}

PackageFilters copyWith({
List<String>? dependsOn,
List<String>? dirExists,
List<String>? fileExists,
List<Glob>? ignore,
bool? includePrivatePackages,
List<String>? noDependsOn,
bool? nullSafe,
bool? published,
List<Glob>? scope,
String? diff,
bool? includeDependencies,
bool? includeDependents,
}) {
return PackageFilters._(
dependsOn: dependsOn ?? this.dependsOn,
dirExists: dirExists ?? this.dirExists,
fileExists: fileExists ?? this.fileExists,
ignore: ignore ?? this.ignore,
includePrivatePackages:
includePrivatePackages ?? this.includePrivatePackages,
noDependsOn: noDependsOn ?? this.noDependsOn,
nullSafe: nullSafe ?? this.nullSafe,
published: published ?? this.published,
scope: scope ?? this.scope,
diff: diff ?? this.diff,
includeDependencies: includeDependencies ?? this.includeDependencies,
includeDependents: includeDependents ?? this.includeDependents,
);
}

@override
bool operator ==(Object other) =>
other is PackageFilters &&
Expand Down
87 changes: 87 additions & 0 deletions packages/melos/test/commands/run_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import 'package:melos/src/common/io.dart';
import 'package:melos/src/common/platform.dart';
import 'package:melos/src/common/utils.dart';
import 'package:path/path.dart' as p;
import 'package:platform/platform.dart';
import 'package:pubspec/pubspec.dart';
import 'package:test/test.dart';

import '../matchers.dart';
import '../mock_env.dart';
import '../utils.dart';

void main() {
Expand Down Expand Up @@ -87,6 +89,91 @@ melos run test_script
},
);

test(
'merges filters from `packageFilters` and `$envKeyMelosPackages`',
withMockPlatform(
() async {
final workspaceDir = await createTemporaryWorkspace(
runPubGet: true,
configBuilder: (path) => MelosWorkspaceConfig(
path: path,
name: 'test_package',
packages: [
createGlob('packages/**', currentDirectoryPath: path),
],
scripts: Scripts({
'test_script': Script(
name: 'test_script',
run: 'melos exec -- "echo hello"',
packageFilters: PackageFilters(
fileExists: const ['log.txt'],
),
),
}),
),
);

final aDir = await createProject(
workspaceDir,
const PubSpec(name: 'a'),
);
writeTextFile(p.join(aDir.path, 'log.txt'), '');

await createProject(
workspaceDir,
const PubSpec(name: 'b'),
);

final cDir = await createProject(
workspaceDir,
const PubSpec(name: 'c'),
);
writeTextFile(p.join(cDir.path, 'log.txt'), '');

final logger = TestLogger();
final config =
await MelosWorkspaceConfig.fromWorkspaceRoot(workspaceDir);
final melos = Melos(
logger: logger,
config: config,
);

await melos.run(scriptName: 'test_script', noSelect: true);

expect(
logger.output.normalizeNewLines(),
ignoringAnsii(
'''
melos run test_script
β””> melos exec -- "echo hello"
β””> RUNNING

\$ melos exec
β””> echo hello
β””> RUNNING (in 1 packages)

${'-' * terminalWidth}
c:
hello
c: SUCCESS
${'-' * terminalWidth}

\$ melos exec
β””> echo hello
β””> SUCCESS

melos run test_script
β””> melos exec -- "echo hello"
β””> SUCCESS
''',
),
);
},
platform: FakePlatform.fromPlatform(const LocalPlatform())
..environment[envKeyMelosPackages] = 'b,c',
),
);

test('supports passing additional arguments to scripts', () async {
final workspaceDir = await createTemporaryWorkspace(
runPubGet: true,
Expand Down
Loading