Compare commits

..
Author SHA1 Message Date
Bot of Thomas Güttler 202fb9cd74 Merge branch 'main' into issue-478-fix-stalwart-dual-stack-bind 2026-06-07 04:27:16 +02:00
Thomas SharedInbox c6b6d942d4 Merge branch 'main' into issue-478-fix-stalwart-dual-stack-bind 2026-06-07 00:30:48 +02:00
Thomas SharedInbox bc0f4e83fc Merge branch 'main' into issue-478-fix-stalwart-dual-stack-bind 2026-06-07 00:15:43 +02:00
Thomas SharedInboxandClaude Sonnet 4.6 5a8a03fb70 fix(ci): forward SSH tunnel directly to dagger engine socket
Eliminates the socat bridge dependency by using OpenSSH's built-in
Unix socket forwarding (-L port:socket_path). The dagger user already
owns /run/dagger/engine.sock so no intermediate TCP listener is needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 23:43:26 +02:00
Thomas SharedInboxandClaude Sonnet 4.6 9c6b037b21 fix: remove dual-stack [::]:PORT bind to silence spurious EADDRINUSE errors
On Linux with IPv6 dual-stack (the Docker default), binding 0.0.0.0:PORT
already covers IPv6 via the dual-stack socket, so the subsequent [::]:PORT
bind hits EADDRINUSE on every Stalwart startup. Drop the sed substitution
that added the [::]:PORT entries.

Closes #478

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 21:51:17 +02:00
+20 -28
View File
@@ -388,7 +388,7 @@ func (m *Ci) Stalwart() *dagger.Service {
return dag.Container().
From("stalwartlabs/stalwart:v0.14.1").
WithFile("/etc/stalwart/config.toml.orig", config).
WithExec([]string{"/bin/sh", "-c", "sed -e 's/hostname = \"localhost\"/hostname = \"stalwart\"/' -e 's/bind = \\[\"0.0.0.0:\\([0-9]*\\)\"\\]/bind = [\"0.0.0.0:\\1\", \"[::]:\\1\"]/g' /etc/stalwart/config.toml.orig > /etc/stalwart/config.toml"}).
WithExec([]string{"/bin/sh", "-c", "sed -e 's/hostname = \"localhost\"/hostname = \"stalwart\"/' /etc/stalwart/config.toml.orig > /etc/stalwart/config.toml"}).
WithDirectory("/tmp/stalwart", dataDir).
WithExposedPort(8080). // JMAP
WithExposedPort(1430). // IMAP
@@ -594,33 +594,25 @@ func (m *Ci) Check(ctx context.Context) (string, error) {
return "", err
}
// Run format, analyze, generated-code check, and coverage in parallel —
// they all share the same setup base and have no dependencies on each other.
var analyze, mocks, coverage string
var checkEg errgroup.Group
checkEg.Go(func() error {
setup := m.setup(m.checkSrc())
_, err := setup.WithExec([]string{"dart", "format", "--output=none", "--set-exit-if-changed", "lib", "test"}).Stdout(ctx)
return err
})
checkEg.Go(func() error {
setup := m.setup(m.checkSrc())
var err error
analyze, err = setup.WithExec([]string{"dart", "analyze", "--fatal-infos"}).Stdout(ctx)
return err
})
checkEg.Go(func() error {
var err error
mocks, err = m.CheckGenerated(ctx)
return err
})
checkEg.Go(func() error {
var err error
coverage, err = m.Coverage(ctx)
return err
})
if err := checkEg.Wait(); err != nil {
return "", err
checkSetup := m.setup(m.checkSrc())
if _, err := checkSetup.WithExec([]string{"dart", "format", "--output=none", "--set-exit-if-changed", "lib", "test"}).Stdout(ctx); err != nil {
return "Format check failed", err
}
analyze, err := checkSetup.WithExec([]string{"dart", "analyze", "--fatal-infos"}).Stdout(ctx)
if err != nil {
return analyze, err
}
mocks, err := m.CheckGenerated(ctx)
if err != nil {
return mocks, err
}
coverage, err := m.Coverage(ctx)
if err != nil {
return coverage, err
}
// Use errgroup.Group (not WithContext) so a failing test does not cancel its