fix: derive Flutter image tag from .fvmrc to prevent version mismatch (#405)

## What

`ci/main.go` previously hardcoded the Flutter container image tag (`ghcr.io/cirruslabs/flutter:3.44.0`) separately from `.fvmrc` (`{ "flutter": "3.44.1" }`). These two values drifted, causing the deploy failure in #394.

## How

`New()` now accepts `ctx context.Context` and returns `(*Ci, error)`. It reads `.fvmrc` from the source directory, parses the `flutter` field, and stores it as `Ci.FlutterVersion`. `toolchain()` constructs the image tag as `"ghcr.io/cirruslabs/flutter:" + m.FlutterVersion`. `Graph()` also uses the live value instead of a stale literal.

Result: `.fvmrc` is the single source of truth. Bumping Flutter via Renovate or manually only requires editing `.fvmrc`; the Dagger pipeline picks up the new version automatically.

## Verification

- `gofmt -e ci/main.go` passes
- No schema changes; no `build_runner` run needed

Closes #396

Co-authored-by: Thomas SharedInbox <sharedinbox@thomas-guettler.de>
Co-authored-by: guettli <guettli@noreply.codeberg.org>
Reviewed-on: https://codeberg.org/guettli/sharedinbox/pulls/405
This commit was merged in pull request #405.
This commit is contained in:
Bot of Thomas Güttler
2026-06-04 17:35:08 +02:00
committed by guettli
co-authored by guettli Thomas SharedInbox
parent 6177605f22
commit f28630fd7e
+23 -5
View File
@@ -3,6 +3,7 @@ package main
import (
"context"
"dagger/ci/internal/dagger"
"encoding/json"
"fmt"
"time"
@@ -149,15 +150,32 @@ if __name__ == "__main__":
type Ci struct {
Source *dagger.Directory
FlutterVersion string
}
func New(
ctx context.Context,
// +defaultPath=".."
source *dagger.Directory,
) *Ci {
) (*Ci, error) {
fvmrcContents, err := source.File(".fvmrc").Contents(ctx)
if err != nil {
return nil, fmt.Errorf("failed to read .fvmrc: %w", err)
}
var fvmrc struct {
Flutter string `json:"flutter"`
}
if err := json.Unmarshal([]byte(fvmrcContents), &fvmrc); err != nil {
return nil, fmt.Errorf("failed to parse .fvmrc: %w", err)
}
if fvmrc.Flutter == "" {
return nil, fmt.Errorf(".fvmrc is missing the 'flutter' field")
}
return &Ci{
FlutterVersion: fvmrc.Flutter,
Source: source.Filter(dagger.DirectoryFilterOpts{
Include: []string{
".fvmrc",
"lib/",
"test/",
"assets/",
@@ -173,7 +191,7 @@ func New(
"website/",
},
}),
}
}, nil
}
// toolchain returns the Flutter+Android toolchain without any mutable cache mounts.
@@ -181,7 +199,7 @@ func New(
// Used as the base for pubGetLayer so flutter pub get is execution-cached between runs.
func (m *Ci) toolchain() *dagger.Container {
return dag.Container().
From("ghcr.io/cirruslabs/flutter:3.44.0").
From("ghcr.io/cirruslabs/flutter:"+m.FlutterVersion).
WithExec([]string{"apt-get", "-qq", "update"}).
WithExec([]string{"apt-get", "install", "-y", "-qq", "clang", "cmake", "ninja-build", "pkg-config", "libgtk-3-dev", "liblzma-dev", "libsecret-1-dev", "libgcrypt20-dev", "libjsoncpp-dev", "sqlite3", "iproute2", "netcat-openbsd", "xvfb", "libosmesa6", "libegl1", "lld"}).
WithExec([]string{"useradd", "-m", "-s", "/bin/bash", "ci"}).
@@ -902,12 +920,12 @@ func (m *Ci) Renovate(ctx context.Context, renovateToken *dagger.Secret) (string
//
// dagger call --progress=plain -q -m ci --source=. graph
func (m *Ci) Graph() string {
return `# CI Pipeline Graph
return fmt.Sprintf(`# CI Pipeline Graph
`+"```"+`mermaid
flowchart TD
subgraph dagger ["Dagger · Check pipeline"]
toolchain["toolchain\nflutter:3.41.6 + NDK + apt + precache"]
toolchain["toolchain\nflutter:%s + NDK + apt + precache"]`, m.FlutterVersion) + `
pubGet["pubGetLayer\nflutter pub get"]
codegen["codegenBase\nbuild_runner build\n(shared cache)"]
stalwart(["Stalwart service\nIMAP · JMAP · SMTP · Sieve"])