env_lint 0.0.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 +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
|