snappconfig 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +159 -0
- data/Rakefile +1 -0
- data/lib/generators/snappconfig/install/install_generator.rb +27 -0
- data/lib/generators/snappconfig/install/templates/application.secrets.yml +2 -0
- data/lib/generators/snappconfig/install/templates/application.yml +3 -0
- data/lib/snappconfig.rb +43 -0
- data/lib/snappconfig/railtie.rb +61 -0
- data/lib/snappconfig/tasks.rake +15 -0
- data/snappconfig.gemspec +22 -0
- metadata +83 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 82216d73ae7c53a02e8d0572eab2ca2e0790ca94
|
4
|
+
data.tar.gz: f0980a18c83716f5e42468c02065093e73c5c68d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 77ceddc54748e10f4c3c11c56cb56921312c9b99ddded6fd70ee231710cd89ffe52817a3dca93023cecdd5f530bc11c287683b009d19ada9d8dc4b16f3b8f86d
|
7
|
+
data.tar.gz: b7324b3ea3346d24967a089e3775534d2260886e7d154003819c73d5cbe32885651f31f20abe78e551e774c8443045549637e67fe83b1c6b1100e7fe0443a344
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Yarin Kessler
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
# Snappconfig
|
2
|
+
|
3
|
+
Smarter Rails configuration that works with Heroku. Here's why it rocks:
|
4
|
+
|
5
|
+
- **It's Simple**. There's no setup code. Just **add some YAML** and you're ready to roll.
|
6
|
+
- It supports **nested values and lists**. Use the data structures you want and access them with standard hash notation (e.g. `CONFIG[:this][:that]`)
|
7
|
+
- It promotes **secure best practices** that keep your secrets out of source control.
|
8
|
+
- It lets you write to a nestable `CONFIG` hash *or* to `ENV` variables- we don’t tell you how to live.
|
9
|
+
- It's **Heroku-friendly**.
|
10
|
+
- It's based on Ryan Bates’ excellent [Railscast](http://railscasts.com/episodes/85-yaml-configuration-revised) and inspired by [Figaro](https://github.com/laserlemon/figaro).
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
|
15
|
+
|
16
|
+
**1)** Add it to your Gemfile and run `bundle` to install
|
17
|
+
|
18
|
+
gem 'snappconfig'
|
19
|
+
|
20
|
+
**2)** Use the generator to create config files (optional):
|
21
|
+
|
22
|
+
$ rails generate snappconfig:install
|
23
|
+
|
24
|
+
This will create:
|
25
|
+
|
26
|
+
- A default config file at `config/application.yml`
|
27
|
+
- A git-ignored config file for secrets at `config/application.secrets.yml`
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
## Usage
|
33
|
+
|
34
|
+
To access config values, just use standard hash notation:
|
35
|
+
|
36
|
+
token = CONFIG[:secret_token]
|
37
|
+
stripe_secret = CONFIG[:stripe][:secret_key]
|
38
|
+
|
39
|
+
Or if you wrote values to **ENV**, get them the way you normally would:
|
40
|
+
|
41
|
+
token = ENV['SECRET_TOKEN']
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
## YAML file examples
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
####Environment specfic (with defaults)
|
50
|
+
mailer_host: "localhost:3000"
|
51
|
+
development:
|
52
|
+
mailer_host: "localhost:3000"
|
53
|
+
test:
|
54
|
+
mailer_host: "test.local"
|
55
|
+
production:
|
56
|
+
mailer_host: "blog.example.com"
|
57
|
+
( **NOTE:** Default values can also be put under a 'defaults' group key. )
|
58
|
+
|
59
|
+
####Nested values:
|
60
|
+
stripe:
|
61
|
+
publishable_key: 5883eeb3cd43cee52585
|
62
|
+
secret_key: 0df20bf20903c4404968
|
63
|
+
|
64
|
+
development:
|
65
|
+
stripe:
|
66
|
+
publishable_key: 5883eeb3cd43cee52585
|
67
|
+
secret_key: 0df20bf20903c4404968
|
68
|
+
production:
|
69
|
+
stripe:
|
70
|
+
publishable_key: e753e42725fe43d3994a
|
71
|
+
secret_key: e8787290a07b1abecae9
|
72
|
+
|
73
|
+
####ENV values:
|
74
|
+
|
75
|
+
ENV:
|
76
|
+
BLOG_USERNAME: "admin"
|
77
|
+
BLOG_PASSWORD: "secret"
|
78
|
+
|
79
|
+
( **NOTE:** Values you put under an **"ENV"** key will be accessible in your app via `ENV['MY_VAR']` instead of `CONFIG[:my_var]`. These values can't be nested. )
|
80
|
+
|
81
|
+
|
82
|
+
|
83
|
+
## Multiple files
|
84
|
+
|
85
|
+
The number of config files you use is up to you. Stuff it all in a single file, or use multiple files for different versions, environments, etc.
|
86
|
+
|
87
|
+
Snappconfig will load all files in the `config/` directory that start with **"application."** and end with **".yml"**, and merge them down in alphabetical order (minus the file extension), with later values taking precedence.
|
88
|
+
|
89
|
+
For example, the following files would be processed in order:
|
90
|
+
|
91
|
+
- **application**.yml
|
92
|
+
- **application.2**.yml
|
93
|
+
- **application.test**.yml
|
94
|
+
|
95
|
+
|
96
|
+
<a name='best_practices'/>
|
97
|
+
##Best practices
|
98
|
+
|
99
|
+
|
100
|
+
There's nothing to stop you from putting all your configuration into a single `application.yml` file. However, best practices dictate that protected values like **passwords and tokens should not be stored in source control.**
|
101
|
+
|
102
|
+
An obvious solution would be to git-ignore the config file, but that approach has its problems. Not all values need to be secret, and without any config file developers won't know what values are expected or what the defaults should be.
|
103
|
+
|
104
|
+
###Separating your secrets
|
105
|
+
|
106
|
+
A better approach is to separate the secret values from the configuration values that are useful to share. Snappconfig makes this easy with multi-file support and the `_REQUIRED` keyword.
|
107
|
+
|
108
|
+
|
109
|
+
For instance, if we already have a mailer configuration that works for our app, there's no reason the bulk of it can't go into source control...
|
110
|
+
|
111
|
+
|
112
|
+
**application.yml:**
|
113
|
+
|
114
|
+
secret_token: _REQUIRED
|
115
|
+
mail:
|
116
|
+
delivery_method: :smtp
|
117
|
+
smtp_settings:
|
118
|
+
address: "smtp.gmail.com"
|
119
|
+
port: '587'
|
120
|
+
domain: 'baci.lindsaar.net'
|
121
|
+
user_name: 'acmesupport'
|
122
|
+
password: _REQUIRED
|
123
|
+
authentication: 'plain'
|
124
|
+
enable_starttls_auto: true
|
125
|
+
|
126
|
+
Using the `_REQUIRED` keyword, we indicate values we expect to be included in the configuration, even though they're not in this file.
|
127
|
+
|
128
|
+
We can then fulfill that obligation by using a git-ignored file that just stores our secrets:
|
129
|
+
|
130
|
+
**application.secrets.yml:**
|
131
|
+
|
132
|
+
secret_token: "024e1460a4fb8271e611d0f53811a382f1f6be121..."
|
133
|
+
mail:
|
134
|
+
smtp_settings:
|
135
|
+
password: 8675309
|
136
|
+
|
137
|
+
Now we've got a complete configuration without compromising anything!
|
138
|
+
|
139
|
+
The `_REQUIRED` keyword is really handy. You can use it to stub out an entire config file template. If any of the required values are not present at runtime Snappconfig will raise an error, ensuring you never go live without a complete configuration.
|
140
|
+
|
141
|
+
###Working with Heroku
|
142
|
+
|
143
|
+
The Heroku file system is read-only, so if you're git-ignoring your config files you won't be able to add them in manually.
|
144
|
+
|
145
|
+
But don't worry, Snappconfig's got you covered- just run the custom rake task:
|
146
|
+
|
147
|
+
$ rake snappconfig:heroku
|
148
|
+
|
149
|
+
and your app configuration will automatically be passed into Heroku for you. Slick!
|
150
|
+
|
151
|
+
|
152
|
+
|
153
|
+
## Contributing
|
154
|
+
|
155
|
+
1. Fork it
|
156
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
157
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
158
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
159
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Snappconfig
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
source_root File.expand_path("../templates", __FILE__)
|
5
|
+
|
6
|
+
# all public methods in here will be run in order
|
7
|
+
|
8
|
+
def create_configuration
|
9
|
+
template "application.yml", "config/application.yml"
|
10
|
+
template "application.secrets.yml", "config/application.secrets.yml"
|
11
|
+
end
|
12
|
+
|
13
|
+
def ignore_configuration
|
14
|
+
if File.exists?(".gitignore")
|
15
|
+
append_to_file(".gitignore") do
|
16
|
+
<<-EOF.strip_heredoc
|
17
|
+
|
18
|
+
# Ignore application secrets.
|
19
|
+
/config/application.secrets.yml
|
20
|
+
EOF
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/snappconfig.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require "snappconfig/railtie"
|
2
|
+
|
3
|
+
module Snappconfig
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def config_files
|
7
|
+
@config_files ||= Dir.entries(Rails.root.join("config").to_s).grep(/(^application)(\.|\..*\.)(yml$)/).sort { |x,y| x.chomp(".yml") <=> y.chomp(".yml") }
|
8
|
+
end
|
9
|
+
|
10
|
+
def merged_raw
|
11
|
+
if @merged_raw
|
12
|
+
return @merged_raw
|
13
|
+
else
|
14
|
+
@merged_raw = {}
|
15
|
+
config_files.each do | file_name |
|
16
|
+
file = ConfigFile.new(file_name)
|
17
|
+
@merged_raw.deep_merge! file.raw
|
18
|
+
end
|
19
|
+
return @merged_raw
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class ConfigFile
|
24
|
+
|
25
|
+
def initialize(name)
|
26
|
+
@name = name
|
27
|
+
end
|
28
|
+
|
29
|
+
def raw
|
30
|
+
@raw ||= yaml && YAML.load(yaml) || {}
|
31
|
+
end
|
32
|
+
|
33
|
+
def yaml
|
34
|
+
@yaml ||= File.exist?(path) ? ERB.new(File.read(path)).result : nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def path
|
38
|
+
@path ||= Rails.root.join("config", @name)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require "rails"
|
2
|
+
|
3
|
+
CONFIG = {}
|
4
|
+
|
5
|
+
module Snappconfig
|
6
|
+
class Railtie < ::Rails::Railtie
|
7
|
+
|
8
|
+
config.before_configuration do
|
9
|
+
|
10
|
+
# Look for CONFIG file in ENV (For Heroku) or else load from file system:
|
11
|
+
appconfig = ENV['CONFIG'] ? YAML.load(ENV['CONFIG']) : Snappconfig.merged_raw
|
12
|
+
|
13
|
+
appconfig.deep_merge! appconfig.fetch('defaults', {})
|
14
|
+
appconfig.deep_merge! appconfig.fetch(Rails.env, {})
|
15
|
+
|
16
|
+
check_required(appconfig)
|
17
|
+
|
18
|
+
# Assign ENV values...
|
19
|
+
if appconfig.has_key?('ENV')
|
20
|
+
appconfig['ENV'].each do |key, value|
|
21
|
+
ENV[key] = value.to_s unless value.kind_of? Hash
|
22
|
+
end
|
23
|
+
# ... and clear ENV values from CONFIG so we don't have duplicate data:
|
24
|
+
appconfig.delete('ENV')
|
25
|
+
appconfig.each do |key,value|
|
26
|
+
value.delete('ENV') if value.is_a?(Hash) && value.has_key?('ENV')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
appconfig = recursively_symbolize_keys(appconfig)
|
31
|
+
CONFIG.merge! appconfig
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
rake_tasks do
|
36
|
+
load "snappconfig/tasks.rake"
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def check_required(hash)
|
42
|
+
hash.each_pair do |key,value|
|
43
|
+
if value == '_REQUIRED'
|
44
|
+
raise "The configuration value #{key} is required but was not supplied. Check your application.yml file(s)."
|
45
|
+
elsif value.is_a?(Hash)
|
46
|
+
check_required(value)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def recursively_symbolize_keys(hash)
|
52
|
+
sym_hash = {}
|
53
|
+
hash.each_pair do |key,value|
|
54
|
+
hash[key] = value.is_a?(Hash) ? recursively_symbolize_keys(value) : value
|
55
|
+
sym_hash[(key.to_sym rescue key) || key] = hash[key]
|
56
|
+
end
|
57
|
+
sym_hash
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "shellwords"
|
2
|
+
|
3
|
+
namespace :snappconfig do
|
4
|
+
|
5
|
+
task :heroku, [:app] => :environment do
|
6
|
+
puts "Passing application configuration to Heroku..."
|
7
|
+
merged_yaml = Snappconfig.merged_raw.to_yaml
|
8
|
+
shell_yaml = Shellwords.escape(merged_yaml)
|
9
|
+
puts `heroku config:set CONFIG=#{shell_yaml}`
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
|
data/snappconfig.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "snappconfig"
|
7
|
+
spec.version = "0.0.1"
|
8
|
+
spec.authors = ["Yarin Kessler"]
|
9
|
+
spec.email = "ykessler@appgrinders.com"
|
10
|
+
spec.summary = %q{Smarter Rails configuration with YAML}
|
11
|
+
spec.description = %q{Smarter, Heroku-friendly Rails configuration using YAML}
|
12
|
+
spec.homepage = "https://github.com/ykessler/snappconfig"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
21
|
+
spec.add_development_dependency "rake"
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: snappconfig
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Yarin Kessler
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-09-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: Smarter, Heroku-friendly Rails configuration using YAML
|
42
|
+
email: ykessler@appgrinders.com
|
43
|
+
executables: []
|
44
|
+
extensions: []
|
45
|
+
extra_rdoc_files: []
|
46
|
+
files:
|
47
|
+
- .gitignore
|
48
|
+
- Gemfile
|
49
|
+
- LICENSE.txt
|
50
|
+
- README.md
|
51
|
+
- Rakefile
|
52
|
+
- lib/generators/snappconfig/install/install_generator.rb
|
53
|
+
- lib/generators/snappconfig/install/templates/application.secrets.yml
|
54
|
+
- lib/generators/snappconfig/install/templates/application.yml
|
55
|
+
- lib/snappconfig.rb
|
56
|
+
- lib/snappconfig/railtie.rb
|
57
|
+
- lib/snappconfig/tasks.rake
|
58
|
+
- snappconfig.gemspec
|
59
|
+
homepage: https://github.com/ykessler/snappconfig
|
60
|
+
licenses:
|
61
|
+
- MIT
|
62
|
+
metadata: {}
|
63
|
+
post_install_message:
|
64
|
+
rdoc_options: []
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - '>='
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
requirements: []
|
78
|
+
rubyforge_project:
|
79
|
+
rubygems_version: 2.0.3
|
80
|
+
signing_key:
|
81
|
+
specification_version: 4
|
82
|
+
summary: Smarter Rails configuration with YAML
|
83
|
+
test_files: []
|