Skip to content

Toolkit Extensions

Affected Package Detection Enterprise ​

The affected command detects which workspace packages are impacted by git changes and runs commands only on those packages. This dramatically speeds up CI pipelines by skipping unchanged packages. The workspace may sit in a subdirectory of a larger git repository: changed files are read relative to the workspace root.

affectedOne changed package pulls in only the packages that depend on itNeeds Enterprise

Step 1 of 5, before: CI should not test the whole workspace for every pull request. affected works out which packages a change can break, using git diff and the path dependencies between pubspecs.

  • apps/
  • template_app/
  • features/
  • auth/
  • auth_impl/
  • home/
  • home_impl/
  • infrastructure/
  • flagr_feature_flag_impl/
  • grafana_monitoring_impl/
  • network_sdk_api/
  • network_sdk_dio/
  • network_sdk_http/
infrastructure/network_sdk_api/lib/src/client/http_client.dart
abstract interface class HttpClient() {  /// Sends a GET request to the specified [path].  Future<HttpResponse> get(String path, {/* … */});  // …}

Usage ​

bash
# List affected packages
dart run monorepo_toolkit affected list

# Run analysis on affected packages only
dart run monorepo_toolkit affected analyze

# Run tests on affected packages only
dart run monorepo_toolkit affected test --coverage

# Run any command on affected packages
dart run monorepo_toolkit affected run -- "dart format --set-exit-if-changed ."

Subcommands ​

affected list ​

Lists packages affected by git changes compared to a base branch:

bash
dart run monorepo_toolkit affected list --base develop
dart run monorepo_toolkit affected list --format plain  # CI-friendly output
FlagAbbrDefaultDescription
--base-bmainBase branch or commit to compare against
--format-fprettyOutput format: pretty or plain
--json-jfalseOutput as JSON array for GitHub Actions matrix

affected analyze ​

Runs flutter analyze lib on affected packages. A package without lib/ is skipped:

bash
dart run monorepo_toolkit affected analyze --base develop
dart run monorepo_toolkit affected analyze --no-fail-fast
dart run monorepo_toolkit affected analyze --no-fatal-infos --no-fatal-warnings  # what generated CI and `melos run analyze` use
FlagAbbrDefaultDescription
--base-bmainBase branch or commit to compare against
--fail-fasttrueStop on first package failure
--fatal-infostrueFail on info-level issues (--no-fatal-infos to allow them)
--fatal-warningstrueFail on warnings (--no-fatal-warnings to allow them)

affected test ​

Runs flutter test on affected packages with optional coverage collection. Golden-tagged tests are excluded (--exclude-tags golden) unless you pass --goldens, because goldens fail on machines whose rasterizer differs from the fixtures. A package without a test/ directory is skipped, and one whose only tests are excluded (flutter test exit code 79) counts as passed:

bash
dart run monorepo_toolkit affected test --coverage --base develop
FlagAbbrDefaultDescription
--base-bmainBase branch or commit to compare against
--coveragefalseCollect coverage information
--goldensfalseInclude golden-tagged tests
--fail-fasttrueStop on first package failure
--total-shards——Total number of shards for within-package test splitting
--shard-index——Zero-based index of this shard (requires --total-shards)

affected run ​

Runs an arbitrary command on affected packages:

bash
dart run monorepo_toolkit affected run -- "flutter test --coverage"
dart run monorepo_toolkit affected run -- "dart format --set-exit-if-changed ."
FlagAbbrDefaultDescription
--base-bmainBase branch or commit to compare against
--fail-fasttrueStop on first package failure

affected format ​

Checks formatting (dart format --set-exit-if-changed .) on affected packages. Flags: --base/-b (default main), --fail-fast (default true).

affected fix-check ​

Runs dart fix --dry-run on affected packages and fails if any fixes are suggested. Flags: --base/-b, --fail-fast.

affected golden ​

Runs flutter test --update-goldens on affected packages. Pass --check to verify without updating (flutter test --tags golden).

FlagAbbrDefaultDescription
--base-bmainBase branch or commit to compare against
--checkfalseVerify goldens without updating them
--fail-fasttrueStop on first package failure

affected build ​

Runs flutter build on affected app packages only (library packages are skipped).

FlagAbbrDefaultDescription
--base-bmainBase branch or commit to compare against
--platform-papkBuild target: apk, aab, ios, ipa (iOS targets need macOS + Xcode)
--fail-fasttrueStop on first package failure

affected license ​

Audits transitive dependency licenses of affected packages and fails on any license outside the allowlist (MIT, Apache-2.0, BSD-3-Clause, BSD-2-Clause, ISC, Zlib by default).

FlagAbbrDefaultDescription
--base-bmainBase branch or commit to compare against
--allowExtra SPDX license identifier to allow (repeatable)
--fail-fastfalseStop on first package with a disallowed license

affected devtool ​

Runs other workspace devtools scoped to the affected packages. Subcommands: size-guard (--base, --changed-only), dependency-graph (--base, --format/-f, --output/-o) and coverage (--base, --fail-fast).

bash
dart run monorepo_toolkit affected devtool coverage --base origin/develop

Configuration ​

Create an affected.yaml at the workspace root:

yaml
affected:
  base_branch: develop

  # Predefined commands (merged with defaults: analyze, test, format)
  commands:
    lint: "dart run custom_lints ."

  # Packages always included regardless of changes
  always_include:
    - template_app

  # Glob patterns to ignore when detecting changes
  ignore:
    - "devtools/**"
    - ".github/**"
    - ".claude/**"

The default ignore patterns are devtools/**, .github/**, and .claude/**. The default predefined commands are analyze (flutter analyze lib), test (flutter test), and format (dart format --set-exit-if-changed .).

CI integration ​

Generated projects already call it: devtools/ci/test.sh runs affected analyze --no-fatal-infos --no-fatal-warnings and affected test --coverage with the base that devtools/ci/scope.sh picks (see CI test scope). By hand:

yaml
steps:
  - name: Analyze affected packages
    run: dart run monorepo_toolkit affected analyze --base origin/develop

  - name: Test affected packages
    run: dart run monorepo_toolkit affected test --coverage --base origin/develop

GitHub Actions Matrix (CI Parallelism) ​

Use affected list --json to feed a dynamic matrix into GitHub Actions, so each affected package is tested in its own parallel job.

yaml
jobs:
  detect:
    runs-on: ubuntu-latest
    outputs:
      packages: ${{ steps.affected.outputs.packages }}
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: dart-lang/setup-dart@v1
      - name: Detect affected packages
        id: affected
        run: |
          PACKAGES=$(dart run monorepo_toolkit affected list --json --base origin/develop)
          echo "packages=$PACKAGES" >> "$GITHUB_OUTPUT"

  test:
    needs: detect
    if: ${{ needs.detect.outputs.packages != '[]' }}
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        package: ${{ fromJSON(needs.detect.outputs.packages) }}
    steps:
      - uses: actions/checkout@v4
      - uses: dart-lang/setup-dart@v1
      - name: Test ${{ matrix.package }}
        run: dart run monorepo_toolkit affected test --base origin/develop

The --json flag outputs a JSON array of package names (e.g. ["auth_impl","ui_kit"]). GitHub's fromJSON() function expands this into the matrix, creating one job per affected package automatically. See ci-affected-matrix.yml.example in the generated project's devtools/scripts/affected/ directory for the full annotated example (copy it into .github/workflows/ to use it).