fudge 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/fudge +9 -0
- data/lib/fudge.rb +16 -0
- data/lib/fudge/build.rb +31 -0
- data/lib/fudge/cli.rb +29 -0
- data/lib/fudge/description.rb +53 -0
- data/lib/fudge/exceptions.rb +31 -0
- data/lib/fudge/helpers.rb +5 -0
- data/lib/fudge/helpers/bundle_aware.rb +14 -0
- data/lib/fudge/parser.rb +12 -0
- data/lib/fudge/railtie.rb +17 -0
- data/lib/fudge/runner.rb +25 -0
- data/lib/fudge/task_dsl.rb +41 -0
- data/lib/fudge/tasks.rb +31 -0
- data/lib/fudge/tasks/clean_bundler_env.rb +24 -0
- data/lib/fudge/tasks/composite_task.rb +24 -0
- data/lib/fudge/tasks/each_directory.rb +34 -0
- data/lib/fudge/tasks/in_directory.rb +24 -0
- data/lib/fudge/tasks/rake.rb +19 -0
- data/lib/fudge/tasks/rspec.rb +29 -0
- data/lib/fudge/tasks/shell.rb +76 -0
- data/lib/fudge/tasks/task.rb +18 -0
- data/lib/fudge/tasks/yard.rb +29 -0
- data/lib/fudge/version.rb +3 -0
- data/lib/tasks/fudge.rake +7 -0
- data/spec/lib/fudge/build_spec.rb +5 -0
- data/spec/lib/fudge/cli_spec.rb +76 -0
- data/spec/lib/fudge/description_spec.rb +241 -0
- data/spec/lib/fudge/exceptions_spec.rb +36 -0
- data/spec/lib/fudge/parser_spec.rb +23 -0
- data/spec/lib/fudge/runner_spec.rb +25 -0
- data/spec/lib/fudge/tasks/bundler_spec.rb +39 -0
- data/spec/lib/fudge/tasks/composite_task_spec.rb +60 -0
- data/spec/lib/fudge/tasks/each_directory_spec.rb +57 -0
- data/spec/lib/fudge/tasks/in_directory_spec.rb +39 -0
- data/spec/lib/fudge/tasks/rake_spec.rb +18 -0
- data/spec/lib/fudge/tasks/rspec_spec.rb +36 -0
- data/spec/lib/fudge/tasks/shell_spec.rb +38 -0
- data/spec/lib/fudge/tasks/task_spec.rb +14 -0
- data/spec/lib/fudge/tasks/yard_spec.rb +25 -0
- data/spec/lib/fudge/tasks_spec.rb +33 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/support/dummy_task.rb +40 -0
- data/spec/support/matchers.rb +47 -0
- data/spec/support/tmpdir.rb +12 -0
- metadata +302 -0
data/bin/fudge
ADDED
data/lib/fudge.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rainbow'
|
2
|
+
require 'active_support/all'
|
3
|
+
|
4
|
+
require 'fudge/railtie' if defined?(Rails)
|
5
|
+
|
6
|
+
module Fudge
|
7
|
+
autoload :Build, 'fudge/build'
|
8
|
+
autoload :Cli, 'fudge/cli'
|
9
|
+
autoload :Description, 'fudge/description'
|
10
|
+
autoload :Exceptions, 'fudge/exceptions'
|
11
|
+
autoload :Helpers, 'fudge/helpers'
|
12
|
+
autoload :Parser, 'fudge/parser'
|
13
|
+
autoload :Runner, 'fudge/runner'
|
14
|
+
autoload :Tasks, 'fudge/tasks'
|
15
|
+
autoload :TaskDSL, 'fudge/task_dsl'
|
16
|
+
end
|
data/lib/fudge/build.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
module Fudge
|
2
|
+
# Represents a build defined in the FudgeFile
|
3
|
+
#
|
4
|
+
class Build < Tasks::CompositeTask
|
5
|
+
attr_accessor :callbacks
|
6
|
+
attr_reader :success_hooks, :failure_hooks
|
7
|
+
|
8
|
+
def initialize(*args)
|
9
|
+
@success_hooks = []
|
10
|
+
@failure_hooks = []
|
11
|
+
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
def run(options={})
|
16
|
+
success = super
|
17
|
+
if callbacks
|
18
|
+
puts "Running #{success ? 'success' : 'failure'} callbacks...".foreground(:cyan).bright
|
19
|
+
hooks = success ? @success_hooks : @failure_hooks
|
20
|
+
|
21
|
+
hooks.each do |hook|
|
22
|
+
return false unless hook.run
|
23
|
+
end
|
24
|
+
else
|
25
|
+
puts "Skipping callbacks...".foreground(:cyan).bright
|
26
|
+
end
|
27
|
+
|
28
|
+
success
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/fudge/cli.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'thor'
|
2
|
+
|
3
|
+
module Fudge
|
4
|
+
class Cli < Thor
|
5
|
+
desc "init", "Initialize a blank Fudgefile"
|
6
|
+
def init
|
7
|
+
path = File.expand_path('Fudgefile', Dir.pwd)
|
8
|
+
|
9
|
+
if File.exists?(path)
|
10
|
+
puts "Fudgefile already exists."
|
11
|
+
else
|
12
|
+
contents = <<RUBY
|
13
|
+
build :default do
|
14
|
+
task :rspec
|
15
|
+
end
|
16
|
+
RUBY
|
17
|
+
File.open(path, 'w') { |f| f.write(contents) }
|
18
|
+
puts "Fudgefile created."
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
desc "build [BUILD_NAME]", "Run a build with the given name (default: 'default')"
|
23
|
+
method_option :callbacks, :type => :boolean, :default => false
|
24
|
+
def build(build_name='default')
|
25
|
+
description = Fudge::Parser.new.parse('Fudgefile')
|
26
|
+
Fudge::Runner.new(description).run_build(build_name, options)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Fudge
|
2
|
+
# A class that represents a FudgeFile definition in Ruby class form.
|
3
|
+
#
|
4
|
+
class Description
|
5
|
+
include TaskDSL
|
6
|
+
|
7
|
+
attr_reader :builds
|
8
|
+
|
9
|
+
# Sets builds to an initial empty array
|
10
|
+
def initialize(file)
|
11
|
+
@path = file.path
|
12
|
+
@builds = {}
|
13
|
+
@task_groups = {}
|
14
|
+
instance_eval(file.read, __FILE__, __LINE__)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Adds a build to the current description
|
18
|
+
def build(name)
|
19
|
+
@builds[name] = build = Build.new
|
20
|
+
with_scope(build) { yield }
|
21
|
+
end
|
22
|
+
|
23
|
+
# Adds a task group to the current description or includes a task group
|
24
|
+
def task_group(name, *args, &block)
|
25
|
+
if block
|
26
|
+
@task_groups[name] = block
|
27
|
+
else
|
28
|
+
find_task_group(name).call(*args)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Gets a task group of the given name
|
33
|
+
def find_task_group(name)
|
34
|
+
@task_groups[name].tap do |block|
|
35
|
+
raise Exceptions::TaskGroupNotFound.new(name) unless block
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def on_success
|
40
|
+
task = Fudge::Tasks::CompositeTask.new
|
41
|
+
current_scope.success_hooks << task
|
42
|
+
|
43
|
+
with_scope(task) { yield }
|
44
|
+
end
|
45
|
+
|
46
|
+
def on_failure
|
47
|
+
task = Fudge::Tasks::CompositeTask.new
|
48
|
+
current_scope.failure_hooks << task
|
49
|
+
|
50
|
+
with_scope(task) { yield }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Fudge
|
2
|
+
module Exceptions
|
3
|
+
class Base < StandardError; end
|
4
|
+
|
5
|
+
class BuildFailed < Base
|
6
|
+
def message
|
7
|
+
"Build FAILED!".foreground(:red).bright
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class TaskNotFound < Base
|
12
|
+
def initialize(task)
|
13
|
+
@task = task
|
14
|
+
end
|
15
|
+
|
16
|
+
def message
|
17
|
+
"No task found with name '#{@task}'"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class TaskGroupNotFound < Base
|
22
|
+
def initialize(name)
|
23
|
+
@name = name
|
24
|
+
end
|
25
|
+
|
26
|
+
def message
|
27
|
+
"No task group found with name '#{@name}'"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/fudge/parser.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rails'
|
2
|
+
require 'fudge'
|
3
|
+
|
4
|
+
module Fudge
|
5
|
+
|
6
|
+
# Adds behaviours to Rails
|
7
|
+
class Railtie < Rails::Railtie
|
8
|
+
railtie_name :fudge
|
9
|
+
rake_tasks do
|
10
|
+
begin
|
11
|
+
|
12
|
+
Dir[ File.join(File.dirname(__FILE__), '../tasks/*.rake')] .each { |f| load f } #Load static tasks
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/fudge/runner.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module Fudge
|
2
|
+
class Runner
|
3
|
+
def initialize(description)
|
4
|
+
@description = description
|
5
|
+
end
|
6
|
+
|
7
|
+
def run_build(which_build='default', options={})
|
8
|
+
which_build = String.new(which_build)
|
9
|
+
|
10
|
+
puts "Running build ".foreground(:cyan) + which_build.bright.foreground(:yellow)
|
11
|
+
|
12
|
+
# Run the build
|
13
|
+
build = @description.builds[which_build.to_sym]
|
14
|
+
build.callbacks = options[:callbacks]
|
15
|
+
status = build.run
|
16
|
+
|
17
|
+
# Output status
|
18
|
+
if status
|
19
|
+
puts "Build SUCCEEDED!".foreground(:green).bright
|
20
|
+
else
|
21
|
+
raise Exceptions::BuildFailed
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Fudge
|
2
|
+
module TaskDSL
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
attr_writer :scope
|
7
|
+
end
|
8
|
+
|
9
|
+
def scope
|
10
|
+
@scope ||= [self]
|
11
|
+
end
|
12
|
+
|
13
|
+
# Adds a task to the current scope
|
14
|
+
def task(name, *args)
|
15
|
+
klass = Fudge::Tasks.discover(name)
|
16
|
+
|
17
|
+
task = klass.new(*args)
|
18
|
+
current_scope.tasks << task
|
19
|
+
|
20
|
+
with_scope(task) { yield if block_given? }
|
21
|
+
end
|
22
|
+
|
23
|
+
# Delegate to the current object scope
|
24
|
+
def method_missing(meth, *args, &block)
|
25
|
+
task meth, *args, &block
|
26
|
+
rescue Fudge::Exceptions::TaskNotFound
|
27
|
+
super
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def current_scope
|
32
|
+
scope.last
|
33
|
+
end
|
34
|
+
|
35
|
+
def with_scope(task)
|
36
|
+
scope << task
|
37
|
+
yield
|
38
|
+
scope.pop
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/fudge/tasks.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
module Fudge
|
2
|
+
module Tasks
|
3
|
+
# Registers a task under a given name
|
4
|
+
def self.register(task_class)
|
5
|
+
registered_tasks[task_class.name] = task_class
|
6
|
+
end
|
7
|
+
|
8
|
+
# Finds a task with a given name
|
9
|
+
def self.discover(name)
|
10
|
+
task = registered_tasks[name]
|
11
|
+
raise Fudge::Exceptions::TaskNotFound.new(name) unless task
|
12
|
+
task
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
def self.registered_tasks
|
17
|
+
@registered_tasks ||= {}
|
18
|
+
end
|
19
|
+
|
20
|
+
# Require all my tasks
|
21
|
+
require 'fudge/tasks/task'
|
22
|
+
require 'fudge/tasks/shell'
|
23
|
+
require 'fudge/tasks/composite_task'
|
24
|
+
require 'fudge/tasks/each_directory'
|
25
|
+
require 'fudge/tasks/in_directory'
|
26
|
+
require 'fudge/tasks/clean_bundler_env'
|
27
|
+
require 'fudge/tasks/rake'
|
28
|
+
require 'fudge/tasks/rspec'
|
29
|
+
require 'fudge/tasks/yard'
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Fudge
|
2
|
+
module Tasks
|
3
|
+
class CleanBundlerEnv < CompositeTask
|
4
|
+
def self.name
|
5
|
+
:clean_bundler_env
|
6
|
+
end
|
7
|
+
|
8
|
+
def run(options={})
|
9
|
+
old_env = ENV
|
10
|
+
keys = ENV.keys.grep(/BUNDLE|RUBY/)
|
11
|
+
|
12
|
+
keys.each { |k| ENV[k] = nil }
|
13
|
+
|
14
|
+
result = super(options.merge(:bundler => true))
|
15
|
+
|
16
|
+
keys.each { |k| ENV[k] = old_env[k] }
|
17
|
+
|
18
|
+
result
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
register CleanBundlerEnv
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Fudge
|
2
|
+
module Tasks
|
3
|
+
class CompositeTask < Task
|
4
|
+
attr_accessor :description
|
5
|
+
|
6
|
+
def tasks
|
7
|
+
@tasks ||= []
|
8
|
+
end
|
9
|
+
|
10
|
+
# Runs the task (by default running all other tasks in order)
|
11
|
+
def run(options={})
|
12
|
+
tasks.each do |t|
|
13
|
+
args_text = t.respond_to?(:args) && t.args ? t.args.join(', ') : ''
|
14
|
+
|
15
|
+
puts "Running task ".foreground(:blue) +
|
16
|
+
t.class.name.to_s.foreground(:yellow).bright + ' ' +
|
17
|
+
args_text.foreground(:yellow).bright
|
18
|
+
|
19
|
+
return unless t.run(options)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Fudge
|
2
|
+
module Tasks
|
3
|
+
# A task which runs a number of other tasks in a given directory (relative to the current directory)
|
4
|
+
class EachDirectory < CompositeTask
|
5
|
+
attr_accessor :exclude
|
6
|
+
|
7
|
+
def self.name
|
8
|
+
:each_directory
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(pattern, *args)
|
12
|
+
super(*args)
|
13
|
+
|
14
|
+
@pattern = pattern
|
15
|
+
end
|
16
|
+
|
17
|
+
def run(options={})
|
18
|
+
# Allow either a string (usually "*") or an array of strings with directories
|
19
|
+
redir = @pattern.kind_of?(String) ? Dir[@pattern] : Dir[*@pattern]
|
20
|
+
|
21
|
+
redir.select { |path| File.directory? path }.each do |dir|
|
22
|
+
next if exclude && exclude.include?(dir)
|
23
|
+
|
24
|
+
Dir.chdir dir do
|
25
|
+
puts "--> In directory".foreground(:cyan) + " #{dir}:".foreground(:cyan).bright
|
26
|
+
return false unless super
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
register EachDirectory
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Fudge
|
2
|
+
module Tasks
|
3
|
+
# A task which runs a number of other tasks in a given directory (relative to the current directory)
|
4
|
+
class InDirectory < CompositeTask
|
5
|
+
def self.name
|
6
|
+
:in_directory
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(directory, *args)
|
10
|
+
super
|
11
|
+
@directory = directory
|
12
|
+
end
|
13
|
+
|
14
|
+
def run(options={})
|
15
|
+
Dir.chdir @directory do
|
16
|
+
puts "--> In directory".foreground(:cyan) + " #{@directory}:".foreground(:cyan).bright
|
17
|
+
super
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
register InDirectory
|
23
|
+
end
|
24
|
+
end
|