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.
- 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
|