Skip to content

Commit

Permalink
feat!: local installation of melos in workspace (#431)
Browse files Browse the repository at this point in the history
  • Loading branch information
blaugold authored Feb 4, 2023
1 parent d71e749 commit 9b080a5
Show file tree
Hide file tree
Showing 27 changed files with 537 additions and 338 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/scripts/install-tools.bat
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
CMD /C dart pub global activate --source=path . --executable=melos
CMD /C dart pub global activate --source=path . --executable=melos --overwrite
REM Workaround an issue when running global executables on Windows for the first time.
CMD /C melos > NUL
melos bootstrap
2 changes: 1 addition & 1 deletion .github/workflows/scripts/install-tools.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/bash

dart pub global activate --source="path" . --executable="melos"
dart pub global activate --source="path" . --executable="melos" --overwrite
melos bootstrap
4 changes: 3 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ To setup and use this melos mono repo locally for the purposes of contributing,
```bash
# Install melos if it's not already installed:
dart pub global activate melos
# Bootstrap the workspace.
melos bootstrap
# Activate 'melos' from path:
melos activate
# Confirm you now using a local development version:
Expand Down Expand Up @@ -90,7 +92,7 @@ To send us a pull request:
Please make sure all your check-ins have detailed commit messages explaining the patch.

When naming the title of your pull request, please follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0-beta.4/)
guide.
guide.

Please also enable **“Allow edits by maintainers”**, this will help to speed-up the review
process as well.
Expand Down
9 changes: 6 additions & 3 deletions all_lint_rules.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ linter:
- always_declare_return_types
- always_put_control_body_on_new_line
- always_put_required_named_parameters_first
- always_require_non_null_named_parameters
- always_specify_types
- always_use_package_imports
- annotate_overrides
- avoid_annotating_with_dynamic
# - avoid_as
- avoid_bool_literals_in_conditional_expressions
- avoid_catches_without_on_clauses
- avoid_catching_errors
Expand All @@ -48,8 +48,6 @@ linter:
- avoid_relative_lib_imports
- avoid_renaming_method_parameters
- avoid_return_types_on_setters
- avoid_returning_null
- avoid_returning_null_for_future
- avoid_returning_null_for_void
- avoid_returning_this
- avoid_setters_without_getters
Expand Down Expand Up @@ -95,6 +93,7 @@ linter:
- hash_and_equals
- implementation_imports
- implicit_call_tearoffs
- invariant_booleans
- iterable_contains_unrelated_type
- join_return_with_assignment
- leading_newlines_in_multiline_strings
Expand Down Expand Up @@ -128,6 +127,7 @@ linter:
- prefer_adjacent_string_concatenation
- prefer_asserts_in_initializer_lists
- prefer_asserts_with_message
- prefer_bool_in_asserts
- prefer_collection_literals
- prefer_conditional_assignment
- prefer_const_constructors
Expand All @@ -137,6 +137,7 @@ linter:
- prefer_constructors_over_static_methods
- prefer_contains
- prefer_double_quotes
- prefer_equal_for_default_values
- prefer_expression_function_bodies
- prefer_final_fields
- prefer_final_in_for_each
Expand Down Expand Up @@ -176,6 +177,7 @@ linter:
- sort_constructors_first
- sort_pub_dependencies
- sort_unnamed_constructors_first
- super_goes_last
- test_types_in_equals
- throw_in_finally
- tighten_type_of_initializing_formals
Expand All @@ -184,6 +186,7 @@ linter:
- unawaited_futures
- unnecessary_await_in_return
- unnecessary_brace_in_string_interps
- unnecessary_breaks
- unnecessary_const
- unnecessary_constructor_name
- unnecessary_final
Expand Down
3 changes: 3 additions & 0 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,6 @@ linter:
# Not a common style and would add a lot of verbosity to function signature.
# 'parameter_assignments' already enforces this to an extent.
prefer_final_parameters: false

# Useful to allow for `multiLine` utility function.
no_adjacent_strings_in_list: false
98 changes: 73 additions & 25 deletions docs/getting-started.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,64 +5,110 @@ description: Learn how to start using Melos in your project

# Getting Started

Melos requires a few one-off steps to be completed before you can start using it.
Melos requires a few one-off steps to be completed before you can start using
it.

## Installation

Melos can be installed as a global package via [pub.dev](https://pub.dev/):
Installe Melos as a
[global package](https://dart.dev/tools/pub/cmd/pub-global#running-a-script-from-your-path)
via [pub.dev](https://pub.dev/) so it can be used from anywhere on your system:

```bash
dart pub global activate melos
```

### Setup
## Setup a workspace

To set up your project to use Melos, create a `melos.yaml` file in the root of the project.
Melos is designed to work with a workspace. A workspace is a directory which
contains all the packages that are going to be developed together. Its root
directory must contain a `melos.yaml` file.

Within the `melos.yaml` file, add `name` and `packages` fields:
### Install Melos in the workspace

Different Melos workspaces might use different versions of Melos. To ensure
everyone working in the workspace (as well as CI jobs) is using the same version
of Melos, a dependency on the `melos` package has to be added to the
`pubspec.yaml` file at the workspace root directory. The globally installed
version of Melos will switch to the version specified in the `pubspec.yaml`
file, if both versions are not the same.

If you don't have a `pubspec.yaml` file at the workspace root yet, create one
now:

```yaml
name: my_project
name: <project>_workspace

environment:
sdk: '>=2.18.0 <3.0.0'
```
The corresponding `pubspec.lock` file should also be committed. Make sure to
exclude it from the `.gitignore` file.

Add Melos as a development dependency by running the following command:

```bash
dart pub add melos --dev
```

### Configure the workspace

Next create a `melos.yaml` file at the repository root. Within the `melos.yaml`
file, add the `name` and `packages` fields:

```yaml
name: <project>
packages:
- packages/**
- packages/*
```

The `packages` list should contain paths to the individual packages within your project. Each path
can be defined using the [glob](https://docs.python.org/3/library/glob.html) pattern expansion format.
The `packages` list should contain paths to the individual packages within your
project. Each path can be defined using the
[glob](https://docs.python.org/3/library/glob.html) pattern expansion format.

Melos generates `pubspec_overrides.yaml` files to link local packages for development. Typically these files
should be ignored by git. To ignore these files, add the following to your `.gitignore` file:
Melos generates `pubspec_overrides.yaml` files to link local packages for
development. Typically these files should be ignored by git. To ignore these
files, add the following to your `.gitignore` file:

```
pubspec_overrides.yaml
```

## Bootstrapping

Once installed & setup, Melos needs to be bootstrapped. Bootstrapping has 2 primary roles:
Once installed & setup, Melos needs to be bootstrapped. Bootstrapping has 2
primary roles:

1. Installing all package dependencies (internally using `pub get`).
2. Locally linking any packages together.

### Why do I need to bootstrap?

In normal projects, packages can be linked by providing a `path` within the `pubspec.yaml`. This works for small
projects however presents a problem at scale. Packages cannot be published with a locally defined path, meaning
once you're ready to publish your packages you'll need to manually update all the packages `pubspec.yaml` files
with the versions. If your packages are also tightly coupled (dependencies of each other), you'll also have to manually
check which versions should be updated. Even with a few packages this can become a long and error-prone task.
In normal projects, packages can be linked by providing a `path` within the
`pubspec.yaml`. This works for small projects however presents a problem at
scale. Packages cannot be published with a locally defined path, meaning once
you're ready to publish your packages you'll need to manually update all the
packages `pubspec.yaml` files with the versions. If your packages are also
tightly coupled (dependencies of each other), you'll also have to manually check
which versions should be updated. Even with a few packages this can become a
long and error-prone task.

Melos solves this problem by overriding local files which the Dart analyzer uses to read packages from. If a local package
exists (defined in the `melos.yaml` file) and a different local package has it listed as a dependency, it will be linked
regardless of whether a version has been specified.
Melos solves this problem by overriding local files which the Dart analyzer uses
to read packages from. If a local package exists (defined in the `melos.yaml`
file) and a different local package has it listed as a dependency, it will be
linked regardless of whether a version has been specified.

## Next steps

Once successfully bootstrapped, you can develop your packages side-by-side with changes to a single package immediately reflecting
across other dependent packages.
Once successfully bootstrapped, you can develop your packages side-by-side with
changes to a single package immediately reflecting across other dependent
packages.

Melos also provides other helpful features such as running scripts across all packages. For example, to run dart analyzer in each package, add a new `script` item in your `melos.yaml`:
Melos also provides other helpful features such as running scripts across all
packages. For example, to run dart analyzer in each package, add a new `script`
item in your `melos.yaml`:

```yaml
name: my_project
Expand All @@ -77,7 +123,9 @@ scripts:

Then execute the command by running `melos run analyze`.

If you're looking for some inspiration as to what scripts can help with, check out the
If you're looking for some inspiration as to what scripts can help with, check
out the
[FlutterFire repository](https://github.com/firebase/flutterfire/blob/master/melos.yaml).

If you are using VS Code, there is an [extension](/ide-support#vs-code) available, to integrate Melos with VS Code.
If you are using VS Code, there is an [extension](/ide-support#vs-code)
available, to integrate Melos with VS Code.
32 changes: 32 additions & 0 deletions docs/guides/migrations.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,38 @@ description: How to migrate between major versions of Melos.

## 2.0.0 to 3.0.0

### Versioning of Melos in workspaces

From Melos 3.0.0, the version of Melos to use in any given workspace must be
specified in a `pubspec.yaml` file next to the `melos.yaml` file, in the
workspace root directory.

Different Melos workspaces might use different versions of Melos. To ensure
everyone working in the workspace (as well as CI jobs) is using the same version
of Melos, a dependency on the `melos` package has to be added to the
`pubspec.yaml` file at the workspace root directory. The globally installed
version of Melos will switch to the version specified in the `pubspec.yaml`
file, if both versions are not the same.

If you don't have a `pubspec.yaml` file at the workspace root yet, create one
now:

```yaml
name: <project>_workspace

environment:
sdk: '>=2.18.0 <3.0.0'
```
The corresponding `pubspec.lock` file should also be committed. Make sure to
exclude it from the `.gitignore` file.

Add Melos as a development dependency by running the following command:

```bash
dart pub add melos --dev
```

### Local package linking with `pubspec_overrides.yaml`

The initial mechanism used by Melos to link local packages for development had
Expand Down
2 changes: 1 addition & 1 deletion melos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ scripts:
concurrency: 1
packageFilters:
dirExists:
- 'test/'
- test
# This tells Melos tests to ignore env variables passed to tests from `melos run test`
# as they could change the behaviour of how tests filter packages.
env:
Expand Down
11 changes: 2 additions & 9 deletions packages/melos/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,15 +131,8 @@ The following projects are using Melos:

## Getting Started

Install the latest Melos version as a global package via
[Pub](https://pub.dev/).

```bash
dart pub global activate melos

# Or alternatively to specify a specific version:
# pub global activate melos 0.4.1
```
Go to the [Getting Started](https://melos.invertase.dev/getting-started) page of
the [documentation](https://docs.page/invertase/melos) to start using Melos.

---

Expand Down
69 changes: 8 additions & 61 deletions packages/melos/bin/melos.dart
Original file line number Diff line number Diff line change
@@ -1,64 +1,11 @@
// ignore_for_file: avoid_print

import 'dart:io';

import 'package:args/command_runner.dart';
import 'package:cli_launcher/cli_launcher.dart';
import 'package:melos/src/command_runner.dart';
import 'package:melos/src/common/exception.dart';
import 'package:melos/src/common/utils.dart' as utils;
import 'package:melos/src/workspace_configs.dart';
import 'package:melos/version.g.dart';
import 'package:pub_updater/pub_updater.dart';

Future<void> main(List<String> arguments) async {
if (arguments.contains('--version') || arguments.contains('-v')) {
print(melosVersion);
// No version checks on CIs.
if (utils.isCI) return;

// Check for updates.
final pubUpdater = PubUpdater();
const packageName = 'melos';
final isUpToDate = await pubUpdater.isUpToDate(
packageName: packageName,
currentVersion: melosVersion,
Future<void> main(List<String> arguments) async => launchExecutable(
arguments,
LaunchConfig(
name: ExecutableName('melos'),
launchFromSelf: false,
entrypoint: melosEntryPoint,
),
);
if (!isUpToDate) {
final latestVersion = await pubUpdater.getLatestVersion(packageName);
final shouldUpdate = utils.promptBool(
message: 'There is a new version of $packageName available '
'($latestVersion). Would you like to update?',
defaultsTo: true,
defaultsToWithoutPrompt: false,
);
if (shouldUpdate) {
await pubUpdater.update(packageName: packageName);
print('$packageName has been updated to version $latestVersion.');
}
}

return;
}
try {
final config = shouldUseEmptyConfig(arguments)
? MelosWorkspaceConfig.empty()
: await MelosWorkspaceConfig.fromDirectory(Directory.current);
await MelosCommandRunner(config).run(arguments);
} on MelosException catch (err) {
stderr.writeln(err.toString());
exitCode = 1;
} on UsageException catch (err) {
stderr.writeln(err.toString());
exitCode = 1;
} catch (err) {
exitCode = 1;
rethrow;
}
}

bool shouldUseEmptyConfig(List<String> arguments) {
final willShowHelp = arguments.isEmpty ||
arguments.contains('--help') ||
arguments.contains('-h');
return willShowHelp;
}
Loading

0 comments on commit 9b080a5

Please sign in to comment.