Project level user config

Project Level User Config

It’s common to couple user-level configuration with a project, rather than with an environment.

Environment level user config is located in ~/.guild/config.yml or as specified by the env var GUILD_CONFIG. As of 0.7.4, this is the only way to provide this configuration.

Guild should support the ability to provide user level config within a project.

Guild’s project level configuration is limited to a Guild file (guild.yml). This defines models and operations. It does not define user config elements like remotes.

Proposal 1 - guild-config.yml

Guild could support user level config guild-config.yml as a single file within a project. The file should exist alongside the Guild file guild.yml.

Guild could apply this configuration to the environment level config defined in .guild/config.yml. Alternatively, the project level user config could replace the environment level config entirely.

For example:

- My Project
  - guild.yml
  - guild-config.yml

Proposal 2 - Mirror .guild under project

Guild could look for a .guild directory alongside guild.yml and use it as a priority over the environment level .guild directory. User config would be defined in .guild/config.yml.

For example:

- My Project
  - guild.yml
  - .guild
    - config.yml

This approach is potentially broader in that it opens up the possibility to use the project for other items otherwise stored under the environment.

Proposal evaluation

The immediate goal is to support project level configuration at all. We should consider deferring more advanced features:

  • Defer or reject the ability to extend environment level config — i.e. project level config should replace environment level config outright.

  • Defer or reject non-config level extension or replacement suggested in Proposal 2.

Extending user config

The ability to extend user config complicates the implementation by introducing a user config path. User config is no longer under a single location but rather under multiple possible locations. This breaks the current interface, which assumes a single, unambiguous location.

In particular, Guild resolves relative paths in user config using the config file location. If user config can be defined in multiple files, each config object specifying a relative path must to resolve that path using the config file the object itself is defined in.

Consider this example.

Environment level config file:

# ~/.guild/config.yml
remotes:
  foo:
    private-key: id_rsa

Project level config file:

# guild-config.yml

remotes:
  bar:
    private-key: id_rsa

If Guild supports user config extension, the remotes command should show both foo and bar:

guild remotes
bar
foo

The implementation of this is straight forward: detect guild-config.yml and include it in the user config path, merging its contents into ~/.guild/config.yml. The resolution of the relative path id_rsa in the case of both foo and bar remotes is less straight forward. Each remote data object must include the path of the file it is defined in to correctly resolve the relative path.

This scheme therefore presents non-trivial changes to the existing API:

  • Guild can no longer assume a single path to user config. Any API that makes this assumption must be changed in a non-backward compatible way.
  • All configuration objects must be enhanced to include the config file path that defines them.
  • Resolution of relative paths must be made in the context of the defining object.

If we defer or reject user config extension, we can avoid these changes. The existing API is preserved as-is. The only change is the location of the user configuration file.

We should reject user config extension as presented in Proposal 1 for the following reasons:

  • The feature requires non-trivial, backward-incompatible API changes.
  • The requirement to extend user config is speculative (no clear user demand) and introduces user-facing complexity (complicated docs, potentially confusing runtime behavior, potential for subtle bugs)
  • The decision to omit user config extension does not prevent us from adding this feature later.

Mirror .guild at the project level

Proposal 2 goes even further in extending existing functionality and should be similarly referred or rejected. It’s unclear how or even why such extensions are useful — e.g. what is the point of extending caching, runs, etc.

Working decision

Modify Guild to look for guild-config.yml in the current working directory and use it for user config. This follows the current pattern of using the environment variable GUILD_CONFIG if defined.

The new behavior should therefore be:

  • Continue using a single file for user config.
  • Use the path specified by the GUILD_CONFIG environment variable, if defined.
  • Otherwise, look for guild-config.yml in the current working directory. If this file exists, use it.
  • Otherwise, use ~/.guild/config.yml.