diff --git a/docs/configuration/overview.mdx b/docs/configuration/overview.mdx index f12ffdd17..c3ce67eec 100644 --- a/docs/configuration/overview.mdx +++ b/docs/configuration/overview.mdx @@ -129,6 +129,14 @@ Whether to run `pub get` in parallel during bootstrapping. The default is `true`. +### `command/bootstrap/runPubGetOffline` + +Whether to attempt to run `pub get` in offline mode during bootstrapping. + +Useful in closed network environments with pre-populated pubcaches. + +The default is `false`. + ### `command/version/message` A template for the commit message, that is generated by `melos version`. diff --git a/packages/melos/lib/src/commands/bootstrap.dart b/packages/melos/lib/src/commands/bootstrap.dart index 3e2c78171..8440584b2 100644 --- a/packages/melos/lib/src/commands/bootstrap.dart +++ b/packages/melos/lib/src/commands/bootstrap.dart @@ -13,7 +13,8 @@ mixin _BootstrapMixin on _CleanMixin { useFlutter: workspace.isFlutterWorkspace, workspace: workspace, ), - 'get' + 'get', + if (workspace.config.commands.bootstrap.runPubGetOffline) '--offline' ].join(' '); logger @@ -177,6 +178,7 @@ mixin _BootstrapMixin on _CleanMixin { workspace: workspace, ), 'get', + if (workspace.config.commands.bootstrap.runPubGetOffline) '--offline' ]; final executable = currentPlatform.isWindows ? 'cmd' : '/bin/sh'; diff --git a/packages/melos/lib/src/workspace_configs.dart b/packages/melos/lib/src/workspace_configs.dart index 6f49e1d5c..09540d50c 100644 --- a/packages/melos/lib/src/workspace_configs.dart +++ b/packages/melos/lib/src/workspace_configs.dart @@ -181,6 +181,7 @@ class BootstrapCommandConfigs { const BootstrapCommandConfigs({ this.usePubspecOverrides = false, this.runPubGetInParallel = true, + this.runPubGetOffline = false, }); factory BootstrapCommandConfigs.fromYaml(Map yaml) { @@ -198,9 +199,17 @@ class BootstrapCommandConfigs { ) ?? true; + final runPubGetOffline = assertKeyIsA( + key: 'runPubGetOffline', + map: yaml, + path: 'command/bootstrap', + ) ?? + false; + return BootstrapCommandConfigs( usePubspecOverrides: usePubspecOverrides, runPubGetInParallel: runPubGetInParallel, + runPubGetOffline: runPubGetOffline, ); } @@ -215,10 +224,17 @@ class BootstrapCommandConfigs { /// The default is `true`. final bool runPubGetInParallel; + /// Whether to attempt to run `pub get` in offline mode during bootstrapping. + /// Useful in closed network environments with pre-populated pubcaches. + /// + /// The default is `false`. + final bool runPubGetOffline; + Map toJson() { return { 'usePubspecOverrides': usePubspecOverrides, 'runPubGetInParallel': runPubGetInParallel, + 'runPubGetOffline': runPubGetOffline, }; } @@ -227,13 +243,15 @@ class BootstrapCommandConfigs { other is BootstrapCommandConfigs && runtimeType == other.runtimeType && other.usePubspecOverrides == usePubspecOverrides && - other.runPubGetInParallel == runPubGetInParallel; + other.runPubGetInParallel == runPubGetInParallel && + other.runPubGetOffline == runPubGetOffline; @override int get hashCode => runtimeType.hashCode ^ usePubspecOverrides.hashCode ^ - runPubGetInParallel.hashCode; + runPubGetInParallel.hashCode ^ + runPubGetOffline.hashCode; @override String toString() { @@ -241,6 +259,7 @@ class BootstrapCommandConfigs { BootstrapCommandConfigs( usePubspecOverrides: $usePubspecOverrides, runPubGetInParallel: $runPubGetInParallel, + runPubGetOffline: $runPubGetOffline, )'''; } } diff --git a/packages/melos/test/commands/bootstrap_test.dart b/packages/melos/test/commands/bootstrap_test.dart index 3335794d4..2b1146fba 100644 --- a/packages/melos/test/commands/bootstrap_test.dart +++ b/packages/melos/test/commands/bootstrap_test.dart @@ -10,6 +10,7 @@ import 'package:test/test.dart'; import '../matchers.dart'; import '../utils.dart'; +import '../workspace_config_test.dart'; io.Directory createTmpDir() { final dir = io.Directory.systemTemp.createTempSync(); @@ -575,6 +576,58 @@ e-Because a depends on package_that_does_not_exists any which doesn't exist (cou ); }); + test('can run pub get offline', () async { + final workspaceDir = createTemporaryWorkspaceDirectory( + configBuilder: (path) => MelosWorkspaceConfig.fromYaml( + createYamlMap( + { + 'command': { + 'bootstrap': { + 'runPubGetOffline': true, + }, + }, + }, + defaults: configMapDefaults, + ), + path: path, + ), + ); + + final logger = TestLogger(); + final config = await MelosWorkspaceConfig.fromDirectory(workspaceDir); + final workspace = await MelosWorkspace.fromConfig( + config, + logger: logger.toMelosLogger(), + ); + final melos = Melos(logger: logger, config: config); + final pubExecArgs = pubCommandExecArgs( + useFlutter: workspace.isFlutterWorkspace, + workspace: workspace, + ); + + await runMelosBootstrap(melos, logger); + + expect( + logger.output, + ignoringAnsii( + ''' +melos bootstrap + └> ${workspaceDir.path} + +Running "${pubExecArgs.join(' ')} get --offline" in workspace packages... + +Linking workspace packages... + > SUCCESS + +Generating IntelliJ IDE files... + > SUCCESS + + -> 0 packages bootstrapped +''', + ), + ); + }); + test('can disable IDE generation using melos config', () {}, skip: true); test('can supports package filter', () {}, skip: true); diff --git a/packages/melos/test/workspace_config_test.dart b/packages/melos/test/workspace_config_test.dart index e7d53382c..cb8c81e49 100644 --- a/packages/melos/test/workspace_config_test.dart +++ b/packages/melos/test/workspace_config_test.dart @@ -181,6 +181,21 @@ void main() { ); }); + test('can decode `bootstrap` with pub get offline', () { + expect( + CommandConfigs.fromYaml(const { + 'bootstrap': { + 'runPubGetOffline': true, + } + }), + const CommandConfigs( + bootstrap: BootstrapCommandConfigs( + runPubGetOffline: true, + ), + ), + ); + }); + test('can decode `version`', () { expect( CommandConfigs.fromYaml(const {