anvil-core 0.0.1.alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/.travis.yml +4 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +30 -0
- data/Rakefile +6 -0
- data/anvil-core.gemspec +35 -0
- data/bin/anvil +8 -0
- data/lib/anvil.rb +13 -0
- data/lib/anvil/assure.rb +9 -0
- data/lib/anvil/assures/directory_assure.rb +11 -0
- data/lib/anvil/assures/file_assure.rb +11 -0
- data/lib/anvil/cli.rb +59 -0
- data/lib/anvil/config.rb +15 -0
- data/lib/anvil/config/class_methods.rb +41 -0
- data/lib/anvil/parser.rb +34 -0
- data/lib/anvil/rubygems.rb +19 -0
- data/lib/anvil/task.rb +47 -0
- data/lib/anvil/task/class_methods.rb +39 -0
- data/lib/anvil/task/naming.rb +28 -0
- data/lib/anvil/task/options.rb +41 -0
- data/lib/anvil/task/repositories.rb +13 -0
- data/lib/anvil/task_manager.rb +47 -0
- data/lib/anvil/version.rb +3 -0
- data/lib/gem_ext/mixlib.rb +22 -0
- data/lib/tasks/gem_build_task.rb +51 -0
- data/lib/tasks/help_task.rb +20 -0
- data/lib/tasks/projects/add_task.rb +31 -0
- data/lib/tasks/projects/list_task.rb +21 -0
- data/spec/lib/assure_spec.rb +15 -0
- data/spec/lib/assures/directory_assure_spec.rb +19 -0
- data/spec/lib/assures/file_assure_spec.rb +13 -0
- data/spec/lib/cli_spec.rb +54 -0
- data/spec/lib/config_spec.rb +24 -0
- data/spec/lib/task/naming_spec.rb +26 -0
- data/spec/lib/task/options_spec.rb +33 -0
- data/spec/lib/task_manager_spec.rb +45 -0
- data/spec/lib/task_spec.rb +74 -0
- data/spec/lib/tasks/gem_build_task_spec.rb +89 -0
- data/spec/lib/tasks/projects/add_task_spec.rb +26 -0
- data/spec/lib/tasks/projects/list_task_spec.rb +20 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/support/dot_anvil/config.rb +2 -0
- data/spec/support/fixtures/dummy_after_task.rb +3 -0
- data/spec/support/fixtures/dummy_assure.rb +5 -0
- data/spec/support/fixtures/dummy_before_task.rb +3 -0
- data/spec/support/fixtures/dummy_failed_assure.rb +5 -0
- data/spec/support/fixtures/dummy_task.rb +15 -0
- data/spec/support/fixtures/foo/dummy_task.rb +5 -0
- data/spec/support/shared/config_context.rb +10 -0
- 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,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,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
|