From cca0e5d46198816b76b6f83d945815e724adf737 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bot=20of=20Thomas=20G=C3=BCttler?= Date: Fri, 5 Jun 2026 11:50:49 +0200 Subject: [PATCH] feat: run local Dart tasks via Dagger (#417) (#418) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Adds \`CheckFast\`, \`Analyze\`, \`FormatWrite\`, \`Codegen\`, and \`AnalyzeFix\` Dagger functions to \`ci/main.go\` - Updates \`format\`, \`codegen\`, \`analyze\`, \`analyze-fix\`, and \`check-fast\` Taskfile tasks to delegate to Dagger and export modified files back to the host (\`-o .\`) - Updates the \`dart-check\` pre-commit hook to run \`dagger call ... check-fast\` instead of \`scripts/pre_commit_check.sh\` These tasks no longer require a local Dart/Flutter SDK installation — Dagger pulls the toolchain image and runs everything in a container. ## New Dagger functions | Function | Returns | What it does | |---|---|---| | \`CheckFast(ctx)\` | \`string\` | Runs CheckHygiene, CheckLayers, Format, Analyze, CheckMocks, Coverage in parallel | | \`Analyze(ctx)\` | \`string\` | \`dart analyze --fatal-infos\` | | \`FormatWrite()\` | \`*dagger.Directory\` | \`dart format lib test\` — writes files, returns \`/src\` | | \`Codegen()\` | \`*dagger.Directory\` | \`flutter pub run build_runner build\` — returns \`/src\` with generated files | | \`AnalyzeFix()\` | \`*dagger.Directory\` | \`dart fix --apply\` — writes files, returns \`/src\` | ## Test plan - [ ] \`task format\` — runs Dagger, exports formatted files back to \`.\` - [ ] \`task codegen\` — runs Dagger, exports generated \`.g.dart\` files back to \`.\` - [ ] \`task analyze\` — runs Dagger, prints analysis output - [ ] \`task analyze-fix\` — runs Dagger, exports fixed files back to \`.\` - [ ] \`task check-fast\` — runs all fast checks in parallel via Dagger - [ ] Pre-commit hook triggers \`dagger call ... check-fast\` on commit Closes #417 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Thomas SharedInbox Co-authored-by: guettli Reviewed-on: https://codeberg.org/guettli/sharedinbox/pulls/418 --- .pre-commit-config.yaml | 2 +- Taskfile.yml | 40 ++++++++------------------ ci/main.go | 62 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 30 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index da357db..794ddf2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -32,7 +32,7 @@ repos: - id: dart-check name: dart format (autofix) + check-fast (parallel) language: system - entry: bash -c 'cd "$(git rev-parse --show-toplevel)" && nix develop --command scripts/pre_commit_check.sh' + entry: bash -c 'cd "$(git rev-parse --show-toplevel)" && nix develop --command dagger call --progress=plain -q -m ci --source=. check-fast' pass_filenames: false always_run: true - id: ci-no-direct-dagger diff --git a/Taskfile.yml b/Taskfile.yml index 5a901e8..e4d7fe6 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -96,34 +96,19 @@ tasks: - scripts/silent_on_success.sh fvm flutter pub run build_runner build --delete-conflicting-outputs codegen: - desc: Generate Drift DB code (run after any schema change) - deps: [_preflight, _pub-get] - sources: - - lib/**/*.dart - - pubspec.yaml - generates: - - lib/**/*.g.dart + desc: Generate Drift DB code via Dagger (exports generated files back to host) cmds: - - fvm flutter pub run build_runner build --delete-conflicting-outputs + - dagger call --progress=plain -q -m ci --source=. codegen -o . analyze: - desc: Static analysis (flutter analyze) - deps: [_preflight, _codegen] - sources: - - lib/**/*.dart - - test/**/*.dart - - pubspec.yaml - - analysis_options.yaml + desc: Static analysis via Dagger (dart analyze --fatal-infos) cmds: - - scripts/run_analyze.sh + - dagger call --progress=plain -q -m ci --source=. analyze format: - desc: Format all Dart source files - deps: [_preflight] - sources: - - "**/*.dart" + desc: Format all Dart source files via Dagger (writes back to host) cmds: - - fvm dart format lib test + - dagger call --progress=plain -q -m ci --source=. format-write -o . check-mocks: desc: Fail if any *.mocks.dart file is out of date (re-runs build_runner) @@ -136,13 +121,9 @@ tasks: - scripts/check_mocks_fresh.sh analyze-fix: - desc: Auto-fix lint issues with dart fix --apply - deps: [_preflight] - sources: - - lib/**/*.dart - - test/**/*.dart + desc: Auto-fix lint issues via Dagger (dart fix --apply, writes back to host) cmds: - - fvm dart fix --apply + - dagger call --progress=plain -q -m ci --source=. analyze-fix -o . test: desc: Unit tests + coverage gate (fails if any non-excluded lib/ file is missing) @@ -690,8 +671,9 @@ tasks: ${SSH_USER}@${SSH_HOST}:public_html/ check-fast: - desc: Pre-commit checks — analyze + unit+widget tests + coverage gate (no build, no integration) - deps: [analyze, check-coverage, check-hygiene, check-layers, check-mocks] + desc: Pre-commit checks via Dagger (format, analyze, mocks, coverage — no integration or backend) + cmds: + - dagger call --progress=plain -q -m ci --source=. check-fast check-layers: desc: Enforce architecture — ui/ must not import data/ (only core/ interfaces allowed) diff --git a/ci/main.go b/ci/main.go index 920cc44..b508d80 100644 --- a/ci/main.go +++ b/ci/main.go @@ -440,6 +440,68 @@ func (m *Ci) Format(ctx context.Context) (string, error) { Stdout(ctx) } +// FormatWrite formats Dart files and exports the modified /src directory. +func (m *Ci) FormatWrite() *dagger.Directory { + return m.setup(m.checkSrc()). + WithExec([]string{"dart", "format", "lib", "test"}). + Directory("/src") +} + +// Analyze runs static analysis with dart analyze --fatal-infos. +func (m *Ci) Analyze(ctx context.Context) (string, error) { + return m.setup(m.checkSrc()). + WithExec([]string{"dart", "analyze", "--fatal-infos"}). + Stdout(ctx) +} + +// Codegen runs build_runner and exports the modified /src directory. +func (m *Ci) Codegen() *dagger.Directory { + return m.codegenBase().Directory("/src") +} + +// AnalyzeFix runs dart fix --apply and exports the modified /src directory. +func (m *Ci) AnalyzeFix() *dagger.Directory { + return m.setup(m.checkSrc()). + WithExec([]string{"dart", "fix", "--apply"}). + Directory("/src") +} + +// CheckFast runs fast checks (hygiene, layers, format, analyze, mocks, coverage) in parallel. +func (m *Ci) CheckFast(ctx context.Context) (string, error) { + ctx, cancel := context.WithTimeout(ctx, 15*time.Minute) + defer cancel() + + var eg errgroup.Group + eg.Go(func() error { + _, err := m.CheckHygiene(ctx) + return err + }) + eg.Go(func() error { + _, err := m.CheckLayers(ctx) + return err + }) + eg.Go(func() error { + _, err := m.Format(ctx) + return err + }) + eg.Go(func() error { + _, err := m.Analyze(ctx) + return err + }) + eg.Go(func() error { + _, err := m.CheckGenerated(ctx) + return err + }) + eg.Go(func() error { + _, err := m.Coverage(ctx) + return err + }) + if err := eg.Wait(); err != nil { + return "", err + } + return "All fast checks passed!", nil +} + // CheckGenerated verifies that all generated files (*.g.dart, *.mocks.dart) are up to date. // It snapshots the committed source (including any stale generated files) before // running build_runner, so git diff detects real staleness instead of always