ci: remove Nix dependency and modernize Stalwart test setup with Dagger Services

This commit is contained in:
GuettliBot2
2026-05-17 13:17:28 +02:00
parent 34d28d8a56
commit 92778346d3
5 changed files with 76 additions and 110 deletions
+1 -10
View File
@@ -17,15 +17,6 @@ jobs:
with:
fetch-depth: 50
- uses: cachix/install-nix-action@v27
with:
nix_path: nixpkgs=channel:nixos-25.11
- name: Enable Nix flakes
run: |
mkdir -p ~/.config/nix
echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf
- name: Install Android SDK
run: |
SDK="${ANDROID_HOME:-$HOME/Android/Sdk}"
@@ -40,4 +31,4 @@ jobs:
fi
- name: Run Android Integration Tests
run: nix develop --no-warn-dirty --command task integration-android
run: task integration-android
+25 -72
View File
@@ -16,14 +16,11 @@ jobs:
with:
fetch-depth: 50
- uses: cachix/install-nix-action@v27
with:
nix_path: nixpkgs=channel:nixos-25.11
- name: Enable Nix flakes
- name: Install Dagger & Task
run: |
mkdir -p ~/.config/nix
echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf
curl -L https://dl.dagger.io/dagger/install.sh | BIN_DIR=/usr/local/bin sh
curl -sL https://taskfile.dev/install.sh | sh -s -- -b /usr/local/bin
sudo apt-get update && sudo apt-get install -y stunnel4 netcat-openbsd
- name: Setup Dagger Remote Engine (via stunnel)
env:
@@ -32,19 +29,10 @@ jobs:
DAGGER_CA_CERT: ${{ secrets.DAGGER_CA_CERT }}
DAGGER_CLIENT_CERT: ${{ secrets.DAGGER_CLIENT_CERT }}
DAGGER_CLIENT_KEY: ${{ secrets.DAGGER_CLIENT_KEY }}
run: nix develop --no-warn-dirty --command scripts/setup_dagger_remote.sh
- name: Setup Dagger Remote Engine (via stunnel)
env:
DAGGER_STUNNEL_URL1: ${{ secrets.DAGGER_STUNNEL_URL1 }}
DAGGER_STUNNEL_URL2: ${{ secrets.DAGGER_STUNNEL_URL2 }}
DAGGER_CA_CERT: ${{ secrets.DAGGER_CA_CERT }}
DAGGER_CLIENT_CERT: ${{ secrets.DAGGER_CLIENT_CERT }}
DAGGER_CLIENT_KEY: ${{ secrets.DAGGER_CLIENT_KEY }}
run: nix develop --no-warn-dirty --command scripts/setup_dagger_remote.sh
run: scripts/setup_dagger_remote.sh
- name: Run Full Check Suite
run: nix develop --no-warn-dirty --command dagger call --progress=plain -m ci check --source .
run: dagger call --progress=plain -m ci check --source .
build-linux:
name: Build Linux Release
@@ -57,14 +45,11 @@ jobs:
with:
fetch-depth: 50
- uses: cachix/install-nix-action@v27
with:
nix_path: nixpkgs=channel:nixos-25.11
- name: Enable Nix flakes
- name: Install Dagger & Task
run: |
mkdir -p ~/.config/nix
echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf
curl -L https://dl.dagger.io/dagger/install.sh | BIN_DIR=/usr/local/bin sh
curl -sL https://taskfile.dev/install.sh | sh -s -- -b /usr/local/bin
sudo apt-get update && sudo apt-get install -y stunnel4 netcat-openbsd
- name: Setup Dagger Remote Engine (via stunnel)
env:
@@ -73,7 +58,7 @@ jobs:
DAGGER_CA_CERT: ${{ secrets.DAGGER_CA_CERT }}
DAGGER_CLIENT_CERT: ${{ secrets.DAGGER_CLIENT_CERT }}
DAGGER_CLIENT_KEY: ${{ secrets.DAGGER_CLIENT_KEY }}
run: nix develop --no-warn-dirty --command scripts/setup_dagger_remote.sh
run: scripts/setup_dagger_remote.sh
- name: Build & Deploy Linux to server
continue-on-error: true
@@ -83,7 +68,7 @@ jobs:
SSH_HOST: ${{ secrets.SSH_HOST }}
run: |
HASH=$(git rev-parse --short HEAD)
nix develop --no-warn-dirty --command dagger call --progress=plain -m ci deploy-linux --source . --ssh-key env:SSH_PRIVATE_KEY --ssh-user "$SSH_USER" --ssh-host "$SSH_HOST" --commit-hash "$HASH"
dagger call --progress=plain -m ci deploy-linux --source . --ssh-key env:SSH_PRIVATE_KEY --ssh-user "$SSH_USER" --ssh-host "$SSH_HOST" --commit-hash "$HASH"
deploy-playstore:
name: Build & Deploy to Play Store
@@ -96,14 +81,11 @@ jobs:
with:
fetch-depth: 50
- uses: cachix/install-nix-action@v27
with:
nix_path: nixpkgs=channel:nixos-25.11
- name: Enable Nix flakes
- name: Install Dagger & Task
run: |
mkdir -p ~/.config/nix
echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf
curl -L https://dl.dagger.io/dagger/install.sh | BIN_DIR=/usr/local/bin sh
curl -sL https://taskfile.dev/install.sh | sh -s -- -b /usr/local/bin
sudo apt-get update && sudo apt-get install -y stunnel4 netcat-openbsd
- name: Setup Dagger Remote Engine (via stunnel)
env:
@@ -112,40 +94,14 @@ jobs:
DAGGER_CA_CERT: ${{ secrets.DAGGER_CA_CERT }}
DAGGER_CLIENT_CERT: ${{ secrets.DAGGER_CLIENT_CERT }}
DAGGER_CLIENT_KEY: ${{ secrets.DAGGER_CLIENT_KEY }}
run: nix develop --no-warn-dirty --command scripts/setup_dagger_remote.sh
- name: Install Android SDK (cached on runner between runs)
run: |
SDK="${ANDROID_HOME:-$HOME/Android/Sdk}"
if [ ! -d "$SDK/platforms/android-34" ]; then
echo "Android SDK not found, installing..."
wget -q https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip -O /tmp/cmdtools.zip
mkdir -p "$SDK/cmdline-tools"
unzip -q /tmp/cmdtools.zip -d "$SDK/cmdline-tools"
[ -d "$SDK/cmdline-tools/cmdline-tools" ] && mv "$SDK/cmdline-tools/cmdline-tools" "$SDK/cmdline-tools/latest"
yes | "$SDK/cmdline-tools/latest/bin/sdkmanager" --licenses >/dev/null 2>&1 || true
"$SDK/cmdline-tools/latest/bin/sdkmanager" "platform-tools" "build-tools;34.0.0" "platforms;android-34"
else
echo "Android SDK cached, skipping install."
fi
- name: Prepare Keystore
env:
ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
run: |
if [ -n "$ANDROID_KEYSTORE_BASE64" ]; then
echo "$ANDROID_KEYSTORE_BASE64" | base64 -d > android/app/upload-keystore.jks
else
echo "Error: ANDROID_KEYSTORE_BASE64 secret is not set."
exit 1
fi
run: scripts/setup_dagger_remote.sh
- name: Build & Deploy to Play Store
env:
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
PLAY_STORE_CONFIG_JSON: ${{ secrets.PLAY_STORE_CONFIG_JSON }}
run: |
nix develop --no-warn-dirty --command dagger call --progress=plain -m ci publish-android --source . --play-store-config env:PLAY_STORE_CONFIG_JSON
dagger call --progress=plain -m ci publish-android --source . --play-store-config env:PLAY_STORE_CONFIG_JSON
- name: Build & Deploy APK to server
continue-on-error: true
@@ -156,7 +112,7 @@ jobs:
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
run: |
HASH=$(git rev-parse --short HEAD)
nix develop --no-warn-dirty --command dagger call --progress=plain -m ci deploy-apk --source . --ssh-key env:SSH_PRIVATE_KEY --ssh-user "$SSH_USER" --ssh-host "$SSH_HOST" --commit-hash "$HASH"
dagger call --progress=plain -m ci deploy-apk --source . --ssh-key env:SSH_PRIVATE_KEY --ssh-user "$SSH_USER" --ssh-host "$SSH_HOST" --commit-hash "$HASH"
publish-website:
name: Publish Website Build History
@@ -172,14 +128,11 @@ jobs:
with:
fetch-depth: 1
- uses: cachix/install-nix-action@v27
with:
nix_path: nixpkgs=channel:nixos-25.11
- name: Enable Nix flakes
- name: Install Dagger & Task
run: |
mkdir -p ~/.config/nix
echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf
curl -L https://dl.dagger.io/dagger/install.sh | BIN_DIR=/usr/local/bin sh
curl -sL https://taskfile.dev/install.sh | sh -s -- -b /usr/local/bin
sudo apt-get update && sudo apt-get install -y stunnel4 netcat-openbsd
- name: Setup Dagger Remote Engine (via stunnel)
env:
@@ -188,7 +141,7 @@ jobs:
DAGGER_CA_CERT: ${{ secrets.DAGGER_CA_CERT }}
DAGGER_CLIENT_CERT: ${{ secrets.DAGGER_CLIENT_CERT }}
DAGGER_CLIENT_KEY: ${{ secrets.DAGGER_CLIENT_KEY }}
run: nix develop --no-warn-dirty --command scripts/setup_dagger_remote.sh
run: scripts/setup_dagger_remote.sh
- name: Generate build history and deploy website
continue-on-error: true
@@ -197,4 +150,4 @@ jobs:
SSH_USER: ${{ secrets.SSH_USER }}
SSH_HOST: ${{ secrets.SSH_HOST }}
run: |
nix develop --no-warn-dirty --command dagger call --progress=plain -m ci publish-website --source . --ssh-key env:SSH_PRIVATE_KEY --ssh-user "$SSH_USER" --ssh-host "$SSH_HOST"
dagger call --progress=plain -m ci publish-website --source . --ssh-key env:SSH_PRIVATE_KEY --ssh-user "$SSH_USER" --ssh-host "$SSH_HOST"
+7 -10
View File
@@ -19,14 +19,11 @@ jobs:
with:
submodules: recursive
- uses: cachix/install-nix-action@v27
with:
nix_path: nixpkgs=channel:nixos-25.11
- name: Enable Nix flakes
- name: Install Dagger & Task
run: |
mkdir -p ~/.config/nix
echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf
curl -L https://dl.dagger.io/dagger/install.sh | BIN_DIR=/usr/local/bin sh
curl -sL https://taskfile.dev/install.sh | sh -s -- -b /usr/local/bin
sudo apt-get update && sudo apt-get install -y stunnel4 netcat-openbsd
- name: Setup Dagger Remote Engine (via stunnel)
env:
@@ -35,7 +32,7 @@ jobs:
DAGGER_CA_CERT: ${{ secrets.DAGGER_CA_CERT }}
DAGGER_CLIENT_CERT: ${{ secrets.DAGGER_CLIENT_CERT }}
DAGGER_CLIENT_KEY: ${{ secrets.DAGGER_CLIENT_KEY }}
run: nix develop --no-warn-dirty --command scripts/setup_dagger_remote.sh
run: scripts/setup_dagger_remote.sh
- name: Build & Deploy Website
env:
@@ -43,9 +40,9 @@ jobs:
SSH_USER: ${{ secrets.WEBSITE_SSH_USER }}
SSH_HOST: ${{ secrets.WEBSITE_SSH_HOST }}
run: |
nix develop --no-warn-dirty --command dagger call --progress=plain -m ci publish-website --source . --ssh-key env:SSH_PRIVATE_KEY --ssh-user "$SSH_USER" --ssh-host "$SSH_HOST"
dagger call --progress=plain -m ci publish-website --source . --ssh-key env:SSH_PRIVATE_KEY --ssh-user "$SSH_USER" --ssh-host "$SSH_HOST"
- name: Verify Website
env:
SSH_HOST: ${{ secrets.WEBSITE_SSH_HOST }}
run: nix develop --no-warn-dirty --command scripts/website-verify.sh
run: scripts/website-verify.sh
+38 -8
View File
@@ -36,10 +36,6 @@ func (m *Ci) Base(source *dagger.Directory) *dagger.Container {
"clang", "cmake", "ninja-build", "pkg-config",
"libgtk-3-dev", "liblzma-dev", "libsecret-1-dev",
"libgcrypt20-dev", "libjsoncpp-dev", "sqlite3", "curl", "python3", "iproute2"}).
WithExec([]string{"curl", "-sL", "https://github.com/stalwartlabs/mail-server/releases/download/v0.14.1/stalwart-x86_64-unknown-linux-gnu.tar.gz", "-o", "/tmp/stalwart.tar.gz"}).
WithExec([]string{"tar", "-xzf", "/tmp/stalwart.tar.gz", "-C", "/usr/local/bin", "stalwart"}).
WithExec([]string{"chmod", "+x", "/usr/local/bin/stalwart"}).
WithExec([]string{"rm", "/tmp/stalwart.tar.gz"}).
WithMountedCache("/root/.pub-cache", dag.CacheVolume("flutter-pub-cache")).
WithMountedCache("/root/.gradle", dag.CacheVolume("gradle-cache")).
WithEnvVariable("PUB_CACHE", "/root/.pub-cache").
@@ -66,6 +62,23 @@ func (m *Ci) Deployer(sshKey *dagger.Secret) *dagger.Container {
WithEnvVariable("RSYNC_RSH", "ssh -o StrictHostKeyChecking=no -i /root/.ssh/id_ed25519")
}
// Latest Stalwart Mail Server as a Dagger Service
func (m *Ci) Stalwart(source *dagger.Directory) *dagger.Service {
config := source.Directory("stalwart-dev").File("config.toml")
return dag.Container().
From("stalwartlabs/stalwart:latest").
WithFile("/etc/stalwart/config.toml", config).
// Create data dir in /tmp where permissions are usually more relaxed.
// Note: The Stalwart image might run as a non-root user.
WithExec([]string{"/bin/sh", "-c", "mkdir -p /tmp/stalwart && chmod 777 /tmp/stalwart"}).
WithExposedPort(8080). // JMAP
WithExposedPort(1430). // IMAP
WithExposedPort(1025). // SMTP
WithExposedPort(4190). // ManageSieve
AsService()
}
// Setup environment: pub get and build_runner
func (m *Ci) Setup(source *dagger.Directory) *dagger.Container {
return m.Base(source).
@@ -145,8 +158,25 @@ func (m *Ci) Check(ctx context.Context, source *dagger.Directory) (string, error
return coverage, err
}
// Run backend tests (requires Stalwart)
testBackend, err := setup.WithExec([]string{"stalwart-dev/test.sh"}).Stdout(ctx)
// Run backend tests (requires Stalwart Service)
stalwart := m.Stalwart(source)
testBackend, err := setup.
WithServiceBinding("stalwart", stalwart).
WithEnvVariable("STALWART_IMAP_HOST", "stalwart").
WithEnvVariable("STALWART_SMTP_HOST", "stalwart").
WithEnvVariable("STALWART_URL", "http://stalwart:8080").
WithEnvVariable("STALWART_IMAP_PORT", "1430").
WithEnvVariable("STALWART_SMTP_PORT", "1025").
WithEnvVariable("STALWART_SIEVE_PORT", "4190").
WithEnvVariable("STALWART_USER_B", "alice@example.com").
WithEnvVariable("STALWART_PASS_B", "secret").
// USER_C/PASS_C needed for multi-account tests
WithEnvVariable("STALWART_USER_C", "bob@example.com").
WithEnvVariable("STALWART_PASS_C", "secret").
// We can't use stalwart-dev/test.sh directly because it tries to START stalwart.
// We just run the tests against the bound service.
WithExec([]string{"flutter", "test", "test/backend"}).
Stdout(ctx)
if err != nil {
return testBackend, err
}
@@ -225,8 +255,8 @@ func (m *Ci) PublishWebsite(
// Build and return the Linux bundle
func (m *Ci) BuildLinux(source *dagger.Directory) *dagger.Directory {
return m.Setup(source).
WithExec([]string{"flutter", "build", "linux", "--debug"}).
Directory("build/linux/x64/debug/bundle")
WithExec([]string{"flutter", "build", "linux", "--release"}).
Directory("build/linux/x64/release/bundle")
}
// Build and return the Linux bundle (release)
+5 -10
View File
@@ -1,10 +1,5 @@
# Minimal Stalwart Mail configuration for local development and integration tests.
#
# Do not start directly — use stalwart-dev/start, which substitutes $STALWART_PORT
# and writes a per-clone config into /tmp/stalwart-dev-PORT/ before starting.
#
# Check: curl http://localhost:$STALWART_PORT/.well-known/jmap
#
# HTTP only — localhost testing, no TLS.
# Two test accounts (alice, bob) for multi-account sync tests.
@@ -13,27 +8,27 @@ hostname = "localhost"
[[server.listener]]
id = "jmap"
bind = ["127.0.0.1:8080"]
bind = ["0.0.0.0:8080"]
protocol = "http"
[[server.listener]]
id = "imap"
bind = ["127.0.0.1:1430"]
bind = ["0.0.0.0:1430"]
protocol = "imap"
[[server.listener]]
id = "smtp"
bind = ["127.0.0.1:1025"]
bind = ["0.0.0.0:1025"]
protocol = "smtp"
[[server.listener]]
id = "managesieve"
bind = ["127.0.0.1:4190"]
bind = ["0.0.0.0:4190"]
protocol = "managesieve"
[store."db"]
type = "sqlite"
path = "/tmp/stalwart-dev/data.sqlite"
path = "/tmp/stalwart/data.sqlite"
[storage]
data = "db"