Search code examples
ruby-on-railsherokuheroku-toolbeltheroku-cli

Clone a repository during deployment on Heroku


I have a Rails project PROJECTX, which is hosted on Heroku. For storing production configs and files, I am using a different repository PROJECTX-config. Is it possible to:

  1. clone PROJECTX-config,
  2. remove current config files, and
  3. symlink config files to PROJECTX-config files

Note that this has to be done on Heroku. Also I am aware that Heroku has options to maintain configs using environment variables, but this is not what I am looking for.

Thanks!


Solution

  • No its not possible.

    Each dyno gets its own ephemeral filesystem, with a fresh copy of the most recently deployed code. During the dyno’s lifetime its running processes can use the filesystem as a temporary scratchpad, but no files that are written are visible to processes in any other dyno and any files written will be discarded the moment the dyno is stopped or restarted. For example, this occurs any time a dyno is replaced due to application deployment and approximately once a day as part of normal dyno management.
    - https://devcenter.heroku.com/articles/dynos#ephemeral-filesystem

    Or at least not without a Rube Goldberg machine like setupe where you setup some kind of automation (like a post-commit hook) to merge repo A and repo B and push the result to heroku.

    Also I believe that app config should not be present in environment variables, as it is tedious to maintain rather than maintaining a file.

    Heroku does not agree here.

    The traditional approach for handling such config vars is to put them under source - in a properties file of some sort. This is an error-prone process, and is especially complicated for open source apps which often have to maintain separate (and private) branches with app-specific configurations.
    A better solution is to use environment variables, and keep the keys out of the code. On a traditional host or working locally you can set environment vars in your bashrc file. On Heroku, you use config vars. - https://devcenter.heroku.com/articles/config-vars

    Although you might be overestimating what you actually need to store in ENV vars. You only need to store secrets such as API keys in ENV.

    Other non-secret configuration such your settings for various gems can and should be setup in config/initializers.

    If you still think using the GUI is that terrible then use YAML files which you parse and use to set the ENV vars:

    require 'yaml'
    
    yaml = YAML.load_file(File.join(__dir__, 'conf.yml'))
    
    def create_key(*components)
      components.join('_').upcase
    end
    
    env_vars = yaml["production"].each_with_object({}) do |(key,value), memo|
      key_components = [key]
      if value.kind_of? Hash
        value.each_pair do |k,v|
          memo[create_key(*key_components.dup.push(k))] = v
        end
      else
        memo[create_key(*key_components)] = value
      end
    end.each do |k,v|
      system("heroku config:set #{k}=#{v}")
      puts "Setting #{k} = #{v}; #{ $? }"
    end
    

    Or you could even store a serialized form (JSON or YAML) in a single env var - there is a total size limit of 32kb though.