Skip to content

Commit

Permalink
#131 - Add 'play' management command
Browse files Browse the repository at this point in the history
  • Loading branch information
ellmetha committed May 25, 2024
1 parent b6ad13e commit a631367
Show file tree
Hide file tree
Showing 5 changed files with 202 additions and 0 deletions.
19 changes: 19 additions & 0 deletions docs/docs/development/reference/management-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,25 @@ marten new project myblog --dir=./projects/myblog # Creates a "myblog" project i
marten new app auth # Creates an "auth" application repository structure
```

## `play`

**Usage:** `marten play [options]`

Start a Crystal playground server initialized for the current project and open it in the default browser.

### Options

* `-b HOST, --bind=HOST` - Binds the playground to the specified IP
* `-p PORT, --port=PORT` - Runs the playground on the specified port
* `--no-open` - Do not open the playground in the default browser

### Examples

```bash
marten play # Starts the Crystal playground using the default host/port and opens it in the browser
marten play --no-open # Starts the Crystal playground using the default host/port without opening it
```

## `resetmigrations`

**Usage:** `marten resetmigrations [options] [app_label]`
Expand Down
7 changes: 7 additions & 0 deletions spec/marten/cli/admin_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,13 @@ describe Marten::CLI::Admin do
output.includes?(Marten::CLI::Manage::Command::Serve.help).should be_true
end

it "supports running the Crystal playground by using the \"play\" management command" do
output = Marten::CLI::AdminSpec.run_inside_command(["play", "-h"])

output.includes?("Usage: marten play [options]").should be_true
output.includes?(Marten::CLI::Manage::Command::Play.help).should be_true
end

it "builds and runs the manage.cr CLI for other commands" do
output = Marten::CLI::AdminSpec.run_inside_command(["other"])

Expand Down
81 changes: 81 additions & 0 deletions spec/marten/cli/manage/command/play_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
require "./spec_helper"

describe Marten::CLI::Manage::Command::Play do
describe "#run" do
it "starts the Crystal playground as expected when no host/port are provided" do
stdout = IO::Memory.new
stderr = IO::Memory.new

command = Marten::CLI::Manage::Command::Play.new(
options: ["--no-open"],
stdout: stdout,
stderr: stderr
)

spawn { command.handle }

sleep 1

command.playground_process.try(&.terminate)

stdout.rewind.gets_to_end.includes?("Listening on http://127.0.0.1:8080").should be_true
end

it "starts the Crystal playground as expected when a host is provided" do
stdout = IO::Memory.new
stderr = IO::Memory.new

command = Marten::CLI::Manage::Command::Play.new(
options: ["--no-open", "--bind", "localhost"],
stdout: stdout,
stderr: stderr
)

spawn { command.handle }

sleep 1

command.playground_process.try(&.terminate)

stdout.rewind.gets_to_end.includes?("Listening on http://[::1]:8080").should be_true
end

it "starts the Crystal playground as expected when a port is provided" do
stdout = IO::Memory.new
stderr = IO::Memory.new

command = Marten::CLI::Manage::Command::Play.new(
options: ["--no-open", "--port", "3000"],
stdout: stdout,
stderr: stderr
)

spawn { command.handle }

sleep 1

command.playground_process.try(&.terminate)

stdout.rewind.gets_to_end.includes?("Listening on http://127.0.0.1:3000").should be_true
end

it "starts the Crystal playground as expected when a host and port are provided" do
stdout = IO::Memory.new
stderr = IO::Memory.new

command = Marten::CLI::Manage::Command::Play.new(
options: ["--no-open", "--bind", "localhost", "--port", "3000"],
stdout: stdout,
stderr: stderr
)

spawn { command.handle }

sleep 1

command.playground_process.try(&.terminate)

stdout.rewind.gets_to_end.includes?("Listening on http://[::1]:3000").should be_true
end
end
end
2 changes: 2 additions & 0 deletions src/marten/cli/admin.cr
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ module Marten
Manage::Command::New.new(options: options[1..], stdout: stdout, stderr: stderr).handle!
elsif command_invoked?(command, Manage::Command::Serve)
Manage::Command::Serve.new(options: options[1..], stdout: stdout, stderr: stderr).handle!
elsif command_invoked?(command, Manage::Command::Play)
Manage::Command::Play.new(options: options[1..], stdout: stdout, stderr: stderr).handle!
else
build_and_run_manage_command
end
Expand Down
93 changes: 93 additions & 0 deletions src/marten/cli/manage/command/play.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
module Marten
module CLI
class Manage
module Command
class Play < Base
@host : String?
@open : Bool = true
@playground_process : Process?
@port : Int32?

# :nodoc:
getter playground_process

help "Start a Crystal playground server initialized for the current project."

def setup
on_option_with_arg(
:b,
:bind,
arg: "host",
description: "Binds the playground to the specified IP"
) do |v|
@host = v
end

on_option_with_arg(
:p,
:port,
arg: "port",
description: "Runs the playground on the specified port"
) do |v|
@port = v.to_i
end

on_option(:"no-open", description: "Do not open the playground in the default browser") do
@open = false
end
end

def run
write_playground_source
@playground_process = Process.new(play_command, shell: true, output: stdout, error: stderr)
Process.run(open_command, shell: true) if open?
@playground_process.try(&.wait)
end

private PLAYGROUND_SOURCE_CONTENT = <<-CRYSTAL
require "./src/project"
# Setup the project.
Marten.setup
# Write your code here.
CRYSTAL

private PLAYGROUND_SOURCE_PATH = "tmp/project_playground.cr"

private getter host
private getter port

private getter? open

private def open_command
# Identify which 'open' command to use based on the OS based on flags
url = "http://#{host || "localhost"}:#{port || 8080}"

open_command = ""
{% if flag?(:linux) %}
open_command = "xdg-open #{url}" # Linux
{% elsif flag?(:win32) || flag?(:win64) %}
open_command = "start #{url}" # Windows
{% else %}
open_command = "open #{url}" # macOS
{% end %}
end

private def play_command
command = String.build do |s|
s << "crystal play"
s << " --binding #{host}" if host
s << " --port #{port}" if port
s << " #{PLAYGROUND_SOURCE_PATH}"
end
end

private def write_playground_source
File.write(PLAYGROUND_SOURCE_PATH, PLAYGROUND_SOURCE_CONTENT)
end
end
end
end
end
end

0 comments on commit a631367

Please sign in to comment.