diff --git a/README.md b/README.md index 7e0d28bb..76b09192 100644 --- a/README.md +++ b/README.md @@ -218,6 +218,29 @@ If you use this gem to handle env vars for multiple Rails environments (developm Credentials should only be accessible on the machines that need access to them. Never commit sensitive information to a repository that is not needed by every development machine and server. + +You can use the `-t` or `--template` flag on the dotenv cli to create a template of your `.env` file. +```shell +$ dotenv -t .env +``` +A template will be created in your working directory named `{FINAME}.template`. So in the above example, it would create a `.env.template` file. + +The template will contain all the environment variables in your `.env` file but with their values set to the variable names. + +```shell +# .env +S3_BUCKET=YOURS3BUCKET +SECRET_KEY=YOURSECRETKEYGOESHERE +``` + +Would become + +```shell +# .env.template +S3_BUCKET=S3_BUCKET +SECRET_KEY=SECRET_KEY +``` + Personally, I prefer to commit the `.env` file with development-only settings. This makes it easy for other developers to get started on the project without compromising credentials for other environments. If you follow this advice, make sure that all the credentials for your development environment are different from your other deployments and that the development credentials do not have access to any confidential data. ### Why is it not overriding existing `ENV` variables? diff --git a/lib/dotenv/cli.rb b/lib/dotenv/cli.rb index 446318e7..57bc3f0a 100644 --- a/lib/dotenv/cli.rb +++ b/lib/dotenv/cli.rb @@ -1,5 +1,6 @@ require "dotenv" require "dotenv/version" +require "dotenv/template" require "optparse" module Dotenv @@ -41,6 +42,7 @@ def add_options(parser, flag_matchers) add_files_option(parser, flag_matchers) add_help_option(parser, flag_matchers) add_version_option(parser, flag_matchers) + add_template_option(parser, flag_matchers) end def add_files_option(parser, flag_matchers) @@ -66,6 +68,18 @@ def add_version_option(parser, flag_matchers) end end + # Take a env file and create a template from it. This will keep the Key + # names but will replace the values. Useful for fat fingers who don't want + # to push env files. + def add_template_option(parser, flag_matchers) + flag_matchers.push("-t \\S+", "--template \\S+") + description = "Create a template of an existing env file" + parser.on("-t", "--template=FILE", description) do |file| + template = Dotenv::EnvTemplate.new(file) + template.create_template + end + end + # Detect dotenv flags vs executable args so we can parse properly and still # take advantage of OptionParser for dotenv flags def split_argv(arg_string, matchers) diff --git a/lib/dotenv/template.rb b/lib/dotenv/template.rb new file mode 100644 index 00000000..a872cef2 --- /dev/null +++ b/lib/dotenv/template.rb @@ -0,0 +1,19 @@ +module Dotenv + # Class for creating a template from a env file + class EnvTemplate + def initialize(env_file) + @env_file = env_file + end + + def create_template + File.open(@env_file, "r") do |env_file| + File.open("#{@env_file}.template", "w") do |env_template| + env_file.each do |line| + variable = line.split("=").first + env_template.puts "#{variable}=#{variable}" + end + end + end + end + end +end diff --git a/spec/dotenv/cli_spec.rb b/spec/dotenv/cli_spec.rb index b69ff43a..dd2f9c0b 100644 --- a/spec/dotenv/cli_spec.rb +++ b/spec/dotenv/cli_spec.rb @@ -54,6 +54,24 @@ def run(*args) expect(cli.exec_args).to eql(["foo", "-f", "something"]) end + it "templates a file specified by -t" do + @buffer = StringIO.new + @input = StringIO.new("FOO=BAR\nFOO2=BAR2") + @origin_filename = "plain.env" + @template_filename = "plain.env.template" + @content = "the content fo the file" + allow(File).to receive(:open).with(@origin_filename, "r").and_yield(@input) + # rubocop:disable LineLength + allow(File).to receive(:open).with(@template_filename, "w").and_yield(@buffer) + + # call the function that writes to the file + cli = Dotenv::CLI.new(["-t", "plain.env"]) + cli.send(:parse_argv!, cli.argv) + + # reading the buffer and checking its content. + expect(@buffer.string).to eq("FOO=FOO\nFOO2=FOO2\n") + end + # Capture output to $stdout and $stderr def capture_output(&_block) original_stderr = $stderr