Skip to content
Open
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
33 changes: 23 additions & 10 deletions lib/hanami/cli/commands/gem/new.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

require "dry/inflector"
require_relative "../../errors"
require_relative "../../formatter"

module Hanami
module CLI
Expand Down Expand Up @@ -157,31 +158,43 @@ def call(
skip_view: skip_view,
database: normalized_database
)
out.puts Formatter.header("Setting up #{app}...", out: out)

generator.call(app, context: context) do
if skip_install
out.puts "Skipping installation, please enter `#{app}' directory and run `bundle exec hanami install'"
out.puts ""
out.puts Formatter.info("Skipping installation", out: out)
out.puts Formatter.dim(" To complete setup, run: cd #{app} && bundle exec hanami install", out: out)
else
out.puts "Running bundle install..."
out.puts ""
out.puts Formatter.info("Installing dependencies...", out: out)
bundler.install!

unless skip_assets
out.puts "Running npm install..."
out.puts Formatter.info("Installing npm packages...", out: out)
system_call.call("npm", ["install"]).tap do |result|
unless result.successful?
puts "NPM ERROR:"
puts(result.err.lines.map { |line| line.prepend(" ") })
out.puts Formatter.error("NPM installation failed:", out: out)
out.puts(result.err.lines.map { |line| Formatter.dim(" #{line}", out: out) })
end
end
end

out.puts "Running hanami install..."
out.puts Formatter.info("Running hanami install...", out: out)
run_install_command!(head: head)

out.puts "Running bundle binstubs hanami-cli rake..."
out.puts Formatter.info("Running bundle binstubs hanami-cli rake...", out: out)
install_binstubs!

out.puts "Initializing git repository..."
out.puts Formatter.info("Initializing git repository...", out: out)
init_git_repository

out.puts ""
out.puts Formatter.success("Successfully created #{app}!", out: out)
out.puts ""
out.puts Formatter.dim("Next steps:", out: out)
out.puts Formatter.dim(" cd #{app}", out: out)
out.puts Formatter.dim(" bundle exec hanami dev", out: out)
end
end
end
Expand Down Expand Up @@ -227,8 +240,8 @@ def install_binstubs!
def init_git_repository
system_call.call("git", ["init"]).tap do |result|
unless result.successful?
out.puts "WARNING: Failed to initialize git repository"
out.puts(result.err.lines.map { |line| line.prepend(" ") })
out.puts Formatter.warning("Failed to initialize git repository", out: out)
out.puts(result.err.lines.map { |line| Formatter.dim(" #{line}", out: out) })
end
end
end
Expand Down
13 changes: 9 additions & 4 deletions lib/hanami/cli/files.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require "dry/files"
require_relative "formatter"

module Hanami
module CLI
Expand Down Expand Up @@ -43,7 +44,7 @@ def mkdir(path)
return if exist?(path)

super
created(dir_path(path))
created_directory(dir_path(path))
end

# @since 2.0.0
Expand Down Expand Up @@ -83,15 +84,19 @@ def delete_keepfiles(path)
end

def updated(path)
out.puts "Updated #{path}"
out.puts Formatter.updated(path, out: out)
end

def created(path)
out.puts "Created #{path}"
out.puts Formatter.created(path, out: out)
end

def created_directory(path)
out.puts Formatter.created_directory(path, out: out)
end

def within_folder(path)
out.puts "-> Within #{dir_path(path)}"
out.puts Formatter.dim("-> Entering `#{path}/` directory...", out: out)
end

def dir_path(path)
Expand Down
163 changes: 163 additions & 0 deletions lib/hanami/cli/formatter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
# frozen_string_literal: true

module Hanami
module CLI
# Provides formatting utilities for CLI output including colors and icons
#
# There is significant overlap with Hanami-Utils ShellColor module, but hasn't been merged together yet.
#
# @api private
# @since 2.3.0
module Formatter
# ANSI color codes
COLORS = {
reset: "\e[0m",
bold: "\e[1m",
green: "\e[32m",
blue: "\e[34m",
cyan: "\e[36m",
yellow: "\e[33m",
red: "\e[31m",
gray: "\e[90m"
}.freeze

# Icons for different operations
ICONS = {
create: "✓",
update: "↻",
info: "→",
warning: "⚠",
error: "✗",
success: "✓"
}.freeze

module_function

# Wraps text in color codes
#
# @param text [String] the text to colorize
# @param color [Symbol] the color name from COLORS
# @param out [IO] the output stream to check for TTY (defaults to $stdout)
# @return [String] colorized text
#
# @api private
def colorize(text, color, out: $stdout)
return text unless out.tty?

"#{COLORS[color]}#{text}#{COLORS[:reset]}"
end

# Formats a create message
#
# @param path [String] the path that was created
# @param out [IO] the output stream to check for TTY (defaults to $stdout)
# @return [String] formatted message
#
# @api private
def created(path, out: $stdout)
icon = colorize(ICONS[:create], :green, out: out)
label = colorize("create", :green, out: out)
" #{icon} #{label} #{path}"
end

# Formats a create directory message
#
# @param path [String] the directory path that was created
# @param out [IO] the output stream to check for TTY (defaults to $stdout)
# @return [String] formatted message
#
# @api private
def created_directory(path, out: $stdout)
icon = colorize(ICONS[:create], :green, out: out)
label = colorize("create directory", :green, out: out)
"#{icon} #{label} #{path}"
end

# Formats an update message
#
# @param path [String] the path that was updated
# @param out [IO] the output stream to check for TTY (defaults to $stdout)
# @return [String] formatted message
#
# @api private
def updated(path, out: $stdout)
icon = colorize(ICONS[:update], :cyan, out: out)
label = colorize("update", :cyan, out: out)
" #{icon} #{label} #{path}"
end

# Formats an info message
#
# @param text [String] the message text
# @param out [IO] the output stream to check for TTY (defaults to $stdout)
# @return [String] formatted message
#
# @api private
def info(text, out: $stdout)
icon = colorize(ICONS[:info], :blue, out: out)
"#{icon} #{text}"
end

# Formats a success message
#
# @param text [String] the message text
# @param out [IO] the output stream to check for TTY (defaults to $stdout)
# @return [String] formatted message
#
# @api private
def success(text, out: $stdout)
icon = colorize(ICONS[:success], :green, out: out)
label = colorize("✓", :green, out: out)
"#{label} #{colorize(text, :green, out: out)}"
end

# Formats a warning message
#
# @param text [String] the message text
# @param out [IO] the output stream to check for TTY (defaults to $stdout)
# @return [String] formatted message
#
# @api private
def warning(text, out: $stdout)
icon = colorize(ICONS[:warning], :yellow, out: out)
label = colorize("warning", :yellow, out: out)
"#{icon} #{label} #{text}"
end

# Formats an error message
#
# @param text [String] the message text
# @param out [IO] the output stream to check for TTY (defaults to $stdout)
# @return [String] formatted message
#
# @api private
def error(text, out: $stdout)
icon = colorize(ICONS[:error], :red, out: out)
label = colorize("error", :red, out: out)
"#{icon} #{label} #{text}"
end

# Formats a section header
#
# @param text [String] the header text
# @param out [IO] the output stream to check for TTY (defaults to $stdout)
# @return [String] formatted header
#
# @api private
def header(text, out: $stdout)
"\n#{colorize(text, :bold, out: out)}"
end

# Formats a dim/secondary text
#
# @param text [String] the text to dim
# @param out [IO] the output stream to check for TTY (defaults to $stdout)
# @return [String] formatted text
#
# @api private
def dim(text, out: $stdout)
text # No special dim color, just return plain text for now
end
end
end
end
Loading