Skip to content

feat: implement --env-file support in mocker run - #2

Merged
us merged 3 commits into
us:mainfrom
kingdonb:add-env-file-option
Mar 9, 2026
Merged

feat: implement --env-file support in mocker run#2
us merged 3 commits into
us:mainfrom
kingdonb:add-env-file-option

Conversation

@kingdonb

@kingdonb kingdonb commented Mar 9, 2026

Copy link
Copy Markdown
Contributor

Hello! I saw mocker and noticed it was missing the --env-file= option. I asked Gemini to add it!

Just a suggestion. I'll rewrite the commit message here to conform to the standards, in case you want to merge this.

@kingdonb
kingdonb force-pushed the add-env-file-option branch from a2c1b5b to 17eedad Compare March 9, 2026 01:39
@kingdonb kingdonb changed the title Add option to mocker run: --env-file= feat: implement --env-file support in mocker run Mar 9, 2026
@kingdonb

kingdonb commented Mar 9, 2026

Copy link
Copy Markdown
Contributor Author

He's gone ahead and added a test now, as well

@kingdonb

kingdonb commented Mar 9, 2026

Copy link
Copy Markdown
Contributor Author

I'm working on some other changes, but I'll keep them to myself until I hear back from you! (I wanted to run -i -t but I think it's more complicated than I've understood yet. Learning to use the underlying container binary with Gemini now - thanks for making this, it's very helpful so far!) I won't be offended if you close this, in any case.

@us

us commented Mar 9, 2026

Copy link
Copy Markdown
Owner

thank you for your contributions, now just reviewing then will merge soon!

@us us closed this Mar 9, 2026
@us us reopened this Mar 9, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Docker-like --env-file support to the mocker run command so users can supply environment variables from a file, and documents the flag in usage examples.

Changes:

  • Added --env-file option to mocker run and merged env vars from file + -e/--env (with -e taking precedence).
  • Added a CLI parsing test for the new flag.
  • Updated README usage example and PROGRESS tracking.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
Sources/Mocker/Commands/Run.swift Introduces --env-file option and env-file parsing/merge logic.
Tests/MockerTests/CLITests.swift Adds a parsing-level test for the new flag.
README.md Documents --env-file in the mocker run example.
PROGRESS.md Records completion of the env-file task.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +70 to +75
let trimmed = line.trimmingCharacters(in: .whitespaces)
if trimmed.isEmpty || trimmed.hasPrefix("#") { continue }
let parts = trimmed.split(separator: "=", maxSplits: 1)
guard parts.count == 2 else { continue }
environment[String(parts[0])] = String(parts[1])
}

Copilot AI Mar 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

split(separator:maxSplits:) omits empty subsequences by default, so a line like FOO= in the env file will be ignored instead of setting FOO to an empty value (Docker's --env-file supports empty values). Consider using split(..., omittingEmptySubsequences: false) and validating parts[0] is non-empty; also consider trimming whitespace around the key to avoid FOO =bar producing a key with a trailing space.

Copilot uses AI. Check for mistakes.
Comment on lines +72 to +81
let parts = trimmed.split(separator: "=", maxSplits: 1)
guard parts.count == 2 else { continue }
environment[String(parts[0])] = String(parts[1])
}
}

// 2. Add from -e/--env (overrides --env-file)
for item in env {
let parts = item.split(separator: "=", maxSplits: 1)
guard parts.count == 2 else { continue }

Copilot AI Mar 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same parsing issue for -e/--env: FOO= will currently be dropped because split omits empty values by default. If the goal is Docker CLI compatibility, it should treat KEY= as setting an empty string value (and ideally reject empty keys).

Suggested change
let parts = trimmed.split(separator: "=", maxSplits: 1)
guard parts.count == 2 else { continue }
environment[String(parts[0])] = String(parts[1])
}
}
// 2. Add from -e/--env (overrides --env-file)
for item in env {
let parts = item.split(separator: "=", maxSplits: 1)
guard parts.count == 2 else { continue }
let parts = trimmed.split(separator: "=", maxSplits: 1, omittingEmptySubsequences: false)
guard parts.count == 2, !parts[0].isEmpty else { continue }
environment[String(parts[0])] = String(parts[1])
}
}
// 2. Add from -e/--env (overrides --env-file)
for item in env {
let parts = item.split(separator: "=", maxSplits: 1, omittingEmptySubsequences: false)
guard parts.count == 2, !parts[0].isEmpty else { continue }

Copilot uses AI. Check for mistakes.
Comment on lines +68 to +74
let content = try String(contentsOf: fileURL, encoding: .utf8)
for line in content.components(separatedBy: .newlines) {
let trimmed = line.trimmingCharacters(in: .whitespaces)
if trimmed.isEmpty || trimmed.hasPrefix("#") { continue }
let parts = trimmed.split(separator: "=", maxSplits: 1)
guard parts.count == 2 else { continue }
environment[String(parts[0])] = String(parts[1])

Copilot AI Mar 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading --env-file currently surfaces a raw Foundation file I/O error to the user. Other commands wrap user-facing file issues in MockerError (e.g., composeFileNotFound), so consider catching read failures here and throwing a MockerError.operationFailed (or a dedicated error) with a clear message like "failed to read env file: ".

Suggested change
let content = try String(contentsOf: fileURL, encoding: .utf8)
for line in content.components(separatedBy: .newlines) {
let trimmed = line.trimmingCharacters(in: .whitespaces)
if trimmed.isEmpty || trimmed.hasPrefix("#") { continue }
let parts = trimmed.split(separator: "=", maxSplits: 1)
guard parts.count == 2 else { continue }
environment[String(parts[0])] = String(parts[1])
do {
let content = try String(contentsOf: fileURL, encoding: .utf8)
for line in content.components(separatedBy: .newlines) {
let trimmed = line.trimmingCharacters(in: .whitespaces)
if trimmed.isEmpty || trimmed.hasPrefix("#") { continue }
let parts = trimmed.split(separator: "=", maxSplits: 1)
guard parts.count == 2 else { continue }
environment[String(parts[0])] = String(parts[1])
}
} catch {
throw MockerError.operationFailed("failed to read env file: \(envFilePath)")

Copilot uses AI. Check for mistakes.
Comment on lines +63 to +83
var environment: [String: String] = [:]

// 1. Read from --env-file if provided
if let envFilePath = envFile {
let fileURL = URL(fileURLWithPath: envFilePath)
let content = try String(contentsOf: fileURL, encoding: .utf8)
for line in content.components(separatedBy: .newlines) {
let trimmed = line.trimmingCharacters(in: .whitespaces)
if trimmed.isEmpty || trimmed.hasPrefix("#") { continue }
let parts = trimmed.split(separator: "=", maxSplits: 1)
guard parts.count == 2 else { continue }
environment[String(parts[0])] = String(parts[1])
}
}

// 2. Add from -e/--env (overrides --env-file)
for item in env {
let parts = item.split(separator: "=", maxSplits: 1)
guard parts.count == 2 else { continue }
environment[String(parts[0])] = String(parts[1])
}

Copilot AI Mar 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new env-file parsing/precedence logic is only covered by an argument-parsing test. Consider extracting the env parsing into a small helper (e.g., parseEnvFile / parseEnvPairs) and adding unit tests for: comments/blank lines, FOO= empty values, and -e overriding values from --env-file.

Copilot uses AI. Check for mistakes.
@us
us merged commit 628bde3 into us:main Mar 9, 2026
us added a commit that referenced this pull request Mar 9, 2026
* feat: implement --env-file support in mocker run

* docs: update README with --env-file usage and add CLI tests

* fix: add Mocker dependency to MockerTests for CLI test linking

---------

Co-authored-by: us <rahmetsaritekin@gmail.com>
@us

us commented Mar 9, 2026

Copy link
Copy Markdown
Owner

@kingdonb thank you again for support, you can create a new branches for other contributions too!

us added a commit that referenced this pull request Mar 13, 2026
* feat: implement --env-file support in mocker run

* docs: update README with --env-file usage and add CLI tests

* fix: add Mocker dependency to MockerTests for CLI test linking

---------

Co-authored-by: us <rahmetsaritekin@gmail.com>
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.

3 participants