Skip to content

feat: Add support for multiple environment files - #225

Merged
xmnlab merged 2 commits into
makim-org:mainfrom
xmnlab:add-multi-env-files
Feb 10, 2026
Merged

feat: Add support for multiple environment files#225
xmnlab merged 2 commits into
makim-org:mainfrom
xmnlab:add-multi-env-files

Conversation

@xmnlab

@xmnlab xmnlab commented Feb 10, 2026

Copy link
Copy Markdown
Contributor

Pull Request description

How to test these changes

  • ...

Pull Request checklists

This PR is a:

  • bug-fix
  • new feature
  • maintenance

About this PR:

  • it includes tests.
  • the tests are executed on CI.
  • the tests generate log file(s) (path).
  • pre-commit hooks were executed locally.
  • this PR requires a project documentation update.

Author's checklist:

  • I have reviewed the changes and it contains no misspelling.
  • The code is well commented, especially in the parts that contain more
    complexity.
  • New and old tests passed locally.

Additional information

Reviewer's checklist

Copy and paste this template for your review's note:

## Reviewer's Checklist

- [ ] I managed to reproduce the problem locally from the `main` branch
- [ ] I managed to test the new changes locally
- [ ] I confirm that the issues mentioned were fixed/resolved .

@github-actions

Copy link
Copy Markdown

OSL ChatGPT Reviewer

NOTE: This is generated by an AI program, so some comments may not make sense.

.makim.yaml

LGTM!


docs/spec.md

  • Breaking change: Renaming env-file -> env-files will break existing configs unless the loader still accepts env-file as an alias. Either:

    • Keep backward-compat with a deprecation warning and document it here (e.g., “env-file is deprecated but supported”) (L.15, L.503), or
    • Clearly call out the breaking change and migration guidance, including the release/version where it takes effect (L.15).
  • Undefined failure mode: Specify what happens when a listed file does not exist (error, warn and skip, or silently skip). This affects reliability in CI/CD (L.515, after the “loaded in order” sentence).

  • Path resolution: Clarify whether paths are resolved relative to the directory of .makim.yaml, the project root, or process CWD. This avoids surprising behavior when invoked from subdirs or CI (L.514).

  • Precedence rules: Define how env-files interact with:

    • Existing process environment variables
    • The env section in YAML
    • CLI-provided env overrides
      Which wins on conflict? Document the exact order to prevent accidental overrides (L.515).
  • Security note: Since later files override earlier ones, call out the risk of a local/dev file (.env.local) overriding secure defaults in CI; recommend ordering and/or guidance for CI (e.g., load secure files last or prevent overrides of protected variables) (L.515).


docs/template.md

  • Potential breaking change: Renaming env-file -> env-files will break existing configs if the old key isn’t still supported. Please confirm backward compatibility in code, and add a deprecation note in this section (L.34).

  • Ambiguity on error handling: What happens if an env file is missing/unreadable? Document whether Makim fails fast or skips with a warning (L.39).

  • Path resolution: Clarify whether relative env-files paths are resolved from the working directory or the .makim.yaml location (L.39).

  • Ordering across scopes: The text says it “respects the order of scopes,” but with multiple files and scopes it’s unclear. Explicitly define the full merge order, e.g.: system env -> env-files in global (in listed order) -> env in global -> env-files in group -> env in group -> env-files in task -> env in task, with later entries overriding earlier ones (L.36).


src/makim/core.py

  • Breaking change: Only env-files is read now; existing configs using env-file will silently stop working. Add backward-compatible lookup. Also, normalize Windows/tilde paths using Path.is_absolute() and expanduser() instead of string startswith to avoid misclassifying absolute paths on Windows. (L.604, L.612)

Suggested patch:
def _load_dotenv(self, data_scope: dict[str, Any]) -> dict[str, str]:
"Load and merge environment variables from one or more .env files."
def _normalize_env_files(env: str | list[str] | None) -> list[str]:
"Normalize env-files and support legacy key."
if not env:
return []
return [env] if isinstance(env, str) else list(env)

def _abs_env_path(env_file: str) -> str:
    "Resolve absolute path for an env file."
    p = Path(env_file).expanduser()
    return str(p if p.is_absolute() else (Path(self.file).parent / p))

env_files = _normalize_env_files(data_scope.get('env-files') or data_scope.get('env-file'))  # (L.604)
if not env_files:
    return {}

merged_vars: dict[str, str] = {}
for env_file in env_files:
    env_path = _abs_env_path(env_file)  # (L.612)
    if not Path(env_path).exists():
        MakimLogs.raise_error(
            f'The given env-file `{env_path}` was not found.',
            MakimError.MAKIM_ENV_FILE_NOT_FOUND,
        )
    env_vars = dotenv.dotenv_values(env_path)
    merged_vars.update({k: (v or '') for k, v in env_vars.items()})
return merged_vars

src/makim/schema.json

  • Breaking change: renaming env-file → env-files will invalidate existing configs. Either accept both keys for a deprecation period and forbid using both at once (schema-level not rule), or clearly mark this as a major version change and update migration notes.
  • Schema/runtime drift risk: if the loader still expects a single string env-file, configs validated by this schema (arrays) will fail at runtime. Ensure the parser supports both string and array inputs and applies override order deterministically.
  • Validation/perf: consider type: ["string","array"] instead of oneOf for simpler, faster validation; add minLength: 1 for strings and minItems: 1 (and possibly a reasonable maxItems) for arrays to prevent empty/degenerate inputs and excessive file loads.

tests/smoke/.env-multi-1

LGTM!


tests/smoke/.env-multi-2

LGTM!


tests/smoke/.makim-bash-group-scope.yaml

  • (L.1) Possible type mismatch: if the loader expects env-files to be a list, providing a scalar string may cause iteration over characters or a type error. Use a YAML list: env-files: [".env"].

  • Potential breaking change: if this reflects a schema rename from env-file -> env-files, ensure backward compatibility (support both keys) or add a migration path and tests covering the legacy key to avoid breaking existing user configs.


tests/smoke/.makim-bash-main-scope.yaml

  • Potential type mismatch: if the schema expects env-files to be a list, providing a scalar string may break or be ignored. Recommend using a YAML sequence (L.1):
    env-files:
    • .env

tests/smoke/.makim-bash-task-scope.yaml

  • Potential logic bug: If env-files expects an iterable of paths, providing a scalar string may be iterated as characters (".", "e", "n", "v"), causing file open failures. Use a list. (L.1)

    Suggested change:

    • env-files:
      • .env
  • Breaking change risk: Renaming env-file -> env-files may break existing configs. If this is an intentional API change, add/keep a test asserting legacy env-file is either still supported (alias) or explicitly deprecated with a clear error.


tests/smoke/.makim-complex.yaml

  • Potential logic bug: if the loader treats env-files as an iterable of paths, a scalar string will be iterated character-by-character. Use a list. Suggest change (L.1):
    env-files:
    • .env
  • Breaking change risk: if singular env-file is still supported or deprecated, add a smoke test covering the legacy key, or ensure the loader normalizes both forms.

tests/smoke/.makim-env.yaml

  • Potential logic bug: Two tasks use the same env-files (.env-task) but assert different ENV values.
    • task-scope.test-var-env-file asserts "test"
    • task-scope.test-var-env asserts "staging"
      One of these is wrong or .env-task changed. Align the expectation with the actual .env-task value. Suggestion: change the second assertion to "test" (L.54):
      • assert str(os.getenv("ENV")) == "test"

tests/smoke/.makim-interpreters.yaml

  • Potential type mismatch: if the schema expects env-files to be a list, providing a scalar string may cause iteration over characters or validation errors. Use a list instead (L.1):
    env-files:

    • .env
  • Verify CI/tooling uses a version that recognizes env-files; otherwise this change will break config loading.


tests/smoke/.makim-simple.yaml

  • Potential breakage: if the loader now expects env-files to be a list, providing a scalar may fail. Either make it a sequence (L.1): env-files: [".env"], or normalize in the loader.

  • To keep backward compatibility with existing configs using env-file, normalize both keys in the parser:

def normalize_env_files(cfg: dict) -> list[str]:
    """Normalize env-files to a list"""
    val = cfg.get("env-files", cfg.get("env-file", []))
    if isinstance(val, str):
        return [val]
    if isinstance(val, list):
        return [v for v in val if isinstance(v, str)]
    raise TypeError("env-files must be str or list[str]")
  • If this is an intentional rename, consider deprecating env-file with a warning rather than hard-breaking it.

tests/smoke/.makim-ssh.yaml

  • Risk of config not being read: Does your current Makim version support env-files? If it still expects env-file, SSH_HOST won’t load and host interpolation will fail at runtime. Please confirm the schema before merging.

  • If env-files is correct, many loaders require a sequence. Use a list to avoid type mismatches:

    • Change to:
      env-files:
      • .env-ssh
        (L.1)

tests/smoke/.makim-sugar.yaml

  • (L.1) Does your Makim version actually support env-files? If not, this will be ignored and env vars won’t load. Consider keeping env-file or ensuring the runtime is updated.
  • (L.1) If env-files expects a list, use list syntax to avoid schema/type mismatches:
    • env-files:
      • .env

tests/smoke/.makim-unittest.yaml

  • Possible schema mismatch: if the loader expects env-files to be a list, using a scalar may be ignored or error at runtime. Suggest using a list (L.1): env-files: ['.env'].
  • Backward-compatibility: if previous configs used env-file, ensure the parser accepts both keys (alias/migration) to avoid breaking existing setups.

@xmnlab
xmnlab merged commit 11307c2 into makim-org:main Feb 10, 2026
26 checks passed
@xmnlab
xmnlab deleted the add-multi-env-files branch February 10, 2026 20:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant