anvil-core 0.0.1.alpha.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/.travis.yml +4 -0
  4. data/Gemfile +8 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +30 -0
  7. data/Rakefile +6 -0
  8. data/anvil-core.gemspec +35 -0
  9. data/bin/anvil +8 -0
  10. data/lib/anvil.rb +13 -0
  11. data/lib/anvil/assure.rb +9 -0
  12. data/lib/anvil/assures/directory_assure.rb +11 -0
  13. data/lib/anvil/assures/file_assure.rb +11 -0
  14. data/lib/anvil/cli.rb +59 -0
  15. data/lib/anvil/config.rb +15 -0
  16. data/lib/anvil/config/class_methods.rb +41 -0
  17. data/lib/anvil/parser.rb +34 -0
  18. data/lib/anvil/rubygems.rb +19 -0
  19. data/lib/anvil/task.rb +47 -0
  20. data/lib/anvil/task/class_methods.rb +39 -0
  21. data/lib/anvil/task/naming.rb +28 -0
  22. data/lib/anvil/task/options.rb +41 -0
  23. data/lib/anvil/task/repositories.rb +13 -0
  24. data/lib/anvil/task_manager.rb +47 -0
  25. data/lib/anvil/version.rb +3 -0
  26. data/lib/gem_ext/mixlib.rb +22 -0
  27. data/lib/tasks/gem_build_task.rb +51 -0
  28. data/lib/tasks/help_task.rb +20 -0
  29. data/lib/tasks/projects/add_task.rb +31 -0
  30. data/lib/tasks/projects/list_task.rb +21 -0
  31. data/spec/lib/assure_spec.rb +15 -0
  32. data/spec/lib/assures/directory_assure_spec.rb +19 -0
  33. data/spec/lib/assures/file_assure_spec.rb +13 -0
  34. data/spec/lib/cli_spec.rb +54 -0
  35. data/spec/lib/config_spec.rb +24 -0
  36. data/spec/lib/task/naming_spec.rb +26 -0
  37. data/spec/lib/task/options_spec.rb +33 -0
  38. data/spec/lib/task_manager_spec.rb +45 -0
  39. data/spec/lib/task_spec.rb +74 -0
  40. data/spec/lib/tasks/gem_build_task_spec.rb +89 -0
  41. data/spec/lib/tasks/projects/add_task_spec.rb +26 -0
  42. data/spec/lib/tasks/projects/list_task_spec.rb +20 -0
  43. data/spec/spec_helper.rb +26 -0
  44. data/spec/support/dot_anvil/config.rb +2 -0
  45. data/spec/support/fixtures/dummy_after_task.rb +3 -0
  46. data/spec/support/fixtures/dummy_assure.rb +5 -0
  47. data/spec/support/fixtures/dummy_before_task.rb +3 -0
  48. data/spec/support/fixtures/dummy_failed_assure.rb +5 -0
  49. data/spec/support/fixtures/dummy_task.rb +15 -0
  50. data/spec/support/fixtures/foo/dummy_task.rb +5 -0
  51. data/spec/support/shared/config_context.rb +10 -0
  52. metadata +245 -0
@@ -0,0 +1,28 @@
1
+ require 'active_support/core_ext/string'
2
+
3
+ module Anvil
4
+ class Task
5
+ module Naming
6
+ def get_namespace(task_name)
7
+ task_name.to_s.split ':'
8
+ end
9
+
10
+ def from_name(task_name)
11
+ namespaced_task = get_namespace task_name
12
+ camelized_task = "#{namespaced_task.pop}_task".camelize
13
+ camelized_namespace = "#{namespaced_task.shift}".camelize
14
+
15
+ "#{camelized_namespace}::#{camelized_task}".constantize
16
+ end
17
+
18
+ def task_name
19
+ name[/(.*)Task/, 1].underscore.gsub('/', ':')
20
+ end
21
+
22
+ def description(str = nil)
23
+ return @description unless str
24
+ @description = str
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,41 @@
1
+ require 'anvil/parser'
2
+
3
+ module Anvil
4
+ class Task
5
+ module Options
6
+ def help
7
+ parser.help
8
+ end
9
+
10
+ def parser(&block)
11
+ @parser ||= define_parser(&block)
12
+ end
13
+
14
+ def define_parser(&block)
15
+ parser = Anvil::Parser.new
16
+ parser.task = self
17
+ configure_parser(parser, &block)
18
+ parser
19
+ end
20
+
21
+ def configure_parser(parser, &block)
22
+ block ||= proc {}
23
+
24
+ if description
25
+ parser.separator ''
26
+ parser.separator description
27
+ end
28
+
29
+ parser.separator ''
30
+ parser.separator 'Available options: '
31
+ parser.instance_eval(&block)
32
+ parser
33
+ end
34
+
35
+ def parse_options!(arguments)
36
+ parser.parse!(arguments)
37
+ arguments << parser.options
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,13 @@
1
+ module Anvil
2
+ class Task
3
+ module Repositories
4
+ def resolve_url(url)
5
+ if url =~ /^\w+\/\w+$/
6
+ "git@github.com:#{url}"
7
+ else
8
+ url
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,47 @@
1
+ require 'anvil/config'
2
+ require 'anvil/task'
3
+ require 'rubygems'
4
+ require 'bundler/shared_helpers'
5
+
6
+ module Anvil
7
+ module TaskManager
8
+ @tasks_loaded = false
9
+
10
+ def self.load_tasks
11
+ all_files.each { |file| load(file) }
12
+ @tasks_loaded = true
13
+ end
14
+
15
+ def self.files_from_anvil
16
+ files_from_path(File.expand_path('../..', __FILE__))
17
+ end
18
+
19
+ def self.files_from_current_project
20
+ path = File.dirname(Bundler::SharedHelpers.default_gemfile) + '/lib/anvil/'
21
+ files_from_path(path)
22
+ end
23
+
24
+ def self.files_from_path(path)
25
+ Dir[path + '/tasks/**/*_task.rb']
26
+ end
27
+
28
+ def self.files_from_gems
29
+ Gem.find_latest_files 'anvil/tasks/**/*_task.rb'
30
+ end
31
+
32
+ def self.all_files
33
+ [files_from_anvil,
34
+ files_from_current_project,
35
+ files_from_gems].compact.reduce(&:+).uniq
36
+ end
37
+
38
+ def self.all_tasks
39
+ load_tasks unless @tasks_loaded
40
+ ::Anvil::Task.descendants
41
+ end
42
+
43
+ def self.tasks_by_name
44
+ all_tasks.sort_by { |t| t.name }
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,3 @@
1
+ module Anvil
2
+ VERSION = '0.0.1.alpha.1'
3
+ end
@@ -0,0 +1,22 @@
1
+ module Mixlib::Config
2
+ alias_method :old_method_missing, :method_missing
3
+
4
+ # Override Mixlib::Config#method_missing so we can do
5
+ # things like this:
6
+ #
7
+ # @example define a nested group without use config_context
8
+ #
9
+ # projects do
10
+ # branch_flow %w[release master]
11
+ # project-one do
12
+ # branch_flow %w[integration release master]
13
+ # end
14
+ # end
15
+ def method_missing(method, *args, &block)
16
+ if block_given?
17
+ config_context(method, &block)
18
+ else
19
+ old_method_missing(method, *args)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,51 @@
1
+ require 'fileutils'
2
+ require 'anvil/task'
3
+ require 'anvil/rubygems'
4
+
5
+ class GemBuildTask < Anvil::Task
6
+ description 'Builds a gem for you and can install it on your system.'
7
+
8
+ parser do
9
+ arguments %w[gemspec_file]
10
+
11
+ on('-i', '--[no-]install', 'Install gem') do |i|
12
+ options[:install] = i
13
+ end
14
+ end
15
+
16
+ attr_reader :gemspec_file, :options
17
+
18
+ def initialize(gemspec_file, options = {})
19
+ @gemspec_file = gemspec_file
20
+ @options = options
21
+ end
22
+
23
+ def task
24
+ path = File.dirname(gemspec_file)
25
+
26
+ Dir.chdir(path) do
27
+ gem_file = build_gem(gemspec_file)
28
+ Anvil::Rubygems.install gem_file if install?
29
+
30
+ gem_file
31
+ end
32
+ end
33
+
34
+ def build_gem(gemspec_file)
35
+ rubygems_output = Anvil::Rubygems.build(gemspec_file)
36
+ gem_file = extract_gem_file(rubygems_output)
37
+
38
+ FileUtils.mkdir_p('pkg')
39
+ FileUtils.move(gem_file, 'pkg')
40
+
41
+ File.expand_path("pkg/#{gem_file}")
42
+ end
43
+
44
+ def extract_gem_file(output)
45
+ output.match(/File: (.*)$/)[1]
46
+ end
47
+
48
+ def install?
49
+ options.fetch(:install, true)
50
+ end
51
+ end
@@ -0,0 +1,20 @@
1
+ require 'anvil/task'
2
+
3
+ class HelpTask < Anvil::Task
4
+ description 'Help for the anvil tasks. Usage: anvil help TASK'
5
+
6
+ parser do
7
+ arguments %w[task_name]
8
+ end
9
+
10
+ attr_reader :task_name
11
+
12
+ def initialize(task_name, options = {})
13
+ @task_name = task_name
14
+ end
15
+
16
+ def task
17
+ klazz = Anvil::Task.from_name(task_name)
18
+ printf(klazz.help)
19
+ end
20
+ end
@@ -0,0 +1,31 @@
1
+ require 'anvil/task'
2
+ require 'anvil/task/repositories'
3
+ require 'anvil/config'
4
+ require 'git'
5
+
6
+ module Projects
7
+ class AddTask < Anvil::Task
8
+ include Anvil::Task::Repositories
9
+ description 'Adds a new project for anvil.'
10
+
11
+ parser do
12
+ arguments %w[name repository]
13
+ end
14
+
15
+ attr_reader :name, :repo
16
+
17
+ def initialize(name, repo, options = {})
18
+ @name = name
19
+ @repo = repo
20
+ end
21
+
22
+ def task
23
+ url_to_clone = resolve_url(repo)
24
+ clone_repo(url_to_clone, name)
25
+ end
26
+
27
+ def clone_repo(url, name)
28
+ Dir.chdir(Anvil::Config.base_projects_path) { Git.clone(url, name) }
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,21 @@
1
+ require 'anvil/task'
2
+
3
+ module Projects
4
+ class ListTask < Anvil::Task
5
+ description 'List the projects that anvil can manage.'
6
+
7
+ def initialize(options = {}); end
8
+
9
+ def task
10
+ Dir.chdir(Anvil::Config.base_projects_path) { list_projects(projects) }
11
+ end
12
+
13
+ def projects
14
+ Dir.glob('*').select { |f| File.directory?(f) }.sort
15
+ end
16
+
17
+ def list_projects(names)
18
+ printf("%s\n", names.join("\n"))
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe Anvil::Assure do
4
+ subject { dummy_assure.new }
5
+
6
+ context 'on a passing assure' do
7
+ let(:dummy_assure) { DummyAssure }
8
+ it { should be_assured }
9
+ end
10
+
11
+ context 'on a non passing assure' do
12
+ let(:dummy_assure) { DummyFailedAssure }
13
+ it { should_not be_assured }
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe Anvil::DirectoryAssure do
4
+ context 'with an existing directory' do
5
+ before { FileUtils.mkdir('dummy_dir') }
6
+
7
+ it { should be_assured('dummy_dir') }
8
+ end
9
+
10
+ context 'with a non existing directory' do
11
+ it { should_not be_assured('dummy_dir') }
12
+ end
13
+
14
+ context 'with a file' do
15
+ before { FileUtils.touch('dummy_file') }
16
+
17
+ it { should_not be_assured('dummy_file') }
18
+ end
19
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Anvil::FileAssure do
4
+ context 'with an existing file' do
5
+ before { FileUtils.touch 'dummy_file.txt' }
6
+
7
+ it { should be_assured('dummy_file.txt') }
8
+ end
9
+
10
+ context 'with a non existing file' do
11
+ it { should_not be_assured('dummy_file.txt') }
12
+ end
13
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe Anvil::Cli do
4
+ # before {FakeFS.deactivate!}
5
+ describe '#run' do
6
+ let(:dummy_task) { DummyTask }
7
+ let(:argv) { %w[dummy arg1 arg2 --argument value] }
8
+
9
+ context 'with a task name' do
10
+ before do
11
+ dummy_task.should_receive(:new)
12
+ .with('arg1', 'arg2', argument: 'value').and_call_original
13
+ subject.should_not_receive(:print_help)
14
+ end
15
+
16
+ it('runs the task in the first parameter') { subject.run argv }
17
+ end
18
+
19
+ describe '#build_task' do
20
+ it 'builds the task and parses the arguments' do
21
+ subject.build_task(argv).options.should == { argument: 'value' }
22
+ end
23
+
24
+ context 'if the task is not found' do
25
+ let(:argv) { %w[ihopethiswillnotexistever arg2] }
26
+
27
+ it 'prints task list and exits' do
28
+ expect(subject).to receive(:task_not_found)
29
+ .with('ihopethiswillnotexistever')
30
+ expect do
31
+ subject.build_task(argv)
32
+ end.to raise_error(SystemExit)
33
+ end
34
+ end
35
+
36
+ context 'if the arguments are not the correct' do
37
+ let(:argv) { %w[foo:dummy arg1 arg2 arg3 arg4 arg5 arg6 arg7] }
38
+
39
+ it 'prints task list and exits' do
40
+ expect(subject).to receive(:help).with('foo:dummy')
41
+ expect do
42
+ subject.build_task(argv)
43
+ end.to raise_error(SystemExit)
44
+ end
45
+ end
46
+ end
47
+
48
+ context 'without a task name' do
49
+ let(:argv) { [] }
50
+ before { subject.should_receive(:print_help) }
51
+ it('prints the help') { subject.run argv }
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe Anvil::Config do
4
+ subject { Anvil::Config }
5
+ before { Anvil::Config.reset }
6
+
7
+ its('github.user') { should be_nil }
8
+ its('github.token') { should be_nil }
9
+
10
+ context 'with a config file', config: true do
11
+ its('github.user') { should eq('dummy_user') }
12
+ its('github.token') { should eq('dummy_token') }
13
+ end
14
+
15
+ context '.init_base_path' do
16
+ before { Anvil::Config.send :init_base_path }
17
+ subject { File }
18
+
19
+ it { should be_directory(Anvil::Config.base_path) }
20
+ it { should be_directory(Anvil::Config.base_tasks_path) }
21
+ it { should be_exists(Anvil::Config.base_config_path) }
22
+ it { should be_exists(Anvil::Config.base_projects_path) }
23
+ end
24
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+ require 'anvil/task/naming'
3
+
4
+ describe Anvil::Task::Naming do
5
+ let(:klass) { DummyTask }
6
+
7
+ describe '#task_name' do
8
+ it 'returns the correct task name' do
9
+ expect(klass.task_name).to be_eql('dummy')
10
+ end
11
+ end
12
+
13
+ describe '.from_name' do
14
+ context 'without a namespace' do
15
+ it 'finds the task class' do
16
+ klass.from_name('dummy').should eq(DummyTask)
17
+ end
18
+ end
19
+
20
+ context 'with a namespace' do
21
+ it 'finds the namespaced tasks class' do
22
+ klass.from_name('foo:dummy').should eq(Foo::DummyTask)
23
+ end
24
+ end
25
+ end
26
+ end