├── .gitignore ├── .kitchen.yml ├── .rubocop.yml ├── .travis.yml ├── Berksfile ├── CHANGELOG.md ├── Gemfile ├── README.md ├── Rakefile ├── libraries └── matchers.rb ├── metadata.rb ├── providers ├── alias.rb └── environment.rb ├── resources ├── alias.rb └── environment.rb ├── spec ├── providers │ ├── alias_spec.rb │ └── environment_spec.rb └── spec_helper.rb └── test ├── fixtures └── cookbooks │ ├── magic_shell_alias │ ├── metadata.rb │ └── recipes │ │ ├── add.rb │ │ └── remove.rb │ └── magic_shell_environment │ ├── metadata.rb │ └── recipes │ ├── add.rb │ └── remove.rb ├── integration ├── magic_shell_alias_add │ └── serverspec │ │ └── assert_added_spec.rb ├── magic_shell_alias_remove │ └── serverspec │ │ └── assert_removed_spec.rb ├── magic_shell_environment_add │ └── serverspec │ │ └── assert_added_spec.rb └── magic_shell_environment_remove │ └── serverspec │ └── assert_removed_spec.rb └── shared └── spec_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *# 3 | .#* 4 | \#*# 5 | .*.sw[a-z] 6 | *.un~ 7 | *.tmp 8 | *.bk 9 | *.bkup 10 | .kitchen.local.yml 11 | Berksfile.lock 12 | Gemfile.lock 13 | 14 | .bundle/ 15 | .cache/ 16 | .kitchen/ 17 | .vagrant/ 18 | .vagrant.d/ 19 | .yardoc/ 20 | bin/ 21 | doc/ 22 | tmp/ 23 | vendor/ 24 | -------------------------------------------------------------------------------- /.kitchen.yml: -------------------------------------------------------------------------------- 1 | driver: 2 | name: vagrant 3 | 4 | provisioner: 5 | name: chef_solo 6 | data_path: test/shared 7 | 8 | platforms: 9 | - name: ubuntu-12.04 10 | - name: centos-6.4 11 | 12 | suites: 13 | # 14 | # Alias suites 15 | # 16 | - name: magic_shell_alias_add 17 | run_list: magic_shell_alias::add 18 | - name: magic_shell_alias_remove 19 | run_list: magic_shell_alias::remove 20 | 21 | # 22 | # Environment suites 23 | # 24 | - name: magic_shell_environment_add 25 | run_list: magic_shell_environment::add 26 | - name: magic_shell_environment_remove 27 | run_list: magic_shell_environment::remove 28 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | Encoding: 2 | Enabled: false 3 | LineLength: 4 | Enabled: false 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | rvm: 2 | - 1.9.3 3 | - 2.0.0 4 | - 2.1.0 5 | script: 6 | - bundle exec rake travis:ci 7 | -------------------------------------------------------------------------------- /Berksfile: -------------------------------------------------------------------------------- 1 | source 'https://api.berkshelf.com' 2 | 3 | group :integration do 4 | cookbook 'magic_shell_alias', path: 'test/fixtures/cookbooks/magic_shell_alias' 5 | cookbook 'magic_shell_environment', path: 'test/fixtures/cookbooks/magic_shell_environment' 6 | end 7 | 8 | metadata 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | magic_shell CHANGELOG 2 | ===================== 3 | 4 | 1.0.1 5 | ----- 6 | * changed file permissions to be 0644 instead of 755 7 | 8 | 9 | 1.0.0 10 | ----- 11 | * Refactor providers to support whyrun mode 12 | * Package custom ChefSpec matchers 13 | * Add Test Kitchen integration test 14 | * Update ChefSpec tests 15 | * Expand environment variables (like `$PATH`) 16 | * Add Rakefile for running tests 17 | * Use the latest and greatest testing strategies 18 | 19 | 0.3.1, 0.3.2 20 | ------------ 21 | 22 | * **No changes** - chefigonre with `knife cookbook site share` was being ignored, so unnecessary artifacts were uploaded 23 | 24 | 0.3.0 25 | ---- 26 | 27 | * Full test suite 28 | * Test with strainer 29 | * Support for cross-Chef version default_action 30 | 31 | 0.2.0 32 | ---- 33 | 34 | * Add `magic_shell_environment` 35 | 36 | 0.1.5 37 | ---- 38 | 39 | * The default action for the alias resource is now :add 40 | 41 | 0.1.4 42 | ----- 43 | 44 | * The default action for the alias resource is now :create 45 | * Formatting changes to the metadata, README, and CHANGELOG 46 | 47 | 0.1.3 48 | ----- 49 | 50 | * Address FC0016 - specify a default action 51 | * Add integration with Travis CI 52 | 53 | 0.1.2 54 | ----- 55 | 56 | * Update the README to indicate that you need to specify an action (:add or :remove) 57 | 58 | 0.1.1 59 | ----- 60 | 61 | * Rename the resource and provider files 62 | 63 | 0.1.0 64 | ----- 65 | 66 | * Initial release of magic_shell 67 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | group :test, :development do 4 | gem 'rake' 5 | gem 'stove', '~> 1.1' 6 | end 7 | 8 | group :test do 9 | gem 'berkshelf', '~> 3.0.0.beta' 10 | gem 'chefspec', '~> 3.0' 11 | gem 'foodcritic', '~> 3.0' 12 | gem 'rubocop', '~> 0.16' 13 | 14 | # Because, reasons: https://github.com/bbatsov/rubocop/issues/762 15 | gem 'rainbow', '~> 1.99' 16 | 17 | gem 'test-kitchen', '~> 1.1' 18 | gem 'kitchen-vagrant', '~> 0.14' 19 | end 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | magic_shell Cookbook 2 | ==================== 3 | [![Build Status](https://secure.travis-ci.org/customink-webops/magic_shell.png)](http://travis-ci.org/customink-webops/magic_shell) 4 | 5 | Provides utility for adding some syntactic sugar to your shell. 6 | 7 | Usage 8 | ----- 9 | Update the `metadata.rb` for your cookbook to depend on magic_shell 10 | 11 | ```ruby 12 | depends 'magic_shell' 13 | ``` 14 | 15 | Use the `magic_shell_alias` resource to create a command alias. 16 | 17 | ```ruby 18 | magic_shell_alias 'myrailsapp' do 19 | command 'cd /opt/myrailsapp/current' 20 | end 21 | ``` 22 | 23 | This will alias `myrailsapp` to `cd /opt/myrailsapp/current`. 24 | 25 | You can also remove aliases: 26 | 27 | ```ruby 28 | magic_shell_alias 'myrailsapp' do 29 | action :remove 30 | end 31 | ``` 32 | 33 | Use the `magic_shell_environment` resource to create a shell environment variable. 34 | 35 | ```ruby 36 | magic_shell_environment 'EDITOR' do 37 | value 'vim' 38 | end 39 | ``` 40 | 41 | This will export an `EDITOR` environment variable with a value of `vim`. 42 | 43 | You can also remove environment variables: 44 | 45 | ```ruby 46 | magic_shell_environment 'EDITOR' do 47 | action :remove 48 | end 49 | ``` 50 | 51 | Userspace environment variables and permissions for security or virtualenvs 52 | ```ruby 53 | magic_shell_environment 'EDITOR' do 54 | value 'vim' 55 | owner 'username' 56 | group 'groupname' 57 | mode '0600' 58 | destination '/home/user/.profile.d/' 59 | end 60 | ``` 61 | 62 | Contributing 63 | ------------ 64 | 1. Fork the repo 65 | 2. Create a feature branch 66 | 3. Code, document, write specs, test 67 | 4. Submit a PR 68 | 69 | 70 | License & Authors 71 | ----------------- 72 | - Author: Nathen Harvey 73 | - Author: Seth Vargo 74 | 75 | ```text 76 | Copyright 2012-2014 CustomInk, LLC. 77 | 78 | Licensed under the Apache License, Version 2.0 (the "License"); 79 | you may not use this file except in compliance with the License. 80 | You may obtain a copy of the License at 81 | 82 | http://www.apache.org/licenses/LICENSE-2.0 83 | 84 | Unless required by applicable law or agreed to in writing, software 85 | distributed under the License is distributed on an "AS IS" BASIS, 86 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 87 | See the License for the specific language governing permissions and 88 | limitations under the License. 89 | ``` 90 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler/setup' 2 | 3 | namespace :style do 4 | require 'rubocop/rake_task' 5 | desc 'Run Ruby style checks' 6 | Rubocop::RakeTask.new(:ruby) 7 | 8 | require 'foodcritic' 9 | desc 'Run Chef style checks' 10 | FoodCritic::Rake::LintTask.new(:chef) 11 | end 12 | 13 | desc 'Run all style checks' 14 | task style: ['style:chef', 'style:ruby'] 15 | 16 | require 'rspec/core/rake_task' 17 | desc 'Run ChefSpec unit tests' 18 | RSpec::Core::RakeTask.new(:unit) do |t| 19 | t.rspec_opts = '--color --format progress' 20 | end 21 | 22 | require 'kitchen' 23 | desc 'Run Test Kitchen integration tests' 24 | task :integration do 25 | Kitchen.logger = Kitchen.default_file_logger 26 | Kitchen::Config.new.instances.each do |instance| 27 | instance.test(:always) 28 | end 29 | end 30 | 31 | require 'stove/rake_task' 32 | Stove::RakeTask.new 33 | 34 | # We cannot run Test Kitchen on Travis CI yet... 35 | namespace :travis do 36 | desc 'Run tests on Travis' 37 | task ci: ['style', 'unit'] 38 | end 39 | 40 | # The default rake task should just run it all 41 | task default: ['style', 'unit', 'integration'] 42 | -------------------------------------------------------------------------------- /libraries/matchers.rb: -------------------------------------------------------------------------------- 1 | if defined?(ChefSpec) 2 | def add_magic_shell_alias(name) 3 | ChefSpec::Matchers::ResourceMatcher.new(:magic_shell_alias, :add, name) 4 | end 5 | 6 | def remove_magic_shell_alias(name) 7 | ChefSpec::Matchers::ResourceMatcher.new(:magic_shell_alias, :remove, name) 8 | end 9 | 10 | def add_magic_shell_environment(name) 11 | ChefSpec::Matchers::ResourceMatcher.new(:magic_shell_environment, :add, name) 12 | end 13 | 14 | def remove_magic_shell_environment(name) 15 | ChefSpec::Matchers::ResourceMatcher.new(:magic_shell_environment, :remove, name) 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /metadata.rb: -------------------------------------------------------------------------------- 1 | maintainer 'CustomInk, LLC' 2 | name 'magic_shell' 3 | maintainer_email 'webops@customink.com' 4 | license 'Apache 2.0' 5 | description 'Creates system-global environment variables and shell command aliases' 6 | long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) 7 | version '1.0.1' 8 | -------------------------------------------------------------------------------- /providers/alias.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Cookbook Name:: magic_shell 3 | # Provider:: alias 4 | # 5 | # Author:: Nathen Harvey 6 | # Author:: Seth Vargo 7 | # 8 | # Copyright 2012-2014, CustomInk, LLC. 9 | # 10 | # Licensed under the Apache License, Version 2.0 (the "License"); 11 | # you may not use this file except in compliance with the License. 12 | # You may obtain a copy of the License at 13 | # 14 | # http://www.apache.org/licenses/LICENSE-2.0 15 | # 16 | # Unless required by applicable law or agreed to in writing, software 17 | # distributed under the License is distributed on an "AS IS" BASIS, 18 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | # See the License for the specific language governing permissions and 20 | # limitations under the License. 21 | # 22 | 23 | # 24 | # Delegate update actions to inline resources 25 | # 26 | use_inline_resources if defined?(use_inline_resources) 27 | 28 | # 29 | # This provider supports why-run mode. 30 | # 31 | def whyrun_supported? 32 | true 33 | end 34 | 35 | # 36 | # Create a file entry for the given alias. 37 | # 38 | action :add do 39 | file = Chef::Resource::File.new(destination, run_context) 40 | file.owner('root') 41 | file.group('root') 42 | file.mode('0755') 43 | file.content(<<-EOH.gsub(/^ {8}/, '')) 44 | # 45 | # This file was generated by Chef for #{node['fqdn']} 46 | # Do NOT modify this file by hand! 47 | # 48 | 49 | alias #{new_resource.alias_name}="#{new_resource.command}" 50 | EOH 51 | file.run_action(:create) 52 | end 53 | 54 | # 55 | # Delete the file entry for the given alias. 56 | # 57 | action :remove do 58 | file = Chef::Resource::File.new(destination, run_context) 59 | file.run_action(:delete) 60 | end 61 | 62 | def destination 63 | "/etc/profile.d/#{filename}.sh" 64 | end 65 | 66 | def filename 67 | new_resource.alias_name.to_s.gsub(/\s/, '_') 68 | end 69 | -------------------------------------------------------------------------------- /providers/environment.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Cookbook Name:: magic_shell 3 | # Provider:: environment 4 | # 5 | # Author:: Nathen Harvey 6 | # Author:: Seth Vargo 7 | # 8 | # Copyright 2012-2014, CustomInk, LLC. 9 | # 10 | # Licensed under the Apache License, Version 2.0 (the "License"); 11 | # you may not use this file except in compliance with the License. 12 | # You may obtain a copy of the License at 13 | # 14 | # http://www.apache.org/licenses/LICENSE-2.0 15 | # 16 | # Unless required by applicable law or agreed to in writing, software 17 | # distributed under the License is distributed on an "AS IS" BASIS, 18 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | # See the License for the specific language governing permissions and 20 | # limitations under the License. 21 | # 22 | 23 | # 24 | # Delegate update actions to inline resources 25 | # 26 | use_inline_resources if defined?(use_inline_resources) 27 | 28 | # 29 | # This provider supports why-run mode. 30 | # 31 | def whyrun_supported? 32 | true 33 | end 34 | 35 | # 36 | # Create a file entry for the given environment. 37 | # 38 | action :add do 39 | file = Chef::Resource::File.new(destination, run_context) 40 | file.owner(new_resource.owner) 41 | file.group(new_resource.group) 42 | file.mode(new_resource.mode) 43 | file.sensitive(new_resource.sensitive) 44 | file.content(<<-EOH.gsub(/^ {8}/, '')) 45 | # 46 | # This file was generated by Chef for #{node['fqdn']} 47 | # Do NOT modify this file by hand! 48 | # 49 | 50 | export #{new_resource.environment_variable}="#{new_resource.value}" 51 | EOH 52 | file.run_action(:create) 53 | end 54 | 55 | # 56 | # 57 | # 58 | action :remove do 59 | file = Chef::Resource::File.new(destination, run_context) 60 | file.run_action(:delete) 61 | end 62 | 63 | def destination 64 | "#{new_resource.destination}/#{filename}.sh" 65 | end 66 | 67 | def filename 68 | new_resource.environment_variable.to_s.gsub(/\s/, '_') 69 | end 70 | -------------------------------------------------------------------------------- /resources/alias.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Cookbook Name:: magic_shell 3 | # Resource:: alias 4 | # 5 | # Author:: Nathen Harvey 6 | # Author:: Seth Vargo 7 | # 8 | # Copyright 2012-2014, CustomInk, LLC. 9 | # 10 | # Licensed under the Apache License, Version 2.0 (the "License"); 11 | # you may not use this file except in compliance with the License. 12 | # You may obtain a copy of the License at 13 | # 14 | # http://www.apache.org/licenses/LICENSE-2.0 15 | # 16 | # Unless required by applicable law or agreed to in writing, software 17 | # distributed under the License is distributed on an "AS IS" BASIS, 18 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | # See the License for the specific language governing permissions and 20 | # limitations under the License. 21 | # 22 | 23 | actions :add, :remove 24 | default_action :add 25 | 26 | attribute :alias_name, kind_of: String, name_attribute: true 27 | attribute :command, kind_of: String 28 | -------------------------------------------------------------------------------- /resources/environment.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Cookbook Name:: magic_shell 3 | # Resource:: environment 4 | # 5 | # Author:: Nathen Harvey 6 | # Author:: Seth Vargo 7 | # 8 | # Copyright 2012-2014, CustomInk, LLC. 9 | # 10 | # Licensed under the Apache License, Version 2.0 (the "License"); 11 | # you may not use this file except in compliance with the License. 12 | # You may obtain a copy of the License at 13 | # 14 | # http://www.apache.org/licenses/LICENSE-2.0 15 | # 16 | # Unless required by applicable law or agreed to in writing, software 17 | # distributed under the License is distributed on an "AS IS" BASIS, 18 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | # See the License for the specific language governing permissions and 20 | # limitations under the License. 21 | # 22 | 23 | actions :add, :remove 24 | default_action :add 25 | 26 | attribute :environment_variable, kind_of: String, name_attribute: true 27 | attribute :value, kind_of: String 28 | attribute :owner, kind_of: String, default: 'root' 29 | attribute :group, kind_of: String, default: 'root' 30 | attribute :mode, kind_of: String, default: '0644' 31 | attribute :destination, kind_of: String, default: '/etc/profile.d' 32 | attribute :sensitive, kind_of: [ TrueClass, FalseClass ], default: false 33 | -------------------------------------------------------------------------------- /spec/providers/alias_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'magic_shell_alias' do 4 | let(:chef_run) { ChefSpec::Runner.new } 5 | 6 | it 'adds a new magic_shell_alias' do 7 | chef_run.converge('magic_shell_alias::add') 8 | expect(chef_run).to add_magic_shell_alias('h').with(command: 'cd ~') 9 | end 10 | 11 | it 'removes the magic_shell_alias' do 12 | chef_run.converge('magic_shell_alias::remove') 13 | expect(chef_run).to remove_magic_shell_alias('h') 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/providers/environment_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'magic_shell_environment::add' do 4 | let(:chef_run) { ChefSpec::Runner.new } 5 | 6 | it 'adds a new magic_shell_environment' do 7 | chef_run.converge('magic_shell_environment::add') 8 | expect(chef_run).to add_magic_shell_environment('RAILS_ENV') 9 | .with(value: 'production') 10 | end 11 | 12 | it 'removes the magic_shell_environment' do 13 | chef_run.converge('magic_shell_environment::remove') 14 | expect(chef_run).to remove_magic_shell_environment('RAILS_ENV') 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'chefspec' 2 | require 'chefspec/berkshelf' 3 | 4 | RSpec.configure do |config| 5 | config.log_level = :fatal 6 | end 7 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/magic_shell_alias/metadata.rb: -------------------------------------------------------------------------------- 1 | name 'magic_shell_alias' 2 | depends 'magic_shell' 3 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/magic_shell_alias/recipes/add.rb: -------------------------------------------------------------------------------- 1 | magic_shell_alias 'h' do 2 | command 'cd ~' 3 | end 4 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/magic_shell_alias/recipes/remove.rb: -------------------------------------------------------------------------------- 1 | include_recipe 'magic_shell_alias::add' 2 | 3 | magic_shell_alias 'h' do 4 | action :remove 5 | end 6 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/magic_shell_environment/metadata.rb: -------------------------------------------------------------------------------- 1 | name 'magic_shell_environment' 2 | depends 'magic_shell' 3 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/magic_shell_environment/recipes/add.rb: -------------------------------------------------------------------------------- 1 | magic_shell_environment 'RAILS_ENV' do 2 | value 'production' 3 | end 4 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/magic_shell_environment/recipes/remove.rb: -------------------------------------------------------------------------------- 1 | include_recipe 'magic_shell_environment::add' 2 | 3 | magic_shell_environment 'RAILS_ENV' do 4 | action :remove 5 | end 6 | -------------------------------------------------------------------------------- /test/integration/magic_shell_alias_add/serverspec/assert_added_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative '../../../kitchen/data/spec_helper' 2 | 3 | describe file('/etc/profile.d/h.sh') do 4 | it { should be_file } 5 | its(:content) { should include('alias h="cd ~"') } 6 | end 7 | -------------------------------------------------------------------------------- /test/integration/magic_shell_alias_remove/serverspec/assert_removed_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative '../../../kitchen/data/spec_helper' 2 | 3 | describe file('/etc/profile.d/h.sh') do 4 | it { should_not be_file } 5 | end 6 | -------------------------------------------------------------------------------- /test/integration/magic_shell_environment_add/serverspec/assert_added_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative '../../../kitchen/data/spec_helper' 2 | 3 | describe file('/etc/profile.d/RAILS_ENV.sh') do 4 | it { should be_file } 5 | its(:content) { should include('export RAILS_ENV="production"') } 6 | end 7 | -------------------------------------------------------------------------------- /test/integration/magic_shell_environment_remove/serverspec/assert_removed_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative '../../../kitchen/data/spec_helper' 2 | 3 | describe file('/etc/profile.d/RAILS_ENV.sh') do 4 | it { should_not be_file } 5 | end 6 | -------------------------------------------------------------------------------- /test/shared/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'serverspec' 2 | include Serverspec::Helper::Exec 3 | include Serverspec::Helper::DetectOS 4 | 5 | RSpec.configure do |config| 6 | config.before(:all) do 7 | config.os = backend(Serverspec::Commands::Base).check_os 8 | end 9 | end 10 | --------------------------------------------------------------------------------