Skip to content
This repository has been archived by the owner on Apr 6, 2021. It is now read-only.

Commit

Permalink
Shanty plugin-config
Browse files Browse the repository at this point in the history
- add methods to resolve plugin name in the Plugin class
- add the name of the plugin as the default plugin tag
- add a command line task to display the enabled plugin names
- add a global command line option to imput global configuration
- refactor env so configuration is in a separate class
- make the config class return OpenStructs instead of a hash
  • Loading branch information
janstenpickle committed Sep 25, 2015
1 parent 654addb commit 129bf4c
Show file tree
Hide file tree
Showing 16 changed files with 203 additions and 21 deletions.
17 changes: 17 additions & 0 deletions lib/shanty/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
require 'i18n'
require 'shanty/info'
require 'shanty/task_set'
require 'shanty/env'
require 'shenanigans/hash/to_ostruct'
require 'deep_merge'

module Shanty
# Public: Handle the CLI interface between the user and the registered tasks
Expand All @@ -11,6 +14,8 @@ class Cli

attr_reader :task_sets

CONFIG_FORMAT = '[plugin]:[key] [value]'

def initialize(task_sets)
@task_sets = task_sets
end
Expand All @@ -28,11 +33,23 @@ def run
program(:description, Info::DESCRIPTION)

setup_tasks
global_config
run!
end

private

def global_config
global_option('-c', '--config [CONFIG]', "Add config via command line in the format #{CONFIG_FORMAT}") do |config|
match = config.match(/(?<plugin>\S+):(?<key>\S+)\s+(?<value>\S+)/)
if match
Env.config.merge!(match[:plugin] => { match[:key] => match[:value] })
else
abort("Invalid config format \"#{config}\" should be #{CONFIG_FORMAT}")
end
end
end

def setup_tasks
tasks.each do |name, task|
setup_task(name, task)
Expand Down
51 changes: 51 additions & 0 deletions lib/shanty/config.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
require 'shenanigans/hash/to_ostruct'
require 'deep_merge'

module Shanty
# Public: Configuration class for shanty
class Config
CONFIG_FILE = '.shanty.yml'

def initialize(root, environment)
@root = root
@environment = environment
end

def merge!(new_config)
@config = config_hash.clone.deep_merge(new_config)
end

def [](key)
to_ostruct[key]
end

def method_missing(m)
os_resp = to_ostruct.send(m)
return os_resp unless os_resp.nil?
OpenStruct.new
end

def respond_to?(method_sym, include_private = false)
to_ostruct.send.respond_to?(method_sym, include_private)
end

def to_ostruct
config_hash.to_ostruct
end

private

def config_hash
return @config unless @config.nil?
return @config = {} unless File.exist?(config_path)
config = YAML.load_file(config_path) || {}
@config = config[@environment] || {}
rescue RuntimeError
{}
end

def config_path
"#{@root}/#{CONFIG_FILE}"
end
end
end
11 changes: 6 additions & 5 deletions lib/shanty/env.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
require 'logger'
require 'pathname'
require 'yaml'
require 'shenanigans/hash/to_ostruct'

require 'shanty/config'
require 'shanty/project_tree'

module Shanty
Expand All @@ -24,7 +26,7 @@ def clear!

def require!
Dir.chdir(root) do
(config['require'] || {}).each do |path|
(config.require || []).each do |path|
requires_in_path(path).each { |f| require File.join(root, f) }
end
end
Expand Down Expand Up @@ -58,10 +60,9 @@ def project_tree
end

def config
return @config unless @config.nil?
return @config = {} unless File.exist?(config_path)
config = YAML.load_file(config_path) || {}
@config = config[environment] || {}
@config ||= Config.new(root, environment)
rescue RuntimeError
@config ||= Config.new(nil, environment)
end

private
Expand Down
22 changes: 21 additions & 1 deletion lib/shanty/plugin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ def self.inherited(plugin_class)
@plugins << plugin_class.new
end

def self.plugins
(@plugins || []).map(&:name)
end

def self.all_projects
(@plugins || []).flat_map(&:projects).uniq
end
Expand All @@ -22,10 +26,18 @@ def self.all_with_graph(graph)
end

def self.tags(*args)
@tags ||= []
@tags ||= [name]
@tags.concat(args)
end

def self.option(option, default: nil)
config[name][option] = default if config[name][option].nil?
end

def self.options
config[name]
end

def self.projects(*globs_or_syms)
@project_matchers ||= []
@project_matchers.concat(globs_or_syms)
Expand All @@ -36,6 +48,14 @@ def self.with_graph(&block)
@with_graph_callbacks << block
end

def self.name
to_s.split('::').last.downcase.gsub('plugin', '').to_sym
end

def name
self.class.name
end

def projects
project_matchers = self.class.instance_variable_get(:@project_matchers)
return [] if project_matchers.nil? || project_matchers.empty?
Expand Down
1 change: 0 additions & 1 deletion lib/shanty/plugins/bundler_plugin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
module Shanty
# Public: Bundler plugin for building ruby projects.
class BundlerPlugin < Plugin
tags :bundler
projects '**/Gemfile'
subscribe :build, :bundle_install

Expand Down
1 change: 0 additions & 1 deletion lib/shanty/plugins/cucumber_plugin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
module Shanty
# Public: Cucumber plugin for testing ruby projects.
class CucumberPlugin < Plugin
tags :cucumber
subscribe :test, :cucumber
# By default, we'll detect Cucumber in a project if has a dependency on it in a Gemfile or *.gemspec file. If you
# don't use these files, you'll need to import the plugin manually using a Shantyfile as we can't tell if RSpec is
Expand Down
1 change: 0 additions & 1 deletion lib/shanty/plugins/rspec_plugin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
module Shanty
# Public: Rspec plugin for testing ruby projects.
class RspecPlugin < Plugin
tags :rspec
subscribe :test, :rspec
# By default, we'll detect RSpec in a project if has a dependency on it in a Gemfile or *.gemspec file. If you don't
# use these files, you'll need to import the plugin manually using a Shantyfile as we can't tell if RSpec is being
Expand Down
1 change: 0 additions & 1 deletion lib/shanty/plugins/rubocop_plugin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
module Shanty
# Public: Rubocop plugin for style checking ruby projects.
class RubocopPlugin < Plugin
tags :rubocop
projects '**/.rubocop.yml'
subscribe :test, :rubocop

Expand Down
1 change: 0 additions & 1 deletion lib/shanty/plugins/rubygem_plugin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
module Shanty
# Public: Rubygem plugin for buildin gems.
class RubygemPlugin < Plugin
tags :rubygem
projects '**/*.gemspec'
subscribe :build, :build_gem

Expand Down
1 change: 0 additions & 1 deletion lib/shanty/plugins/shantyfile_plugin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
module Shanty
# Public: Plugin for finding all directories marked with a Shantyfile.
class ShantyfilePlugin < Plugin
tags :shantyfile
projects :shantyfile_projects

def shantyfile_projects
Expand Down
6 changes: 6 additions & 0 deletions lib/shanty/task_sets/basic_task_set.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require 'fileutils'
require 'i18n'
require 'shanty/task_set'
require 'shanty/plugin'

module Shanty
# Public: A set of basic tasks that can be applied to all projects and that
Expand All @@ -11,6 +12,11 @@ def init
FileUtils.touch(File.join(Dir.pwd, '.shanty.yml'))
end

desc 'plugins', 'tasks.plugins.desc'
def plugins(*)
puts Plugin.plugins
end

desc 'projects [--tags TAG,TAG,...]', 'tasks.projects.desc'
option :tags, type: :array, desc: 'tasks.common.options.tags'
def projects(options)
Expand Down
1 change: 1 addition & 0 deletions shanty.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Gem::Specification.new do |gem|
gem.add_dependency 'gitignore_rb', '~>0.2.2'
gem.add_dependency 'i18n', '~>0.7'
gem.add_dependency 'shenanigans', '~>1.0'
gem.add_dependency 'deep_merge', '~>1.0'

gem.add_development_dependency 'coveralls', '~>0.8'
gem.add_development_dependency 'cucumber', '~>2.1'
Expand Down
26 changes: 26 additions & 0 deletions spec/lib/shanty/cli_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
require 'spec_helper'
require 'shanty/cli'
require 'shanty/info'
require 'shanty/env'
require 'shenanigans/hash/to_ostruct'
require_fixture 'test_task_set'

# All classes referenced belong to the shanty project
Expand Down Expand Up @@ -112,6 +114,30 @@ module Shanty

subject.run
end

it('fails to run a command with config options if config is in incorrect format') do
expect(subject).to receive(:abort).with('Invalid config format "nic" should be [plugin]:[key] [value]')

ARGV.concat(%w(-c nic foo))

subject.run
end

it('runs a command with a config option') do
ARGV.concat(['-c nic:kim cage'])

subject.run

expect(Env.config.nic).to eql({ kim: 'cage' }.to_ostruct)
end

it('runs a command with multiple config options') do
ARGV.concat(['-c nic:kim cage', '-c nic:copolla cage'])

subject.run

expect(Env.config.nic).to eql({ kim: 'cage', copolla: 'cage' }.to_ostruct)
end
end
end
end
65 changes: 65 additions & 0 deletions spec/lib/shanty/config_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
require 'shanty/config'
require 'shenanigans/hash/to_ostruct'
require 'deep_merge'

# All classes referenced belong to the shanty project
module Shanty
RSpec.describe(Config) do
subject { Config.new('nic', 'test') }

let(:subconfig) { { 'kim' => 'cage' } }
let(:config) { { 'nic' => subconfig } }
let(:env_config) { { 'test' => config } }

before do
allow(File).to receive(:exist?) { true }
allow(YAML).to receive(:load_file) { env_config }
end

describe(Config) do
it('can respond like an OpenStruct') do
expect(subject.nic).to eql(subconfig.to_ostruct)
end

it('handles no config file existing') do
allow(File).to receive(:exist?) { false }
expect(subject.nic).to eql(OpenStruct.new)
end

it('handles no data in the config file') do
allow(YAML).to receive(:load_file) { false }
expect(subject.nic).to eql(OpenStruct.new)
end

it('loads config from a file') do
allow(File).to receive(:exist?).and_call_original
allow(YAML).to receive(:load_file).and_call_original
Dir.mktmpdir('shanty-tests') do |tmp_path|
Dir.chdir(tmp_path) { FileUtils.touch('.shanty.yml') }
expect(Config.new(tmp_path, 'test').nic).to eql(OpenStruct.new)
end
end

it('returns nothing if .shanty.yml does not exist') do
allow(File).to receive(:exist?).and_call_original
allow(YAML).to receive(:load_file).and_call_original
expect(subject.nic).to eql(OpenStruct.new)
end
end

describe('#[]') do
it('can respond like a hash') do
expect(subject['nic']).to eql(subconfig.to_ostruct)
end
end

describe('merge!') do
it('can merge in new config') do
added_config = { 'copolla' => 'cage' }
subject.merge!('nic' => added_config)

expect(subject['nic']).to eql(subconfig.deep_merge(added_config).to_ostruct)
end
end
end
end
17 changes: 8 additions & 9 deletions spec/lib/shanty/env_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
require 'i18n'
require 'tmpdir'
require 'shanty/env'
require 'shenanigans/hash/to_ostruct'
require 'deep_merge'

# All classes referenced belong to the shanty project
module Shanty
Expand Down Expand Up @@ -109,27 +111,24 @@ module Shanty
end

describe('#config') do
let(:env_config) { { 'foo' => 'bar' } }
let(:config) { { 'stray_cats' => env_config } }

before do
ENV['SHANTY_ENV'] = 'stray_cats'
allow(YAML).to receive(:load_file) { config }
end

it('has all the keys from the config file for the current env') do
expect(subject.config).to eql(env_config)
end

it('handles no config file existing') do
allow(File).to receive(:exist?) { false }
expect(subject.config).to eql({})
expect(subject.config.nic).to eql(OpenStruct.new)
end

it('handles no data in the config file') do
allow(YAML).to receive(:load_file) { false }
expect(subject.config)
end

it('returns nothing if .shanty.yml does not exist') do
FileUtils.rm('.shanty.yml')
expect(subject.config.nic).to eql(OpenStruct.new)
end
end
end
end
Loading

0 comments on commit 129bf4c

Please sign in to comment.