diff --git a/.github/workflows/dart_package.yml b/.github/workflows/dart_package.yml index 3212c6d..2619b6f 100644 --- a/.github/workflows/dart_package.yml +++ b/.github/workflows/dart_package.yml @@ -17,6 +17,26 @@ on: type: string default: "" description: "Newline-separated list of globs to upload as a workflow artifact, relative to the repository root (e.g. 'coverage/lcov.info'). Empty disables the upload." + cognitive_complexity_diff_base: + required: false + type: string + default: "" + description: "Git reference to compare against when computing complexity changes (e.g. 'origin/main'). Empty lets the action auto-detect the base." + cognitive_complexity_fail_on_increase: + required: false + type: boolean + default: false + description: "Whether to fail the job when cognitive complexity increases relative to cognitive_complexity_diff_base." + cognitive_complexity_fail_threshold: + required: false + type: number + default: 15 + description: "The maximum cognitive complexity score a function may reach before the job fails." + cognitive_complexity_targets: + required: false + type: string + default: "lib" + description: "Space-separated list of directories or files to scan for cognitive complexity. Resolved from the repository root, not working_directory." collect_coverage_from: required: false type: string @@ -67,6 +87,10 @@ on: required: false type: boolean default: true + run_cognitive_complexity: + required: false + type: boolean + default: false run_skipped: required: false type: boolean @@ -114,6 +138,10 @@ jobs: steps: - name: ๐Ÿ“š Git Checkout uses: actions/checkout@v7 + with: + # Cognitive complexity comparison needs the full history to resolve the + # diff base; a shallow clone is enough for every other step. + fetch-depth: ${{inputs.run_cognitive_complexity && '0' || '1'}} - name: ๐ŸŽฏ Setup Dart uses: dart-lang/setup-dart@v1.8.1 @@ -149,6 +177,15 @@ jobs: dart pub global activate bloc_tools bloc lint . + - name: ๐Ÿง  Cognitive Complexity + if: ${{inputs.run_cognitive_complexity}} + uses: kevmoo/analytica.dart/packages/cognitive_complexity@main + with: + targets: ${{inputs.cognitive_complexity_targets}} + fail-threshold: ${{inputs.cognitive_complexity_fail_threshold}} + fail-on-increase: ${{inputs.cognitive_complexity_fail_on_increase}} + diff-base: ${{inputs.cognitive_complexity_diff_base}} + - name: ๐Ÿงช Run Tests run: >- very_good dart test diff --git a/.github/workflows/flutter_package.yml b/.github/workflows/flutter_package.yml index 440b35e..328709d 100644 --- a/.github/workflows/flutter_package.yml +++ b/.github/workflows/flutter_package.yml @@ -17,6 +17,26 @@ on: type: string default: "" description: "Newline-separated list of globs to upload as a workflow artifact, relative to the repository root (e.g. '**/failures/**'). Empty disables the upload." + cognitive_complexity_diff_base: + required: false + type: string + default: "" + description: "Git reference to compare against when computing complexity changes (e.g. 'origin/main'). Empty lets the action auto-detect the base." + cognitive_complexity_fail_on_increase: + required: false + type: boolean + default: false + description: "Whether to fail the job when cognitive complexity increases relative to cognitive_complexity_diff_base." + cognitive_complexity_fail_threshold: + required: false + type: number + default: 15 + description: "The maximum cognitive complexity score a function may reach before the job fails." + cognitive_complexity_targets: + required: false + type: string + default: "lib" + description: "Space-separated list of directories or files to scan for cognitive complexity. Resolved from the repository root, not working_directory." collect_coverage_from: required: false type: string @@ -77,6 +97,10 @@ on: required: false type: boolean default: true + run_cognitive_complexity: + required: false + type: boolean + default: false run_skipped: required: false type: boolean @@ -127,6 +151,10 @@ jobs: steps: - name: ๐Ÿ“š Git Checkout uses: actions/checkout@v7 + with: + # Cognitive complexity comparison needs the full history to resolve the + # diff base; a shallow clone is enough for every other step. + fetch-depth: ${{inputs.run_cognitive_complexity && '0' || '1'}} - name: ๐Ÿฆ Setup Flutter uses: subosito/flutter-action@v2.23.0 @@ -166,6 +194,15 @@ jobs: flutter pub global activate bloc_tools bloc lint . + - name: ๐Ÿง  Cognitive Complexity + if: ${{inputs.run_cognitive_complexity}} + uses: kevmoo/analytica.dart/packages/cognitive_complexity@main + with: + targets: ${{inputs.cognitive_complexity_targets}} + fail-threshold: ${{inputs.cognitive_complexity_fail_threshold}} + fail-on-increase: ${{inputs.cognitive_complexity_fail_on_increase}} + diff-base: ${{inputs.cognitive_complexity_diff_base}} + # Built in a bash step so the test command below stays shell-agnostic # (Windows runners default to pwsh, which cannot parse bash loops). - name: ๐ŸŽฏ Resolve Dart Defines diff --git a/site/docs/workflows/dart_package.md b/site/docs/workflows/dart_package.md index 8a99bc1..b99deb5 100644 --- a/site/docs/workflows/dart_package.md +++ b/site/docs/workflows/dart_package.md @@ -17,8 +17,9 @@ The Dart package workflow consists of the following steps: 5. Format 6. Analyze 7. Bloc Lint (if enabled) -8. Run tests (includes coverage collection and enforcement) -9. Upload artifacts (if configured) +8. Cognitive Complexity (if enabled) +9. Run tests (includes coverage collection and enforcement) +10. Upload artifacts (if configured) ## Inputs @@ -143,6 +144,40 @@ The Dart package workflow consists of the following steps: **Default** `true` +### `run_cognitive_complexity` + +**Optional** Whether to run the [cognitive_complexity](https://pub.dev/packages/cognitive_complexity) audit on the package. See [Cognitive complexity](#cognitive-complexity). + +**Default** `false` + +### `cognitive_complexity_targets` + +**Optional** Space-separated list of directories or files to scan for cognitive complexity. + +:::note +Like [`artifact_paths`](#artifact_paths), these paths are resolved from the **repository root**, not from [`working_directory`](#working_directory). For a package nested in a monorepo, write the prefix out in full (e.g. `packages/my_package/lib`). +::: + +**Default** `"lib"` + +### `cognitive_complexity_fail_threshold` + +**Optional** The maximum cognitive complexity score a function may reach before the job fails. + +**Default** `15` + +### `cognitive_complexity_fail_on_increase` + +**Optional** Whether to fail the job when cognitive complexity increases relative to [`cognitive_complexity_diff_base`](#cognitive_complexity_diff_base). Requires the full git history, which is fetched automatically when [`run_cognitive_complexity`](#run_cognitive_complexity) is enabled. + +**Default** `false` + +### `cognitive_complexity_diff_base` + +**Optional** Git reference to compare against when computing complexity changes (e.g. `origin/main`). An empty value lets the action auto-detect the base. + +**Default** `""` + ### `artifact_paths` **Optional** A newline-separated list of globs to upload as a workflow artifact once the tests finish. Runs on both passing and failing test runs, so it captures output from a failed run as well as reports produced by a green one. An empty value disables the upload entirely. @@ -192,6 +227,30 @@ with: Exclusions and the rest of the pattern syntax work as described in the [`actions/upload-artifact` documentation](https://github.com/actions/upload-artifact#upload-using-multiple-paths-and-exclusions). +## Cognitive complexity + +Enable [`run_cognitive_complexity`](#run_cognitive_complexity) to audit the package with [`package:cognitive_complexity`](https://pub.dev/packages/cognitive_complexity). The step fails when any function's score exceeds [`cognitive_complexity_fail_threshold`](#cognitive_complexity_fail_threshold), and can additionally block increases relative to a base ref via [`cognitive_complexity_fail_on_increase`](#cognitive_complexity_fail_on_increase) and [`cognitive_complexity_diff_base`](#cognitive_complexity_diff_base). + +```yaml +with: + run_cognitive_complexity: true + cognitive_complexity_targets: 'lib' + cognitive_complexity_fail_threshold: 15 +``` + +To post the complexity report as a pull request comment, grant the caller workflow `pull-requests: write` permission: + +```yaml +jobs: + build: + permissions: + contents: read + pull-requests: write + uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/dart_package.yml@v1 + with: + run_cognitive_complexity: true +``` + ## Providing environment variables Tests sometimes read values from the environment via [`Platform.environment`](https://api.dart.dev/dart-io/Platform/environment.html), for example: diff --git a/site/docs/workflows/flutter_package.md b/site/docs/workflows/flutter_package.md index 5dcc6f4..ab52285 100644 --- a/site/docs/workflows/flutter_package.md +++ b/site/docs/workflows/flutter_package.md @@ -17,8 +17,9 @@ The Flutter package workflow consists of the following steps: 5. Format 6. Analyze 7. Bloc Lint (if enabled) -8. Run tests (includes coverage collection and enforcement) -9. Upload artifacts (if configured) +8. Cognitive Complexity (if enabled) +9. Run tests (includes coverage collection and enforcement) +10. Upload artifacts (if configured) ## Inputs @@ -148,6 +149,40 @@ Files other than `.fvmrc` and `fvm_config.json` (such as `pubspec.yaml`) are par **Default** `true` +### `run_cognitive_complexity` + +**Optional** Whether to run the [cognitive_complexity](https://pub.dev/packages/cognitive_complexity) audit on the package. See [Cognitive complexity](#cognitive-complexity). + +**Default** `false` + +### `cognitive_complexity_targets` + +**Optional** Space-separated list of directories or files to scan for cognitive complexity. + +:::note +Like [`artifact_paths`](#artifact_paths), these paths are resolved from the **repository root**, not from [`working_directory`](#working_directory). For a package nested in a monorepo, write the prefix out in full (e.g. `packages/my_package/lib`). +::: + +**Default** `"lib"` + +### `cognitive_complexity_fail_threshold` + +**Optional** The maximum cognitive complexity score a function may reach before the job fails. + +**Default** `15` + +### `cognitive_complexity_fail_on_increase` + +**Optional** Whether to fail the job when cognitive complexity increases relative to [`cognitive_complexity_diff_base`](#cognitive_complexity_diff_base). Requires the full git history, which is fetched automatically when [`run_cognitive_complexity`](#run_cognitive_complexity) is enabled. + +**Default** `false` + +### `cognitive_complexity_diff_base` + +**Optional** Git reference to compare against when computing complexity changes (e.g. `origin/main`). An empty value lets the action auto-detect the base. + +**Default** `""` + ### `run_skipped` **Optional** Run skipped tests instead of skipping them. @@ -222,6 +257,30 @@ with: Exclusions and the rest of the pattern syntax work as described in the [`actions/upload-artifact` documentation](https://github.com/actions/upload-artifact#upload-using-multiple-paths-and-exclusions). +## Cognitive complexity + +Enable [`run_cognitive_complexity`](#run_cognitive_complexity) to audit the package with [`package:cognitive_complexity`](https://pub.dev/packages/cognitive_complexity). The step fails when any function's score exceeds [`cognitive_complexity_fail_threshold`](#cognitive_complexity_fail_threshold), and can additionally block increases relative to a base ref via [`cognitive_complexity_fail_on_increase`](#cognitive_complexity_fail_on_increase) and [`cognitive_complexity_diff_base`](#cognitive_complexity_diff_base). + +```yaml +with: + run_cognitive_complexity: true + cognitive_complexity_targets: 'lib' + cognitive_complexity_fail_threshold: 15 +``` + +To post the complexity report as a pull request comment, grant the caller workflow `pull-requests: write` permission: + +```yaml +jobs: + build: + permissions: + contents: read + pull-requests: write + uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/flutter_package.yml@v1 + with: + run_cognitive_complexity: true +``` + ## Example Usage ```yaml diff --git a/test/package-lock.json b/test/package-lock.json index a079ab7..1948997 100644 --- a/test/package-lock.json +++ b/test/package-lock.json @@ -1503,9 +1503,6 @@ "arm" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1527,9 +1524,6 @@ "arm" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1551,9 +1545,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1575,9 +1566,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1599,9 +1587,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1623,9 +1608,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2137,9 +2119,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2154,9 +2133,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2171,9 +2147,6 @@ "loong64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2188,9 +2161,6 @@ "loong64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2205,9 +2175,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2222,9 +2189,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2239,9 +2203,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2256,9 +2217,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2273,9 +2231,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2290,9 +2245,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [