Skip to content

Commit

Permalink
Add pipelines command (#550)
Browse files Browse the repository at this point in the history
* Add pipelines command

* Add --no-plugs option for pipelines

* Add error handling in case of malformed routes file

* Add spec for ensuring the order of pipelines

* Implement pipeline with extended regex

* Remove 's in comments to fix highlighting
  • Loading branch information
NeverHappened authored and drujensen committed Feb 1, 2018
1 parent 944d730 commit 7e96132
Show file tree
Hide file tree
Showing 5 changed files with 224 additions and 5 deletions.
88 changes: 88 additions & 0 deletions spec/amber/cli/commands/pipelines/pipelines_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
require "../../../../spec_helper"
require "../../../../support/helpers/cli_helper"

require "cli/spec"

include CLIHelper
include Cli::Spec::Helper

module Amber::CLI
extend Helpers

describe "amber pipelines" do
begin
ENV["CRYSTAL_CLI_ENV"] = "test"

context "in an `amber new` with default options" do
cleanup
scaffold_app(TESTING_APP)
output = ""

pipeline_names = %w(web static)

web_default_plugs = %w(
Amber::Pipe::PoweredByAmber
Amber::Pipe::Error
Amber::Pipe::Logger
Amber::Pipe::Session
Amber::Pipe::Flash
Amber::Pipe::CSRF
Amber::Pipe::Reload
)

static_default_plugs = %w(
Amber::Pipe::PoweredByAmber
Amber::Pipe::Error
Amber::Pipe::Static
)

pipe_plugs = {
"web" => web_default_plugs,
"static" => static_default_plugs,
}

describe "with the default routes" do
it "runs without an error" do
MainCommand.run %w(pipelines) { |cmd| output = cmd.out.gets_to_end }
output.should_not contain "Good bye :("
end

MainCommand.run %w(pipelines) { |cmd| output = cmd.out.gets_to_end }
output_lines = route_table_rows(output)

it "outputs the correct headers" do
headers = %w(Pipe Plug)
headers.each do |header|
output.should contain header
end
end

it "outputs the default pipeline names" do
pipeline_names.each do |pipeline|
output.should contain pipeline
end
end

it "outputs the plugs for the pipelines" do
(web_default_plugs + static_default_plugs).each do |plug|
output.should contain plug
end
end

it "saves the order of the plugs in the pipeline" do
pipe_plugs.each do |pipe_name, plugs|
output_plugs = output_lines.select { |line| line.includes?(pipe_name) }
plugs.each_with_index do |plug, index|
output_plug = output_plugs[index]
(output_plug != nil).should be_true
output_plug.should contain plug
end
end
end
end
end
ensure
cleanup
end
end
end
1 change: 0 additions & 1 deletion spec/amber/router/pipe/cors_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ module Amber
module Pipe
describe CORS do
context "allowed headers" do

# Pipeline with default settings
pipeline = Pipeline.new
pipeline.build :cors do
Expand Down
132 changes: 132 additions & 0 deletions src/amber/cli/commands/pipelines.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
require "cli"
require "shell-table"
require "../helpers/sentry"

module Amber::CLI
class MainCommand < ::Cli::Supercommand
class Pipelines < Command
getter result = Array(NamedTuple(pipes: Array(String), plugs: Array(String))).new
property current_pipe : String?

class Options
bool "--no-color", desc: "Disable colored output", default: false
bool "--no-plugs", desc: "Don't output the plugs", default: false
help
end

class BadRoutesException < Exception
end

ROUTES_PATH = "config/routes.cr"
LABELS = %w(Pipe Plug)
LABELS_WITHOUT_PLUGS = %w(Pipe)

PIPELINE_REGEX =
/^
\s*
pipeline # match pipeline
\s+ # require at least one whitespace character after pipeline
(
(?:
(?:
\:(?:\w+)
|
\"(?:\w+)\"
)
(?:\,\s*)?
)+
) # match and capture all contiguous words
/x
PLUG_REGEX =
/^
\s*
plug # match plug
\s+ # require at least one whitespace character after plug
(
[\w:]+ # match at least one words with maybe a colon
)?
(?:
[\.\s*\(] # until we reach ., spaces, or braces
)?
/x
FAILED_TO_PARSE_ERROR = "Could not parse pipeline/plugs in #{ROUTES_PATH}"

command_name "pipelines"

def run
parse_routes
print_pipelines
rescue ex : BadRoutesException
CLI.logger.error(ex.message.colorize(:red))
CLI.logger.error "Good bye :("
exit 1
rescue ex
CLI.logger.error "Error: Not valid project root directory.".colorize(:red)
CLI.logger.error "Run `amber pipelines` in project root directory.".colorize(:light_blue)
CLI.logger.error "Good bye :("
exit 1
end

private def parse_routes
lines = File.read_lines(ROUTES_PATH)

lines.map(&.strip).each do |line|
case line
when .starts_with?("pipeline") then set_pipe(line)
when .starts_with?("plug") then set_plug(line)
end
end
end

private def set_pipe(line)
match = line.match(PIPELINE_REGEX)

if match && (pipes = match[1])
pipes = pipes.split(/,\s*/).map { |s| s.gsub(/[:\"]/, "") }
result << {pipes: pipes, plugs: [] of String}
else
raise BadRoutesException.new(FAILED_TO_PARSE_ERROR)
end
end

private def set_plug(line)
match = line.match(PLUG_REGEX)

if match && (plug = match[1]) && result.last
result.last[:plugs] << plug
else
raise BadRoutesException.new(FAILED_TO_PARSE_ERROR)
end
end

private def print_pipelines
table = ShellTable.new

table.labels = options.no_plugs? ? LABELS_WITHOUT_PLUGS : LABELS
table.label_color = :light_red unless options.no_color?
table.border_color = :dark_gray unless options.no_color?

if options.no_plugs?
result.map { |pipes_and_plugs| pipes_and_plugs[:pipes] }.flatten.uniq.each do |pipe|
row = table.add_row
row.add_column(pipe)
end
else
result.each do |pipes_and_plugs|
pipes_and_plugs[:pipes].each do |pipe|
pipes_and_plugs[:plugs].each do |plug|
row = table.add_row
row.add_column(pipe)
row.add_column(plug) unless options.no_plugs?
end
end
end
end

puts "\n", table
end
end
end
end
7 changes: 4 additions & 3 deletions src/amber/pipes/cors.cr
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,17 @@ module Amber
@allow_methods = ALLOW_METHODS,
@allow_headers = ALLOW_HEADERS,
@allow_credentials = false,
@max_age = 0)
@max_age = 0
)
end

def initialize(
@allow_origin = "*",
allow_methods : String = ALLOW_METHODS.join(", "),
allow_headers : String = ALLOW_HEADERS.join(", "),
@allow_credentials = false,
@max_age = 0)

@max_age = 0
)
@allow_methods = allow_methods.strip.split /[\s,]+/
@allow_headers = allow_headers.strip.split /[\s,]+/
end
Expand Down
1 change: 0 additions & 1 deletion src/amber/pipes/powered_by_amber.cr
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
module Amber
module Pipe
class PoweredByAmber < Base

def call(context : HTTP::Server::Context)
context.response.headers["X-Powered-By"] = "Amber"
call_next(context)
Expand Down

0 comments on commit 7e96132

Please sign in to comment.