anvil-core 0.0.1.alpha.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 (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