fudge 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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