version: '3' tasks: go:mod:tidy: summary: Runs `go mod tidy` internal: true cmds: - go mod tidy install:frontend:deps: summary: Install frontend dependencies dir: frontend sources: - package.json - pnpm-lock.yaml generates: - node_modules preconditions: - sh: pnpm --version msg: "Looks like pnpm isn't installed. Install with: corepack enable && corepack prepare pnpm@latest --activate" cmds: - pnpm install build:frontend: label: build:frontend (DEV={{.DEV}}) summary: Build the frontend project dir: frontend sources: - "**/*" - exclude: node_modules/**/* generates: - dist/**/* deps: - task: install:frontend:deps - task: generate:bindings vars: BUILD_FLAGS: ref: .BUILD_FLAGS cmds: - pnpm run {{.BUILD_COMMAND}} env: PRODUCTION: '{{if eq .DEV "true"}}false{{else}}true{{end}}' vars: BUILD_COMMAND: '{{if eq .DEV "true"}}build:dev{{else}}build{{end}}' frontend:vendor:puppertino: summary: Fetches Puppertino CSS into frontend/public for consistent mobile styling sources: - frontend/public/puppertino/puppertino.css generates: - frontend/public/puppertino/puppertino.css cmds: - | set -euo pipefail mkdir -p frontend/public/puppertino # If bundled Puppertino exists, prefer it. Otherwise, try to fetch, but don't fail build on error. if [ ! -f frontend/public/puppertino/puppertino.css ]; then echo "No bundled Puppertino found. Attempting to fetch from GitHub..." if curl -fsSL https://raw.githubusercontent.com/codedgar/Puppertino/main/dist/css/full.css -o frontend/public/puppertino/puppertino.css; then curl -fsSL https://raw.githubusercontent.com/codedgar/Puppertino/main/LICENSE -o frontend/public/puppertino/LICENSE || true echo "Puppertino CSS downloaded to frontend/public/puppertino/puppertino.css" else echo "Warning: Could not fetch Puppertino CSS. Proceeding without download since template may bundle it." fi else echo "Using bundled Puppertino at frontend/public/puppertino/puppertino.css" fi # Ensure index.html includes Puppertino CSS and button classes INDEX_HTML=frontend/index.html if [ -f "$INDEX_HTML" ]; then if ! grep -q 'href="/puppertino/puppertino.css"' "$INDEX_HTML"; then # Insert Puppertino link tag after style.css link awk ' /href="\/style.css"\/?/ && !x { print; print " "; x=1; next }1 ' "$INDEX_HTML" > "$INDEX_HTML.tmp" && mv "$INDEX_HTML.tmp" "$INDEX_HTML" fi # Replace default .btn with Puppertino primary button classes if present sed -E -i'' 's/class=\"btn\"/class=\"p-btn p-prim-col\"/g' "$INDEX_HTML" || true fi generate:bindings: label: generate:bindings (BUILD_FLAGS={{.BUILD_FLAGS}}) summary: Generates bindings for the frontend deps: - task: go:mod:tidy sources: - "**/*.[jt]s" - exclude: frontend/**/* - frontend/bindings/**/* # Rerun when switching between dev/production mode causes changes in output - "**/*.go" - go.mod - go.sum generates: - frontend/bindings/**/* cmds: - wails3 generate bindings -f '{{.BUILD_FLAGS}}' -clean=true -ts generate:icons: summary: Generates Windows `.ico` and Mac `.icns` from an image; on macOS, `-iconcomposerinput appicon.icon -macassetdir darwin` also produces `Assets.car` from a `.icon` file (skipped on other platforms). dir: build sources: - "appicon.png" - "appicon.icon" generates: - "darwin/icons.icns" - "windows/icon.ico" cmds: - wails3 generate icons -input appicon.png -macfilename darwin/icons.icns -windowsfilename windows/icon.ico -iconcomposerinput appicon.icon -macassetdir darwin generate:tray:icons: summary: Rebuild Windows multi-res .ico files from the per-state PNGs. desc: | The colored tray PNGs (assets/netbird-systemtray-.png) and the macOS template variants are committed to the repo as the canonical source. This task only regenerates the Windows multi-resolution .ico files from those PNGs by downscaling each to 16/24/32/48 px and packing them with icotool, so Shell_NotifyIcon picks the frame matching the user's DPI instead of downscaling a single large PNG. Run after replacing any of the colored PNGs (e.g. when copying a new version of the icons from client/ui/assets). The SVG sources in assets/svg/ are kept for reference but are not built by default. dir: assets sources: - "netbird-systemtray-connected.png" - "netbird-systemtray-disconnected.png" - "netbird-systemtray-connecting.png" - "netbird-systemtray-error.png" - "netbird-systemtray-update-connected.png" - "netbird-systemtray-update-disconnected.png" generates: - "netbird-systemtray-*.ico" preconditions: - sh: command -v magick >/dev/null 2>&1 || command -v convert >/dev/null 2>&1 msg: "ImageMagick is required to downscale PNGs (apt install imagemagick)" - sh: command -v icotool >/dev/null 2>&1 msg: "icotool is required to pack tray .ico files (apt install icoutils)" cmds: - | set -euo pipefail tmp=$(mktemp -d) trap 'rm -rf "$tmp"' EXIT resize=$(command -v magick || echo convert) for state in connected disconnected connecting error update-connected update-disconnected; do for sz in 16 24 32 48; do "$resize" "netbird-systemtray-$state.png" -resize ${sz}x${sz} "$tmp/$state-$sz.png" done icotool -c -o "netbird-systemtray-$state.ico" \ "$tmp/$state-16.png" "$tmp/$state-24.png" "$tmp/$state-32.png" "$tmp/$state-48.png" done dev:frontend: summary: Runs the frontend in development mode dir: frontend deps: - task: install:frontend:deps cmds: - pnpm exec vite --port {{.VITE_PORT}} --strictPort update:build-assets: summary: Updates the build assets dir: build cmds: - wails3 update build-assets -name "{{.APP_NAME}}" -binaryname "{{.APP_NAME}}" -config config.yml -dir . build:server: summary: Builds the application in server mode (no GUI, HTTP server only) desc: | Builds the application with the server build tag enabled. Server mode runs as a pure HTTP server without native GUI dependencies. Usage: task build:server deps: - task: build:frontend vars: BUILD_FLAGS: ref: .BUILD_FLAGS cmds: - go build -tags server {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}}-server{{exeExt}} vars: BUILD_FLAGS: "{{.BUILD_FLAGS}}" run:server: summary: Builds and runs the application in server mode deps: - task: build:server cmds: - ./{{.BIN_DIR}}/{{.APP_NAME}}-server{{exeExt}} build:docker: summary: Builds a Docker image for server mode deployment desc: | Creates a minimal Docker image containing the server mode binary. The image is based on distroless for security and small size. Usage: task build:docker [TAG=myapp:latest] cmds: - docker build -t {{.TAG | default (printf "%s:latest" .APP_NAME)}} -f build/docker/Dockerfile.server . vars: TAG: "{{.TAG}}" preconditions: - sh: docker info > /dev/null 2>&1 msg: "Docker is required. Please install Docker first." - sh: test -f build/docker/Dockerfile.server msg: "Dockerfile.server not found. Run 'wails3 update build-assets' to generate it." run:docker: summary: Builds and runs the Docker image desc: | Builds the Docker image and runs it, exposing port 8080. Usage: task run:docker [TAG=myapp:latest] [PORT=8080] Note: The internal container port is always 8080. The PORT variable only changes the host port mapping. Ensure your app uses port 8080 or modify the Dockerfile to match your ServerOptions.Port setting. deps: - task: build:docker vars: TAG: ref: .TAG cmds: - docker run --rm -p {{.PORT | default "8080"}}:8080 {{.TAG | default (printf "%s:latest" .APP_NAME)}} vars: TAG: "{{.TAG}}" PORT: "{{.PORT}}" setup:docker: summary: Builds Docker image for cross-compilation (~800MB download) desc: | Builds the Docker image needed for cross-compiling to any platform. Run this once to enable cross-platform builds from any OS. cmds: - docker build -t wails-cross -f build/docker/Dockerfile.cross build/docker/ preconditions: - sh: docker info > /dev/null 2>&1 msg: "Docker is required. Please install Docker first." ios:device:list: summary: Lists connected iOS devices (UDIDs) cmds: - xcrun xcdevice list ios:run:device: summary: Build, install, and launch on a physical iPhone using Apple tools (xcodebuild/devicectl) vars: PROJECT: '{{.PROJECT}}' # e.g., build/ios/xcode/.xcodeproj SCHEME: '{{.SCHEME}}' # e.g., ios.dev CONFIG: '{{.CONFIG | default "Debug"}}' DERIVED: '{{.DERIVED | default "build/ios/DerivedData"}}' UDID: '{{.UDID}}' # from `task ios:device:list` BUNDLE_ID: '{{.BUNDLE_ID}}' # e.g., com.yourco.wails.ios.dev TEAM_ID: '{{.TEAM_ID}}' # optional, if your project is not already set up for signing preconditions: - sh: xcrun -f xcodebuild msg: "xcodebuild not found. Please install Xcode." - sh: xcrun -f devicectl msg: "devicectl not found. Please update to Xcode 15+ (which includes devicectl)." - sh: test -n '{{.PROJECT}}' msg: "Set PROJECT to your .xcodeproj path (e.g., PROJECT=build/ios/xcode/App.xcodeproj)." - sh: test -n '{{.SCHEME}}' msg: "Set SCHEME to your app scheme (e.g., SCHEME=ios.dev)." - sh: test -n '{{.UDID}}' msg: "Set UDID to your device UDID (see: task ios:device:list)." - sh: test -n '{{.BUNDLE_ID}}' msg: "Set BUNDLE_ID to your app's bundle identifier (e.g., com.yourco.wails.ios.dev)." cmds: - | set -euo pipefail echo "Building for device: UDID={{.UDID}} SCHEME={{.SCHEME}} PROJECT={{.PROJECT}}" XCB_ARGS=( -project "{{.PROJECT}}" -scheme "{{.SCHEME}}" -configuration "{{.CONFIG}}" -destination "id={{.UDID}}" -derivedDataPath "{{.DERIVED}}" -allowProvisioningUpdates -allowProvisioningDeviceRegistration ) # Optionally inject signing identifiers if provided if [ -n '{{.TEAM_ID}}' ]; then XCB_ARGS+=(DEVELOPMENT_TEAM={{.TEAM_ID}}); fi if [ -n '{{.BUNDLE_ID}}' ]; then XCB_ARGS+=(PRODUCT_BUNDLE_IDENTIFIER={{.BUNDLE_ID}}); fi xcodebuild "${XCB_ARGS[@]}" build | xcpretty || true # If xcpretty isn't installed, run without it if [ "${PIPESTATUS[0]}" -ne 0 ]; then xcodebuild "${XCB_ARGS[@]}" build fi # Find built .app APP_PATH=$(find "{{.DERIVED}}/Build/Products" -type d -name "*.app" -maxdepth 3 | head -n 1) if [ -z "$APP_PATH" ]; then echo "Could not locate built .app under {{.DERIVED}}/Build/Products" >&2 exit 1 fi echo "Installing: $APP_PATH" xcrun devicectl device install app --device "{{.UDID}}" "$APP_PATH" echo "Launching: {{.BUNDLE_ID}}" xcrun devicectl device process launch --device "{{.UDID}}" --stderr console --stdout console "{{.BUNDLE_ID}}"