env_lint 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/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +104 -0
- data/Rakefile +1 -0
- data/env_lint.gemspec +26 -0
- data/lib/env_lint/capistrano.rb +51 -0
- data/lib/env_lint/dot_env_file.rb +48 -0
- data/lib/env_lint/dot_env_parser.rb +39 -0
- data/lib/env_lint/env_key_parser.rb +11 -0
- data/lib/env_lint/errors.rb +62 -0
- data/lib/env_lint/formatter.rb +49 -0
- data/lib/env_lint/linted_env.rb +29 -0
- data/lib/env_lint/tasks.rb +21 -0
- data/lib/env_lint/variable.rb +5 -0
- data/lib/env_lint/version.rb +3 -0
- data/lib/env_lint.rb +24 -0
- data/spec/env_lint/capistrano_spec.rb +94 -0
- data/spec/env_lint/dot_env_file_spec.rb +73 -0
- data/spec/env_lint/dot_env_parser_spec.rb +105 -0
- data/spec/env_lint/env_key_parser_spec.rb +36 -0
- data/spec/env_lint/linted_env_spec.rb +85 -0
- data/spec/integration_spec.rb +109 -0
- data/spec/spec_helper.rb +5 -0
- metadata +146 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7074acbb267701af05f8e2f5307fb5d8f563a1dc
|
4
|
+
data.tar.gz: 1f07d11602f9e8230159f83a0719b3cfdb503047
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f1895359dbf17fca012f7ed52ff250ba0ea60b0edfd493691aabbf7b424f4d209d4b8d07c747a9b91e856f6e30f8b478c6fc07462f1592e6ba0a5c720226ae32
|
7
|
+
data.tar.gz: 564fa51150c32279cfcdc4fc965dd0e6b72c1c90d75b9c8ec33fe516394cb8c26fce7034c39d86446c24830275d624689ca4b6caf9ed4c9253df15b2add49573
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Tim Fischbach
|
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,104 @@
|
|
1
|
+
# Env Lint
|
2
|
+
|
3
|
+
<img src="https://travis-ci.org/tf/env_lint.png" data-bindattr-466="466" title="Build Status Images">
|
4
|
+
|
5
|
+
Check environment variables accoring to a `.env.example` file.
|
6
|
+
|
7
|
+
* Avoid spelling errors in variable names in your code or on the
|
8
|
+
command line
|
9
|
+
* Ensure all relevant environment variables are described in the
|
10
|
+
`.env.example` file.
|
11
|
+
* Ensure all required environment variables are configured before
|
12
|
+
deploying a new version of an app
|
13
|
+
* Ease setting up a new development machine
|
14
|
+
|
15
|
+
# Status
|
16
|
+
|
17
|
+
Only tested with [recap](https://github.com/tomafro/recap) capistrano
|
18
|
+
tasks.
|
19
|
+
|
20
|
+
## Installation
|
21
|
+
|
22
|
+
Add this line to your application's Gemfile:
|
23
|
+
|
24
|
+
gem 'env_lint'
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
|
28
|
+
Define a `.env.example` file:
|
29
|
+
|
30
|
+
# Explain each variable in comments like this one
|
31
|
+
APP_NAME=my_app
|
32
|
+
|
33
|
+
# Comments are also recognized if they span multiple
|
34
|
+
# lines
|
35
|
+
FEATURE=true
|
36
|
+
|
37
|
+
# Optional variables
|
38
|
+
# OPTIONAL_VAR="set me if you like"
|
39
|
+
|
40
|
+
### Rake Task
|
41
|
+
|
42
|
+
Require it in your `Rakefile`:
|
43
|
+
|
44
|
+
require 'env_lint/tasks'
|
45
|
+
|
46
|
+
Now you can check your environment:
|
47
|
+
|
48
|
+
$ rake env:lint
|
49
|
+
=> Complains if non optional variables are missing
|
50
|
+
|
51
|
+
If special steps are needed
|
52
|
+
|
53
|
+
### Capistrano Task
|
54
|
+
|
55
|
+
Require it in your `Capfile`:
|
56
|
+
|
57
|
+
require 'env_lint/capistrano'
|
58
|
+
|
59
|
+
Now you can check your servers:
|
60
|
+
|
61
|
+
$ cap env:lint
|
62
|
+
=> Complains if non optional variables are missing
|
63
|
+
|
64
|
+
You might want to lint the environment automatically before each
|
65
|
+
deploy.
|
66
|
+
|
67
|
+
before 'deploy', 'env:lint'
|
68
|
+
|
69
|
+
Lint variable names before setting them:
|
70
|
+
|
71
|
+
before 'env:set', 'env:lint_args'
|
72
|
+
|
73
|
+
$ cap env:set APP_NAME=myapp
|
74
|
+
=> Complains if APP_NAME is defined
|
75
|
+
|
76
|
+
### Lint at Runtime
|
77
|
+
|
78
|
+
Access ENV through a `LintedEnv`:
|
79
|
+
|
80
|
+
require 'env_lint'
|
81
|
+
|
82
|
+
class MyApp
|
83
|
+
LINTED_ENV = EnvLint::LintedEnv.from_file('.env.example')
|
84
|
+
|
85
|
+
def self.env
|
86
|
+
LINTED_ENV
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
Accessing env variables:
|
91
|
+
|
92
|
+
# Ensures APP_NAME is defined in .env.example
|
93
|
+
MyApp.env.fetch(:app_name, 'App name')
|
94
|
+
|
95
|
+
# Ensures APP_NAME is non optional in .env.example
|
96
|
+
MyApp.env.fetch(:app_name)
|
97
|
+
|
98
|
+
## Contributing
|
99
|
+
|
100
|
+
1. Fork it
|
101
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
102
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
103
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
104
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/env_lint.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'env_lint/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'env_lint'
|
8
|
+
spec.version = EnvLint::VERSION
|
9
|
+
spec.authors = ['Tim Fischbach']
|
10
|
+
spec.email = ['mail@timfischbach.de']
|
11
|
+
spec.summary = 'Lint the environment according by .env.example'
|
12
|
+
spec.homepage = ''
|
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_runtime_dependency 'formatador'
|
21
|
+
spec.add_runtime_dependency 'capistrano', '~> 2.9'
|
22
|
+
|
23
|
+
spec.add_development_dependency 'rspec', '3.0.0.beta1'
|
24
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
25
|
+
spec.add_development_dependency 'rake'
|
26
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'env_lint'
|
2
|
+
require 'capistrano'
|
3
|
+
|
4
|
+
module EnvLint
|
5
|
+
module Capistrano
|
6
|
+
def self.load_into(config, formatter)
|
7
|
+
config.load do
|
8
|
+
set(:env_definition_file) { '.env.example' }
|
9
|
+
set(:env_probe_command) { "su - #{application_user} -c 'export'" }
|
10
|
+
|
11
|
+
namespace :env do
|
12
|
+
desc 'Check that every non optional ENV variable is defined.'
|
13
|
+
task :lint do
|
14
|
+
begin
|
15
|
+
EnvLint.verify_export_output(env_definition_file, capture(env_probe_command, via: :sudo))
|
16
|
+
formatter.ok('env looks ok')
|
17
|
+
rescue EnvLint::MissingVariables => e
|
18
|
+
formatter.missing_variables(e.dot_env_file, e.missing_variables)
|
19
|
+
abort
|
20
|
+
rescue EnvLint::Error => e
|
21
|
+
formatter.error(e.message)
|
22
|
+
abort
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
desc 'Lint args passed to command.'
|
27
|
+
task :lint_args do
|
28
|
+
begin
|
29
|
+
EnvLint.verify_args(env_definition_file, env_args)
|
30
|
+
rescue EnvLint::UnknownVariables => e
|
31
|
+
formatter.unknown_variables(e.dot_env_file, e.unknown_variables)
|
32
|
+
abort
|
33
|
+
rescue EnvLint::Error => e
|
34
|
+
formatter.error(e.message)
|
35
|
+
abort
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def env_args
|
40
|
+
ARGV[1..-1]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
if Capistrano::Configuration.instance
|
49
|
+
EnvLint::Capistrano.load_into(Capistrano::Configuration.instance(:must_exist),
|
50
|
+
Formatter.new)
|
51
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module EnvLint
|
2
|
+
class DotEnvFile
|
3
|
+
attr_reader :name, :variables
|
4
|
+
|
5
|
+
def initialize(name, variables)
|
6
|
+
@name = name
|
7
|
+
@variables = variables
|
8
|
+
|
9
|
+
@variables_by_name = variables.each_with_object({}) do |variable, hash|
|
10
|
+
hash[variable.name] = variable
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def find_variable(name)
|
15
|
+
@variables_by_name[name]
|
16
|
+
end
|
17
|
+
|
18
|
+
def verify_no_missing(variable_names)
|
19
|
+
find_missing(variable_names).tap do |missing_variables|
|
20
|
+
raise(MissingVariables.new(self, missing_variables)) if missing_variables.any?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def verify_no_unknown(variable_names)
|
25
|
+
find_unknown(variable_names).tap do |unknown_names|
|
26
|
+
raise(UnknownVariables.new(self, unknown_names)) if unknown_names.any?
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.from_file(file_name)
|
31
|
+
new(file_name, DotEnvParser.new.parse(File.read(file_name)))
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def find_missing(variable_names)
|
37
|
+
@variables.find_all do |variable|
|
38
|
+
!variable.optional? && !variable_names.include?(variable.name)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def find_unknown(variable_names)
|
43
|
+
variable_names.find_all do |name|
|
44
|
+
!@variables_by_name.key?(name)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module EnvLint
|
2
|
+
class DotEnvParser
|
3
|
+
def parse(text)
|
4
|
+
comment_lines = []
|
5
|
+
|
6
|
+
variables = text.lines.each_with_object([]) do |line, result|
|
7
|
+
if match = line.strip.match(ASSIGNMENT)
|
8
|
+
optional, name, value = match.captures
|
9
|
+
value ||= ''
|
10
|
+
value = value.strip.sub(/\A(['"])(.*)\1\z/, '\2')
|
11
|
+
|
12
|
+
result << Variable.new(name, value, !!optional, comment_lines * "\n")
|
13
|
+
comment_lines = []
|
14
|
+
elsif match = line.strip.match(COMMENT)
|
15
|
+
comment_lines << match.captures.first
|
16
|
+
elsif line.strip.empty?
|
17
|
+
comment_lines = []
|
18
|
+
else
|
19
|
+
raise(UnrecognizedDotEnvLine.new(line))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
variables
|
24
|
+
end
|
25
|
+
|
26
|
+
COMMENT = /\A#\s*(.*)\z/
|
27
|
+
|
28
|
+
ASSIGNMENT = /
|
29
|
+
\A
|
30
|
+
(\#\s*)? # optional variable marker
|
31
|
+
([\w\.]+) # key
|
32
|
+
= # separator
|
33
|
+
( # optional value begin
|
34
|
+
[^#\n]+ # unquoted value
|
35
|
+
)? # value end
|
36
|
+
\z
|
37
|
+
/x
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module EnvLint
|
2
|
+
class EnvKeyParser
|
3
|
+
def parse_args(args)
|
4
|
+
args.map { |arg| arg.split('=').first if arg.include?('=') }.compact
|
5
|
+
end
|
6
|
+
|
7
|
+
def parse_export_output(text)
|
8
|
+
parse_args(text.split(/[\n\r]/).map { |line| line.gsub('declare -x', '').strip })
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module EnvLint
|
2
|
+
class Error < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
class UnrecognizedDotEnvLine < Error
|
6
|
+
attr_reader :line
|
7
|
+
|
8
|
+
def initialize(line)
|
9
|
+
super("Unrecognized line in dot env file: '#{line}'")
|
10
|
+
@line = line
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class VariableError < StandardError
|
15
|
+
attr_reader :variable_name
|
16
|
+
|
17
|
+
def initialize(variable_name, message)
|
18
|
+
super(message)
|
19
|
+
@variable_name = variable_name
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class UnknownVariable < VariableError
|
24
|
+
def initialize(variable_name)
|
25
|
+
super(variable_name, "Unknown variable #{variable_name}.")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class DefaultValueRequiredForOptionalVariable < VariableError
|
30
|
+
def initialize(variable_name)
|
31
|
+
super(variable_name, "Non optional variable #{variable_name} used without default value.")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class MissingVariable < VariableError
|
36
|
+
def initialize(variable_name)
|
37
|
+
super(variable_name, "Missing variable #{variable_name}. Check your .env file")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class MissingVariables < Error
|
42
|
+
attr_reader :dot_env_file, :missing_variables
|
43
|
+
|
44
|
+
def initialize(dot_env_file, missing_variables)
|
45
|
+
@dot_env_file = dot_env_file
|
46
|
+
@missing_variables = missing_variables
|
47
|
+
|
48
|
+
super("Missing variables #{missing_variables * ', '}.")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class UnknownVariables < Error
|
53
|
+
attr_reader :dot_env_file, :unknown_variables
|
54
|
+
|
55
|
+
def initialize(dot_env_file, unknown_variables)
|
56
|
+
@dot_env_file = dot_env_file
|
57
|
+
@unknown_variables = unknown_variables
|
58
|
+
|
59
|
+
super("Unknown variables #{unknown_variables * ', '}.")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'formatador'
|
2
|
+
|
3
|
+
module EnvLint
|
4
|
+
class Formatter
|
5
|
+
def initialize(out = Formatador)
|
6
|
+
@out = out
|
7
|
+
end
|
8
|
+
|
9
|
+
def missing_variables(dot_env_file, variables)
|
10
|
+
error("Missing env variables:\n")
|
11
|
+
|
12
|
+
variables.each do |variable|
|
13
|
+
@out.display_line(" [yellow]#{variable.name}[/] - #{variable.comment}")
|
14
|
+
end
|
15
|
+
|
16
|
+
new_line
|
17
|
+
info("Either set the variable or make it optional in the #{dot_env_file.name} file.")
|
18
|
+
end
|
19
|
+
|
20
|
+
def unknown_variables(dot_env_file, variable_names)
|
21
|
+
error("Unknown env variables:\n")
|
22
|
+
|
23
|
+
variable_names.each do |name|
|
24
|
+
@out.display_line(" [yellow]#{name}[/]")
|
25
|
+
end
|
26
|
+
|
27
|
+
new_line
|
28
|
+
info("Only variables descibred in #{dot_env_file.name} can be used.")
|
29
|
+
end
|
30
|
+
|
31
|
+
def error(message)
|
32
|
+
@out.display_line("* [red]#{message}[/]")
|
33
|
+
end
|
34
|
+
|
35
|
+
def ok(message)
|
36
|
+
@out.display_line("* [green]#{message}[/]")
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def info(message)
|
42
|
+
@out.display_line(" #{message}")
|
43
|
+
end
|
44
|
+
|
45
|
+
def new_line
|
46
|
+
@out.display_line('')
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module EnvLint
|
2
|
+
class LintedEnv
|
3
|
+
def initialize(env, dot_env_file)
|
4
|
+
@env = env
|
5
|
+
@dot_env_file = dot_env_file
|
6
|
+
end
|
7
|
+
|
8
|
+
def fetch(name, *args, &block)
|
9
|
+
name = name.to_s.upcase if name.is_a?(Symbol)
|
10
|
+
variable = @dot_env_file.find_variable(name)
|
11
|
+
|
12
|
+
raise(UnknownVariable.new(name)) unless variable
|
13
|
+
|
14
|
+
if variable.optional? && args.empty? && !block_given?
|
15
|
+
raise(DefaultValueRequiredForOptionalVariable.new(name))
|
16
|
+
end
|
17
|
+
|
18
|
+
block ||= lambda do |i|
|
19
|
+
args.any? ? args.first : raise(MissingVariable.new(name))
|
20
|
+
end
|
21
|
+
|
22
|
+
@env.fetch(name, &block)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.from_file(file_name)
|
26
|
+
new(ENV, DotEnvFile.from_file(file_name))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
namespace :env do
|
2
|
+
desc 'Ensure every non optional ENV variable is defined.'
|
3
|
+
task :lint => :load do
|
4
|
+
begin
|
5
|
+
EnvLint.verify_hash(env_definition_file, ENV)
|
6
|
+
EnvLint.formatter.ok('env looks ok')
|
7
|
+
rescue EnvLint::MissingVariables => e
|
8
|
+
EnvLint.formatter.missing_variables(e.dot_env_file, e.missing_variables)
|
9
|
+
abort
|
10
|
+
rescue EnvLint::Error => e
|
11
|
+
EnvLint.formatter.error(e.message)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
task :load do
|
16
|
+
end
|
17
|
+
|
18
|
+
def env_definition_file
|
19
|
+
ENV['DEFINITION'] || '.env.example'
|
20
|
+
end
|
21
|
+
end
|
data/lib/env_lint.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'env_lint/dot_env_file'
|
2
|
+
require 'env_lint/dot_env_parser'
|
3
|
+
require 'env_lint/formatter'
|
4
|
+
require 'env_lint/env_key_parser'
|
5
|
+
require 'env_lint/errors'
|
6
|
+
require 'env_lint/linted_env'
|
7
|
+
require 'env_lint/variable'
|
8
|
+
require 'env_lint/version'
|
9
|
+
|
10
|
+
module EnvLint
|
11
|
+
def self.verify_hash(env_definition_file, env)
|
12
|
+
DotEnvFile.from_file(env_definition_file).verify_no_missing(env.keys)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.verify_export_output(env_definition_file, export_output)
|
16
|
+
DotEnvFile.from_file(env_definition_file)
|
17
|
+
.verify_no_missing(EnvKeyParser.new.parse_export_output(export_output))
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.verify_args(env_definition_file, args)
|
21
|
+
DotEnvFile.from_file(env_definition_file)
|
22
|
+
.verify_no_unknown(EnvKeyParser.new.parse_args(args))
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'env_lint/capistrano'
|
3
|
+
|
4
|
+
module EnvLint
|
5
|
+
describe Capistrano do
|
6
|
+
let :config do
|
7
|
+
::Capistrano::Configuration.new
|
8
|
+
end
|
9
|
+
|
10
|
+
let :namespace do
|
11
|
+
config.env
|
12
|
+
end
|
13
|
+
|
14
|
+
let :formatter do
|
15
|
+
instance_double(Formatter, ok: true, missing_variables: true, unknown_variables: true, error: true)
|
16
|
+
end
|
17
|
+
|
18
|
+
before do
|
19
|
+
config.set(:application_user, 'myapp')
|
20
|
+
|
21
|
+
EnvLint::Capistrano.load_into(config, formatter)
|
22
|
+
end
|
23
|
+
|
24
|
+
describe 'env:lint' do
|
25
|
+
it 'calls verify_export_output with result of capute' do
|
26
|
+
config.set(:env_definition_file, '.env.example')
|
27
|
+
|
28
|
+
allow(namespace).to receive(:capture).and_return('declare -x APP=1')
|
29
|
+
expect(EnvLint).to receive(:verify_export_output).with('.env.example', 'declare -x APP=1')
|
30
|
+
|
31
|
+
config.find_and_execute_task('env:lint')
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'passes missing variables to formatter and aborts' do
|
35
|
+
dot_env_file = {}
|
36
|
+
variables = ['APP']
|
37
|
+
|
38
|
+
allow(namespace).to receive(:capture).and_return('declare -x APP=1')
|
39
|
+
allow(EnvLint).to receive(:verify_export_output).and_raise(MissingVariables.new(dot_env_file, variables))
|
40
|
+
expect(namespace).to receive(:abort)
|
41
|
+
expect(formatter).to receive(:missing_variables).with(dot_env_file, variables)
|
42
|
+
|
43
|
+
config.find_and_execute_task('env:lint')
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'passes error message to formatter and aborts' do
|
47
|
+
dot_env_file = {}
|
48
|
+
variables = ['APP']
|
49
|
+
|
50
|
+
allow(namespace).to receive(:capture).and_return('declare -x APP=1')
|
51
|
+
allow(EnvLint).to receive(:verify_export_output).and_raise(Error.new('message'))
|
52
|
+
expect(namespace).to receive(:abort)
|
53
|
+
expect(formatter).to receive(:error).with('message')
|
54
|
+
|
55
|
+
config.find_and_execute_task('env:lint')
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe 'env:lint_args' do
|
60
|
+
it 'calls verify_args with result of capute' do
|
61
|
+
config.set(:env_definition_file, '.env.example')
|
62
|
+
|
63
|
+
allow(namespace).to receive(:env_args).and_return(['APP=1'])
|
64
|
+
expect(EnvLint).to receive(:verify_args).with('.env.example', ['APP=1'])
|
65
|
+
|
66
|
+
config.find_and_execute_task('env:lint_args')
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'passes missing variables to formatter and aborts' do
|
70
|
+
dot_env_file = {}
|
71
|
+
variables = ['APP']
|
72
|
+
|
73
|
+
allow(namespace).to receive(:env_args).and_return(['APP=1'])
|
74
|
+
allow(EnvLint).to receive(:verify_args).and_raise(UnknownVariables.new(dot_env_file, variables))
|
75
|
+
expect(namespace).to receive(:abort)
|
76
|
+
expect(formatter).to receive(:unknown_variables).with(dot_env_file, variables)
|
77
|
+
|
78
|
+
config.find_and_execute_task('env:lint_args')
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'passes error message to formatter and aborts' do
|
82
|
+
dot_env_file = {}
|
83
|
+
variables = ['APP']
|
84
|
+
|
85
|
+
allow(namespace).to receive(:env_args).and_return(['APP=1'])
|
86
|
+
allow(EnvLint).to receive(:verify_args).and_raise(Error.new('message'))
|
87
|
+
expect(namespace).to receive(:abort)
|
88
|
+
expect(formatter).to receive(:error).with('message')
|
89
|
+
|
90
|
+
config.find_and_execute_task('env:lint_args')
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module EnvLint
|
4
|
+
describe DotEnvFile do
|
5
|
+
describe '#verify_no_missing' do
|
6
|
+
it 'passes if all non optional variables are present in the env' do
|
7
|
+
dot_env_file = DotEnvFile.new('.env.example', [Variable.new('APP')])
|
8
|
+
|
9
|
+
expect {
|
10
|
+
dot_env_file.verify_no_missing(['APP'])
|
11
|
+
}.not_to raise_error
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'raises an exception listing undefined non optional variables' do
|
15
|
+
dot_env_file = DotEnvFile.new('.env.example', [Variable.new('APP'), Variable.new('URL')])
|
16
|
+
|
17
|
+
expect {
|
18
|
+
dot_env_file.verify_no_missing(['APP'])
|
19
|
+
}.to raise_error(MissingVariables)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'lists undefined non optional variables in exception' do
|
23
|
+
dot_env_file = DotEnvFile.new('.env.example', [Variable.new('APP'), Variable.new('URL'), Variable.new('OTHER')])
|
24
|
+
|
25
|
+
begin
|
26
|
+
dot_env_file.verify_no_missing(['APP'])
|
27
|
+
rescue MissingVariables => e
|
28
|
+
expect(e.missing_variables.size).to eq(2)
|
29
|
+
expect(e.missing_variables.first.name).to eq('URL')
|
30
|
+
expect(e.missing_variables.last.name).to eq('OTHER')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'passes if optional variable is not defined' do
|
35
|
+
dot_env_file = DotEnvFile.new('.env.example', [Variable.new('APP', '', true)])
|
36
|
+
|
37
|
+
expect {
|
38
|
+
dot_env_file.verify_no_missing([''])
|
39
|
+
}.not_to raise_error
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#verfy_no_unknown' do
|
44
|
+
it 'passes if all variables of the env are known' do
|
45
|
+
dot_env_file = DotEnvFile.new('.env.example', [Variable.new('APP')])
|
46
|
+
|
47
|
+
expect {
|
48
|
+
dot_env_file.verify_no_unknown(['APP'])
|
49
|
+
}.not_to raise_error
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'raises an exception if a variable is unknown' do
|
53
|
+
dot_env_file = DotEnvFile.new('.env.example', [Variable.new('APP')])
|
54
|
+
|
55
|
+
expect {
|
56
|
+
dot_env_file.verify_no_unknown(['APP', 'UNKNOWN', 'OTHER'])
|
57
|
+
}.to raise_error(UnknownVariables)
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'lists unknown variables in exception' do
|
61
|
+
dot_env_file = DotEnvFile.new('.env.example', [Variable.new('APP')])
|
62
|
+
|
63
|
+
begin
|
64
|
+
dot_env_file.verify_no_unknown(['APP', 'UNKNOWN', 'OTHER'])
|
65
|
+
rescue UnknownVariables => e
|
66
|
+
expect(e.unknown_variables.size).to eq(2)
|
67
|
+
expect(e.unknown_variables.first).to eq('UNKNOWN')
|
68
|
+
expect(e.unknown_variables.last).to eq('OTHER')
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module EnvLint
|
4
|
+
describe DotEnvParser do
|
5
|
+
describe '#parse' do
|
6
|
+
it 'recognizes variables' do
|
7
|
+
variables = DotEnvParser.new.parse(<<-END)
|
8
|
+
APP=myapp
|
9
|
+
END
|
10
|
+
|
11
|
+
expect(variables.first.name).to eq('APP')
|
12
|
+
expect(variables.first.value).to eq('myapp')
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'recognizes double quoted values' do
|
16
|
+
variables = DotEnvParser.new.parse(<<-END)
|
17
|
+
APP="my app"
|
18
|
+
END
|
19
|
+
|
20
|
+
expect(variables.first.value).to eq('my app')
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'recognizes single quoted values' do
|
24
|
+
variables = DotEnvParser.new.parse(<<-END)
|
25
|
+
APP='my app'
|
26
|
+
END
|
27
|
+
|
28
|
+
expect(variables.first.value).to eq('my app')
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'handles empty assignments' do
|
32
|
+
variables = DotEnvParser.new.parse(<<-END)
|
33
|
+
APP=
|
34
|
+
END
|
35
|
+
|
36
|
+
expect(variables.first.value).to eq('')
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'ignores blank linkes' do
|
40
|
+
variables = DotEnvParser.new.parse(<<-END)
|
41
|
+
APP1=myapp
|
42
|
+
|
43
|
+
APP2=myapp
|
44
|
+
END
|
45
|
+
|
46
|
+
expect(variables.count).to eq(2)
|
47
|
+
expect(variables.first.name).to eq('APP1')
|
48
|
+
expect(variables.last.name).to eq('APP2')
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'recognizes optional variables' do
|
52
|
+
variables = DotEnvParser.new.parse(<<-END)
|
53
|
+
# APP=myapp
|
54
|
+
#OTHER=myapp
|
55
|
+
APP=myapp
|
56
|
+
END
|
57
|
+
|
58
|
+
expect(variables[0]).to be_optional
|
59
|
+
expect(variables[1]).to be_optional
|
60
|
+
expect(variables[2]).not_to be_optional
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'recognizes comments' do
|
64
|
+
variables = DotEnvParser.new.parse(<<-END)
|
65
|
+
# The name of the app
|
66
|
+
APP=myapp
|
67
|
+
END
|
68
|
+
|
69
|
+
expect(variables.first.comment).to eq('The name of the app')
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'recognizes multi line comments' do
|
73
|
+
variables = DotEnvParser.new.parse(<<-END)
|
74
|
+
# The name of the app
|
75
|
+
# and here the text goes on
|
76
|
+
APP=myapp
|
77
|
+
END
|
78
|
+
|
79
|
+
expect(variables.first.comment).to eq("The name of the app\nand here the text goes on")
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'starts new comment at blank line' do
|
83
|
+
variables = DotEnvParser.new.parse(<<-END)
|
84
|
+
# This is some header which is not related
|
85
|
+
# to the following variable
|
86
|
+
|
87
|
+
# This is the comment
|
88
|
+
APP=myapp
|
89
|
+
END
|
90
|
+
|
91
|
+
expect(variables.first.comment).to eq('This is the comment')
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'raises exception for unrecognized line' do
|
95
|
+
text = <<-END
|
96
|
+
what is this?
|
97
|
+
END
|
98
|
+
|
99
|
+
expect {
|
100
|
+
DotEnvParser.new.parse(text)
|
101
|
+
}.to raise_error(UnrecognizedDotEnvLine)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module EnvLint
|
4
|
+
describe EnvKeyParser do
|
5
|
+
describe '.parse_args' do
|
6
|
+
it 'recognizes assignments' do
|
7
|
+
parser = EnvKeyParser.new
|
8
|
+
|
9
|
+
keys = parser.parse_args(['APP=myname', 'NAME=test'])
|
10
|
+
|
11
|
+
expect(keys).to eq(['APP', 'NAME'])
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'ignores other args' do
|
15
|
+
parser = EnvKeyParser.new
|
16
|
+
|
17
|
+
keys = parser.parse_args(['env:set', 'APP=myname'])
|
18
|
+
|
19
|
+
expect(keys).to eq(['APP'])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '.parse_export_output' do
|
24
|
+
it 'recognizes assignments' do
|
25
|
+
parser = EnvKeyParser.new
|
26
|
+
|
27
|
+
keys = parser.parse_export_output(<<-END)
|
28
|
+
declare -x APP="myapp"
|
29
|
+
declare -x NAME="test"
|
30
|
+
END
|
31
|
+
|
32
|
+
expect(keys).to eq(['APP', 'NAME'])
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module EnvLint
|
4
|
+
describe LintedEnv do
|
5
|
+
describe '#fetch' do
|
6
|
+
it 'returns value from env for known variable' do
|
7
|
+
env = {'APP' => 'myapp'}
|
8
|
+
dot_env_file = DotEnvFile.new('.env.example', [Variable.new('APP')])
|
9
|
+
linted_env = LintedEnv.new(env, dot_env_file)
|
10
|
+
|
11
|
+
expect(linted_env.fetch('APP')).to eq('myapp')
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'translates symbols to uppercase strings' do
|
15
|
+
env = {'APP_NAME' => 'myapp'}
|
16
|
+
dot_env_file = DotEnvFile.new('.env.example', [Variable.new('APP_NAME')])
|
17
|
+
linted_env = LintedEnv.new(env, dot_env_file)
|
18
|
+
|
19
|
+
expect(linted_env.fetch(:app_name)).to eq('myapp')
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'raises exception for unknown variable' do
|
23
|
+
env = {'APP' => 'myapp'}
|
24
|
+
dot_env_file = DotEnvFile.new('.env.example', [])
|
25
|
+
linted_env = LintedEnv.new(env, dot_env_file)
|
26
|
+
|
27
|
+
expect {
|
28
|
+
linted_env.fetch('APP')
|
29
|
+
}.to raise_error(UnknownVariable)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'raises exception for undefined variable' do
|
33
|
+
env = {}
|
34
|
+
dot_env_file = DotEnvFile.new('.env.example', [Variable.new('APP')])
|
35
|
+
linted_env = LintedEnv.new(env, dot_env_file)
|
36
|
+
|
37
|
+
expect {
|
38
|
+
linted_env.fetch('APP')
|
39
|
+
}.to raise_error(MissingVariable)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'returns default value for undefined variable' do
|
43
|
+
env = {}
|
44
|
+
dot_env_file = DotEnvFile.new('.env.example', [Variable.new('APP')])
|
45
|
+
linted_env = LintedEnv.new(env, dot_env_file)
|
46
|
+
|
47
|
+
expect(linted_env.fetch('APP', 'default')).to eq('default')
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'returns default from block for undefined variable' do
|
51
|
+
env = {}
|
52
|
+
dot_env_file = DotEnvFile.new('.env.example', [Variable.new('APP')])
|
53
|
+
linted_env = LintedEnv.new(env, dot_env_file)
|
54
|
+
|
55
|
+
expect(linted_env.fetch('APP') { 'default' }).to eq('default')
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'raises exception if optional variable is used without default' do
|
59
|
+
env = {'APP' => 'myapp'}
|
60
|
+
dot_env_file = DotEnvFile.new('.env.example', [Variable.new('APP', '', true)])
|
61
|
+
linted_env = LintedEnv.new(env, dot_env_file)
|
62
|
+
|
63
|
+
expect {
|
64
|
+
linted_env.fetch('APP')
|
65
|
+
}.to raise_error(DefaultValueRequiredForOptionalVariable)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'allows to use optional variable with default value' do
|
69
|
+
env = {'APP' => 'myapp'}
|
70
|
+
dot_env_file = DotEnvFile.new('.env.example', [Variable.new('APP', '', true)])
|
71
|
+
linted_env = LintedEnv.new(env, dot_env_file)
|
72
|
+
|
73
|
+
expect(linted_env.fetch('APP', 'default')).to eq('myapp')
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'allows to use optional variable with block' do
|
77
|
+
env = {'APP' => 'myapp'}
|
78
|
+
dot_env_file = DotEnvFile.new('.env.example', [Variable.new('APP', '', true)])
|
79
|
+
linted_env = LintedEnv.new(env, dot_env_file)
|
80
|
+
|
81
|
+
expect(linted_env.fetch('APP') { 'block' }).to eq('myapp')
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
describe EnvLint do
|
5
|
+
SANDBOX_DIR = File.join(File.dirname(__FILE__), 'tmp')
|
6
|
+
|
7
|
+
around do |example|
|
8
|
+
clean_up_sandbox
|
9
|
+
in_sandbox { example.run }
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '.verify_hash' do
|
13
|
+
it 'passes when hash is complete' do
|
14
|
+
File.write('.env.example', <<-END)
|
15
|
+
APP=myapp
|
16
|
+
END
|
17
|
+
|
18
|
+
expect {
|
19
|
+
EnvLint.verify_hash('.env.example', {'APP' => 'some name'})
|
20
|
+
}.not_to raise_error
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'fails when hash is missing non optional variable' do
|
24
|
+
File.write('.env.example', <<-END)
|
25
|
+
APP=myapp
|
26
|
+
END
|
27
|
+
|
28
|
+
expect {
|
29
|
+
EnvLint.verify_hash('.env.example', {'OTHER' => 'other'})
|
30
|
+
}.to raise_error(EnvLint::MissingVariables)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '.verify_args' do
|
35
|
+
it 'passes when all args are known' do
|
36
|
+
File.write('.env.example', <<-END)
|
37
|
+
APP=myapp
|
38
|
+
OTHER=other
|
39
|
+
END
|
40
|
+
|
41
|
+
expect {
|
42
|
+
EnvLint.verify_args('.env.example', ['APP=name'])
|
43
|
+
}.not_to raise_error
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'fails when there are unknown args' do
|
47
|
+
File.write('.env.example', <<-END)
|
48
|
+
APP=myapp
|
49
|
+
END
|
50
|
+
|
51
|
+
expect {
|
52
|
+
EnvLint.verify_args('.env.example', ['OTHER=name'])
|
53
|
+
}.to raise_error(EnvLint::UnknownVariables)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '.verify_export_output' do
|
58
|
+
it 'passes when the env is complete' do
|
59
|
+
File.write('.env.example', <<-END)
|
60
|
+
APP=myapp
|
61
|
+
END
|
62
|
+
export_output = <<-END
|
63
|
+
declare -x APP="myapp"
|
64
|
+
declare -x OTHER="other"
|
65
|
+
END
|
66
|
+
|
67
|
+
expect {
|
68
|
+
EnvLint.verify_export_output('.env.example', export_output)
|
69
|
+
}.not_to raise_error
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'fails when the env is missing non optional variable' do
|
73
|
+
File.write('.env.example', <<-END)
|
74
|
+
APP=myapp
|
75
|
+
END
|
76
|
+
export_output = <<-END
|
77
|
+
declare -x OTHER="other"
|
78
|
+
END
|
79
|
+
|
80
|
+
expect {
|
81
|
+
EnvLint.verify_export_output('.env.example', export_output)
|
82
|
+
}.to raise_error(EnvLint::MissingVariables)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe EnvLint::LintedEnv do
|
87
|
+
it 'allows to read defined variables from ENV' do
|
88
|
+
File.write('.env.example', <<-END)
|
89
|
+
APP=myapp
|
90
|
+
END
|
91
|
+
allow(ENV).to receive(:fetch).with('APP').and_return('value')
|
92
|
+
|
93
|
+
linted_env = EnvLint::LintedEnv.from_file('.env.example')
|
94
|
+
|
95
|
+
expect(linted_env.fetch(:app)).to eq('value')
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def clean_up_sandbox
|
102
|
+
FileUtils.rm_rf(SANDBOX_DIR)
|
103
|
+
FileUtils.mkdir_p(SANDBOX_DIR)
|
104
|
+
end
|
105
|
+
|
106
|
+
def in_sandbox(&block)
|
107
|
+
Dir.chdir(SANDBOX_DIR, &block)
|
108
|
+
end
|
109
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: env_lint
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tim Fischbach
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-02-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: formatador
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: capistrano
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.9'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.9'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 3.0.0.beta1
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 3.0.0.beta1
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.3'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.3'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description:
|
84
|
+
email:
|
85
|
+
- mail@timfischbach.de
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- .gitignore
|
91
|
+
- .travis.yml
|
92
|
+
- Gemfile
|
93
|
+
- LICENSE.txt
|
94
|
+
- README.md
|
95
|
+
- Rakefile
|
96
|
+
- env_lint.gemspec
|
97
|
+
- lib/env_lint.rb
|
98
|
+
- lib/env_lint/capistrano.rb
|
99
|
+
- lib/env_lint/dot_env_file.rb
|
100
|
+
- lib/env_lint/dot_env_parser.rb
|
101
|
+
- lib/env_lint/env_key_parser.rb
|
102
|
+
- lib/env_lint/errors.rb
|
103
|
+
- lib/env_lint/formatter.rb
|
104
|
+
- lib/env_lint/linted_env.rb
|
105
|
+
- lib/env_lint/tasks.rb
|
106
|
+
- lib/env_lint/variable.rb
|
107
|
+
- lib/env_lint/version.rb
|
108
|
+
- spec/env_lint/capistrano_spec.rb
|
109
|
+
- spec/env_lint/dot_env_file_spec.rb
|
110
|
+
- spec/env_lint/dot_env_parser_spec.rb
|
111
|
+
- spec/env_lint/env_key_parser_spec.rb
|
112
|
+
- spec/env_lint/linted_env_spec.rb
|
113
|
+
- spec/integration_spec.rb
|
114
|
+
- spec/spec_helper.rb
|
115
|
+
homepage: ''
|
116
|
+
licenses:
|
117
|
+
- MIT
|
118
|
+
metadata: {}
|
119
|
+
post_install_message:
|
120
|
+
rdoc_options: []
|
121
|
+
require_paths:
|
122
|
+
- lib
|
123
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
124
|
+
requirements:
|
125
|
+
- - '>='
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
128
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - '>='
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
requirements: []
|
134
|
+
rubyforge_project:
|
135
|
+
rubygems_version: 2.2.2
|
136
|
+
signing_key:
|
137
|
+
specification_version: 4
|
138
|
+
summary: Lint the environment according by .env.example
|
139
|
+
test_files:
|
140
|
+
- spec/env_lint/capistrano_spec.rb
|
141
|
+
- spec/env_lint/dot_env_file_spec.rb
|
142
|
+
- spec/env_lint/dot_env_parser_spec.rb
|
143
|
+
- spec/env_lint/env_key_parser_spec.rb
|
144
|
+
- spec/env_lint/linted_env_spec.rb
|
145
|
+
- spec/integration_spec.rb
|
146
|
+
- spec/spec_helper.rb
|