Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions lib/cleat/commands/init.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion lib/cleat/runtime.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand All @@ -25,6 +25,9 @@ defmodule Cleat.Runtime do
file?(dir, "mix.exs") ->
"phoenix"

file?(dir, "Cargo.toml") ->
"rust"

rails?(dir) ->
"rails"

Expand Down
19 changes: 19 additions & 0 deletions test/cleat/commands/init_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
21 changes: 21 additions & 0 deletions test/cleat/runtime_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -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"}))

Expand Down
Loading