Skip to content

feat(flutter-packages-builder): create Flutter monorepo tool#84

Merged
mrverdant13 merged 1 commit into
mainfrom
flutter-mono/feat/create-flutter-monorepo-tool
Apr 16, 2026
Merged

feat(flutter-packages-builder): create Flutter monorepo tool#84
mrverdant13 merged 1 commit into
mainfrom
flutter-mono/feat/create-flutter-monorepo-tool

Conversation

@mrverdant13
Copy link
Copy Markdown
Owner

Details

Create Flutter monorepo tool

@mrverdant13 mrverdant13 self-assigned this Apr 16, 2026
@mrverdant13 mrverdant13 requested a review from Copilot April 16, 2026 21:52
@mrverdant13 mrverdant13 merged commit 6868c39 into main Apr 16, 2026
3 of 4 checks passed
@mrverdant13 mrverdant13 deleted the flutter-mono/feat/create-flutter-monorepo-tool branch April 16, 2026 21:54
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new Node-based CLI tool (flutter-mono) intended to run tasks across a Flutter/Dart monorepo while selecting the Flutter SDK version per package (via FVM), driven by a repo-root flutter_mono.yaml config.

Changes:

  • Introduces tool/flutter-mono.mjs CLI with list, run, and exec commands.
  • Implements package discovery (via pubspec scanning), basic filtering, and per-package Flutter version resolution from environment.flutter / .fvmrc.
  • Adds a minimal YAML parser to read flutter_mono.yaml without external dependencies.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tool/flutter-mono.mjs
Comment on lines +347 to +351
const result = spawnSync(command, {
cwd: pkg.dir,
stdio: 'inherit',
shell: true,
env: {
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

runInPackage uses spawnSync(command, { shell: true }) with a single string command. This makes execution dependent on the platform shell and re-parses the string (leading to subtle quoting bugs and inconsistent behavior vs other repo tooling like tool/build-flutter-packages.mjs, which uses spawnSync(file, args)). Consider switching to spawnSync(file, args, { shell: false }) (or a structured command representation in config) so commands run deterministically and arguments are not re-interpreted by the shell.

Copilot uses AI. Check for mistakes.
Comment thread tool/flutter-mono.mjs
Comment on lines +168 to +171
for (const pattern of config.packages) {
const baseDir = pattern.replace(/\/{0,1}\*+$/, '').replace(/\/$/, '') || '.';
scanForPubspecs(join(ROOT_DIR, baseDir), found);
}
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

discoverPackageDirs documents config.packages as “glob patterns”, but the implementation effectively only supports patterns that end with */** by stripping trailing wildcards and then scanning that base directory. If a user provides a glob like packages/*/subpkg, the * remains in the path and discovery will fail/miss packages. Either implement real glob expansion (e.g. using a glob library) or tighten the config contract/docs to “root directories to scan” rather than globs.

Copilot uses AI. Check for mistakes.
Comment thread tool/flutter-mono.mjs
scope: flags.scope,
flutter: flags.flutter || scriptFilter.flutter === true,
dart: flags.dart || scriptFilter.dart === true,
dirExists: flags['dir-exists'] ?? scriptFilter.dirExists ?? null,
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

Script filter keys are mixed between kebab-case and camelCase: CLI uses --dir-exists, but script-level config is read from scriptFilter.dirExists. Since parseYaml preserves keys as-is, a natural YAML key like dir-exists: (matching the CLI) would be ignored. Consider supporting both spellings or standardizing/documenting one naming convention for filter keys in flutter_mono.yaml.

Suggested change
dirExists: flags['dir-exists'] ?? scriptFilter.dirExists ?? null,
dirExists: flags['dir-exists'] ?? scriptFilter.dirExists ?? scriptFilter['dir-exists'] ?? null,

Copilot uses AI. Check for mistakes.
Comment thread tool/flutter-mono.mjs
Comment on lines +416 to +417
const command = extra.length > 0 ? `${scriptConfig.run} ${extra.join(' ')}` : scriptConfig.run;

Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

runScript builds the command by concatenating extra into a single string. Because process.argv has already stripped shell quotes, extra.join(' ') loses argument boundaries/quoting (e.g. -- foo "a b" becomes foo a b) and can change the meaning of commands. Consider executing with spawnSync(file, args, ...) (no string join) or using a proper argv/shell-quoting strategy so arguments with spaces are preserved.

Copilot uses AI. Check for mistakes.
Comment thread tool/flutter-mono.mjs
}

case 'exec':
execCommand(extra.join(' '), packages, installedVersions, fallbackVersion, flags);
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

exec passes extra.join(' ') into execCommand, which has the same quoting/argument-boundary problem as run (arguments containing spaces will be split when the shell re-parses the string). Prefer passing the raw extra array through and invoking spawnSync(cmd, args, ...) to preserve the original argv exactly.

Suggested change
execCommand(extra.join(' '), packages, installedVersions, fallbackVersion, flags);
execCommand(extra, packages, installedVersions, fallbackVersion, flags);

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants