fudge 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/bin/fudge +9 -0
  2. data/lib/fudge.rb +16 -0
  3. data/lib/fudge/build.rb +31 -0
  4. data/lib/fudge/cli.rb +29 -0
  5. data/lib/fudge/description.rb +53 -0
  6. data/lib/fudge/exceptions.rb +31 -0
  7. data/lib/fudge/helpers.rb +5 -0
  8. data/lib/fudge/helpers/bundle_aware.rb +14 -0
  9. data/lib/fudge/parser.rb +12 -0
  10. data/lib/fudge/railtie.rb +17 -0
  11. data/lib/fudge/runner.rb +25 -0
  12. data/lib/fudge/task_dsl.rb +41 -0
  13. data/lib/fudge/tasks.rb +31 -0
  14. data/lib/fudge/tasks/clean_bundler_env.rb +24 -0
  15. data/lib/fudge/tasks/composite_task.rb +24 -0
  16. data/lib/fudge/tasks/each_directory.rb +34 -0
  17. data/lib/fudge/tasks/in_directory.rb +24 -0
  18. data/lib/fudge/tasks/rake.rb +19 -0
  19. data/lib/fudge/tasks/rspec.rb +29 -0
  20. data/lib/fudge/tasks/shell.rb +76 -0
  21. data/lib/fudge/tasks/task.rb +18 -0
  22. data/lib/fudge/tasks/yard.rb +29 -0
  23. data/lib/fudge/version.rb +3 -0
  24. data/lib/tasks/fudge.rake +7 -0
  25. data/spec/lib/fudge/build_spec.rb +5 -0
  26. data/spec/lib/fudge/cli_spec.rb +76 -0
  27. data/spec/lib/fudge/description_spec.rb +241 -0
  28. data/spec/lib/fudge/exceptions_spec.rb +36 -0
  29. data/spec/lib/fudge/parser_spec.rb +23 -0
  30. data/spec/lib/fudge/runner_spec.rb +25 -0
  31. data/spec/lib/fudge/tasks/bundler_spec.rb +39 -0
  32. data/spec/lib/fudge/tasks/composite_task_spec.rb +60 -0
  33. data/spec/lib/fudge/tasks/each_directory_spec.rb +57 -0
  34. data/spec/lib/fudge/tasks/in_directory_spec.rb +39 -0
  35. data/spec/lib/fudge/tasks/rake_spec.rb +18 -0
  36. data/spec/lib/fudge/tasks/rspec_spec.rb +36 -0
  37. data/spec/lib/fudge/tasks/shell_spec.rb +38 -0
  38. data/spec/lib/fudge/tasks/task_spec.rb +14 -0
  39. data/spec/lib/fudge/tasks/yard_spec.rb +25 -0
  40. data/spec/lib/fudge/tasks_spec.rb +33 -0
  41. data/spec/spec_helper.rb +22 -0
  42. data/spec/support/dummy_task.rb +40 -0
  43. data/spec/support/matchers.rb +47 -0
  44. data/spec/support/tmpdir.rb +12 -0
  45. metadata +302 -0
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ require 'fudge'
3
+ begin
4
+ Fudge::Cli.start
5
+ rescue Fudge::Exceptions::Base => e
6
+ puts e.message
7
+ exit 1
8
+ end
9
+
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,5 @@
1
+ module Fudge
2
+ module Helpers
3
+ require 'fudge/helpers/bundle_aware'
4
+ end
5
+ end
@@ -0,0 +1,14 @@
1
+ module Fudge
2
+ module Helpers
3
+ module BundleAware
4
+ private
5
+ def bundle_cmd(original, options={})
6
+ if options[:bundler]
7
+ "bundle exec #{original}"
8
+ else
9
+ original
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ module Fudge
2
+ # Handles parsing of fudge file and building the necessary description
3
+ #
4
+ class Parser
5
+ # Parse a FudgeFile at a given location
6
+ def parse(file)
7
+ File.open(file) do |f|
8
+ Description.new(f)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -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
@@ -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
@@ -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