From c9a0f8501fdf186f7368732dd41e6a19caf49188 Mon Sep 17 00:00:00 2001 From: puppe1990 Date: Thu, 24 Sep 2026 12:36:24 -0300 Subject: [PATCH] feat(runtime): detect Cargo.toml as rust cleat init and app registration pick rust for Loco/Cargo projects so the panel builds them instead of defaulting to phoenix. --- README.md | 20 +++++++++++++++++--- lib/cleat/commands/init.ex | 1 + lib/cleat/runtime.ex | 5 ++++- test/cleat/commands/init_test.exs | 19 +++++++++++++++++++ test/cleat/runtime_test.exs | 21 +++++++++++++++++++++ 5 files changed, 62 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b1b7d24..1b6743f 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ `cleat` is the command-line client for [Cleat](https://github.com/cleat-cloud/cleat-deploy), a self-hosted PaaS that deploys Phoenix/Elixir, Go, Node (Next.js / TanStack -Start), Ruby on Rails and static apps to Hetzner Cloud and AWS Lightsail over -SSH. +Start), Ruby on Rails, Rust (Loco) and static apps to Hetzner Cloud and AWS +Lightsail over SSH. It talks to the panel's JSON API (`/api/v1`) to list servers and apps, manage env vars, trigger deploys, and watch build and runtime logs. @@ -175,6 +175,20 @@ Ruby version resolution order: `ruby_version` → `.ruby-version` → the Gemfil `ruby` directive → 3.3.6. Start command: `start_command` → `bundle exec puma -C config/puma.rb` → `bundle exec puma -b tcp://0.0.0.0:$PORT`. +For Rust / Loco, `cleat init` detects a `Cargo.toml` and picks the `rust` +runtime. The panel installs rustup, runs `cargo build --release`, publishes +`bin/server` plus `config/`/`assets/`/`frontend/`, and starts a systemd unit. +Loco apps (`loco-rs` or `config/production.yaml`) use `./bin/server start` and +`./bin/server db migrate`. Set `DATABASE_URL` and `JWT_SECRET` as panel env +vars. + +```json +{ + "runtime": "rust", + "start_command": "./bin/server start" +} +``` + Commit the manifest so the panel picks it up on the next deploy. ### Logs @@ -222,7 +236,7 @@ Register and deploy in one shot. If the repo is unknown, pass `--server` and `--host`; the app is created with sane defaults (slug from the repo name). The runtime is detected from the local project the same way `cleat init` does, so a Next.js / TanStack Start repo registers as `node`; override it with `--runtime` -(`phoenix`, `golang`, `node`, `rails` or `static`): +(`phoenix`, `golang`, `node`, `rails`, `rust` or `static`): ```bash cleat deploy --repo owner/repo --server 3 --host repo.example.com --watch diff --git a/lib/cleat/commands/init.ex b/lib/cleat/commands/init.ex index fa453ee..2d7b6be 100644 --- a/lib/cleat/commands/init.ex +++ b/lib/cleat/commands/init.ex @@ -63,6 +63,7 @@ defmodule Cleat.Commands.Init do defp default_release_name("static"), do: nil defp default_release_name("node"), do: nil defp default_release_name("rails"), do: nil + defp default_release_name("rust"), do: nil defp default_release_name("phoenix"), do: mix_app() defp mix_app do diff --git a/lib/cleat/runtime.ex b/lib/cleat/runtime.ex index 84c74f6..56aa3c9 100644 --- a/lib/cleat/runtime.ex +++ b/lib/cleat/runtime.ex @@ -7,7 +7,7 @@ defmodule Cleat.Runtime do `node` instead of silently defaulting to `phoenix`. """ - @runtimes ~w(phoenix golang static node rails) + @runtimes ~w(phoenix golang static node rails rust) @doc """ Detects the runtime for the current working directory, defaulting to `phoenix`. @@ -25,6 +25,9 @@ defmodule Cleat.Runtime do file?(dir, "mix.exs") -> "phoenix" + file?(dir, "Cargo.toml") -> + "rust" + rails?(dir) -> "rails" diff --git a/test/cleat/commands/init_test.exs b/test/cleat/commands/init_test.exs index b6e7402..107b053 100644 --- a/test/cleat/commands/init_test.exs +++ b/test/cleat/commands/init_test.exs @@ -114,6 +114,25 @@ defmodule Cleat.Commands.InitTest do assert read_manifest()["runtime"] == "node" end + test "detects a Loco project as rust" do + File.write!( + "Cargo.toml", + """ + [package] + name = "hello_loco" + version = "0.1.0" + + [dependencies] + loco-rs = "0.16" + """ + ) + + assert :ok = Init.run(%{}) + + manifest = read_manifest() + assert manifest["runtime"] == "rust" + end + test "detects a Rails project as rails" do File.write!("Gemfile", ~s(source "https://rubygems.org"\ngem "rails", "~> 7.1"\n)) File.mkdir_p!("config") diff --git a/test/cleat/runtime_test.exs b/test/cleat/runtime_test.exs index 627dbdd..001330a 100644 --- a/test/cleat/runtime_test.exs +++ b/test/cleat/runtime_test.exs @@ -59,6 +59,27 @@ defmodule Cleat.RuntimeTest do assert Runtime.detect() == "rails" end + test "detects a Loco / Cargo project as rust" do + File.write!( + "Cargo.toml", + """ + [package] + name = "hello_loco" + version = "0.1.0" + + [dependencies] + loco-rs = "0.16" + """ + ) + + assert Runtime.detect() == "rust" + end + + test "normalizes rust as a valid runtime" do + assert Runtime.normalize("rust") == "rust" + assert Runtime.normalize("RUST") == "rust" + end + test "detects a bare package.json as static" do File.write!("package.json", ~s({"name":"site"}))