Skip to content

Multi-environment config via named contexts#3547

Merged
kichristensen merged 15 commits intogetporter:mainfrom
kichristensen:multiEnvironmentConfig
Mar 1, 2026
Merged

Multi-environment config via named contexts#3547
kichristensen merged 15 commits intogetporter:mainfrom
kichristensen:multiEnvironmentConfig

Conversation

@kichristensen
Copy link
Copy Markdown
Contributor

What does this change

Adds kubectl-style multi-context support to the Porter config file. Users can define multiple named environments in a single config file and switch between them at runtime.

New schemaVersion: "2.0.0" format:

schemaVersion: "2.0.0"
current-context: default
contexts:
  - name: default
    config:
      namespace: dev
      default-storage: localdb
  - name: prod
    config:
      namespace: prod
      default-storage: proddb

Context selection (highest to lowest priority):

  1. --context prod flag
  2. PORTER_CONTEXT=prod env var
  3. current-context: field in the config file
  4. Falls back to a context named "default"

New commands:

$ porter config context list
* default
  prod

$ porter config context use prod
Switched to context "prod".

Legacy flat config files continue to work unchanged. Using --context with a legacy file is a hard error with a clear message.

What issue does it fix

Closes #3523

Notes for the reviewer

  • Context list/use use viper internally so they work with any supported config format (YAML, TOML, JSON, HCL)
  • ConfigContextUse does a targeted regex replace of the current-context: line to preserve Liquid template variables elsewhere in the file
  • The defaultConfigTemplate (used by porter config edit when no file exists) now generates the new versioned format

Checklist

  • Did you write tests?
  • Did you write documentation?
  • Did you change porter.yaml or a storage document record? Update the corresponding schema file.
  • If this is your first pull request, please add your name to the bottom of our Contributors list. Thank you for making Porter better! 🙇‍♀️

Add kubectl-style multi-context support to the Porter config
file using a new schemaVersion: "2.0.0" format. Users can
define multiple named contexts in a single config file and
select between them at runtime.

Changes:
- New config format: schemaVersion, current-context, contexts[]
- --context flag and PORTER_CONTEXT env var for context selection
- Context selection priority: flag > env var > current-context
  field in file > "default"
- Legacy flat format still supported; hard error if --context
  used with it
- porter config context list: list contexts, mark active one
- porter config context use <name>: update current-context
- ConfigContextList uses viper (format-agnostic: TOML/JSON/HCL)
- defaultConfigTemplate updated to new versioned format
- Integration tests + CI workflow jobs added

Signed-off-by: Kim Christensen <kimworking@gmail.com>
Adds `porter config migrate` to convert a legacy flat config
file to the multi-context format (schemaVersion: "2.0.0").

- Existing settings are wrapped under a "default" context
- Text-based transformation preserves Liquid template vars
- TOML/JSON/HCL files get a hard error with manual guidance
- No-op if file already uses the multi-context format
- Unit tests (4) and integration test added

Signed-off-by: Kim Christensen <kimworking@gmail.com>
New page: docs/configuration/multi-context.md covering
- config file format (schemaVersion 2.0.0)
- context selection priority (flag > env > current-context > default)
- porter config context list/use commands
- porter config migrate for upgrading legacy files

Updated configuration.md to link to the new page.

Signed-off-by: Kim Christensen <kimworking@gmail.com>
Signed-off-by: Kim Christensen <kimworking@gmail.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds kubectl-style multi-context configuration support to Porter, allowing users to define multiple named environments (dev, staging, prod, etc.) in a single config file and easily switch between them. The implementation introduces:

Changes:

  • New schemaVersion: "2.0.0" config format with named contexts
  • Context selection via --context flag, PORTER_CONTEXT env var, or current-context field
  • New commands: porter config context list, porter config context use, and porter config migrate

Reviewed changes

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

Show a summary per file
File Description
pkg/config/config.go Adds ContextName field to Config struct for storing selected context
pkg/config/datastore.go Defines ConfigSchemaVersion constant and new types for multi-context structure
pkg/config/loader.go Implements multi-context loading logic with fallback to legacy format
pkg/porter/config_file.go Adds ConfigContextList, ConfigContextUse, and ConfigMigrate commands
cmd/porter/config.go Wires up new context subcommands
cmd/porter/main.go Adds --context global flag
tests/integration/config_test.go Comprehensive integration tests for multi-context functionality
pkg/porter/config_file_test.go Unit tests for context commands
pkg/config/loader_test.go Unit tests for context loading logic
docs/content/docs/configuration/multi-context.md New documentation page explaining multi-context feature
docs/content/docs/configuration/configuration.md Updates to main config documentation
docs/content/docs/references/cli/*.md Generated CLI documentation for new commands and global flag
.github/workflows/*.yml Adds config_test to CI workflows

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

Comment thread pkg/porter/config_file.go
Comment thread pkg/porter/config_file.go Outdated
Comment thread pkg/porter/config_file.go
Comment thread pkg/porter/config_file.go
Comment thread pkg/config/config.go Outdated
Comment thread pkg/porter/config_file.go
Signed-off-by: Kim Christensen <kimworking@gmail.com>
Signed-off-by: Kim Christensen <kimworking@gmail.com>
Replace substring search with a regex anchored to line-start so
YAML comments containing 'schemaVersion:' cannot cause false
positives in ConfigMigrate and ConfigContextUse.

Signed-off-by: Kim Christensen <kimworking@gmail.com>
Signed-off-by: Kim Christensen <kimworking@gmail.com>
- Reject names with newline/CR to prevent YAML injection
- Verify the named context exists before updating the file,
  giving a clear error instead of silently writing an invalid
  current-context value

Signed-off-by: Kim Christensen <kimworking@gmail.com>
Auto-migration is YAML-only, but TOML (and other viper-supported
formats) can be used if the user manually writes the multi-context
structure. Add a test to confirm context list reads TOML correctly.

Signed-off-by: Kim Christensen <kimworking@gmail.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

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


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

Comment thread pkg/porter/config_file.go Outdated
Comment thread pkg/porter/config_file.go Outdated
Comment thread pkg/porter/config_file.go Outdated
Comment thread pkg/porter/config_file.go Outdated
Comment thread pkg/config/config.go
Comment thread cmd/porter/main.go Outdated
Comment thread pkg/config/loader.go
Comment thread pkg/config/loader.go
- ContextName comment: note current-context is checked before
  falling back to 'default'
- --context flag help: same priority description
- loader error: mention PORTER_CONTEXT alongside --context

Signed-off-by: Kim Christensen <kimworking@gmail.com>
Replace schemaVersion/currentContext package-level regexes with a
replaceCurrentContext helper that dispatches a format-specific
pattern (YAML, TOML/HCL, JSON) so comments and Liquid template
variables elsewhere in the file are preserved.

ConfigMigrate remains YAML-only; schemaVersion detection in both
commands now uses viper so single/no-quote YAML variants and other
formats are handled correctly.

Add TestConfigContextUse_TOML to confirm TOML round-trip.

Signed-off-by: Kim Christensen <kimworking@gmail.com>
Validate that context names match [a-zA-Z0-9][a-zA-Z0-9_.-]* before
writing. Characters like '#', spaces, and quotes can break YAML/TOML/
JSON output; this charset is safe across all supported formats and
matches Kubernetes context naming conventions.

Signed-off-by: Kim Christensen <kimworking@gmail.com>
extractContextConfig now returns an error when schemaVersion is
present but the contexts key is absent, preventing silent fallback
to defaults that could mask misconfiguration.

Signed-off-by: Kim Christensen <kimworking@gmail.com>
Signed-off-by: Kim Christensen <kimworking@gmail.com>
@kichristensen kichristensen merged commit 424ae2c into getporter:main Mar 1, 2026
48 checks passed
@kichristensen kichristensen deleted the multiEnvironmentConfig branch March 1, 2026 22:18
@lbergnehr
Copy link
Copy Markdown
Contributor

@kichristensen sorry for not getting to this sooner, but I think it looks like a great solution! I'm going to test it out as soon as it's landed in a release, or possibly in the canary, and let you know if I have any feedback! Good job!

@lbergnehr
Copy link
Copy Markdown
Contributor

Added this suggestion after trying this out a bit: #3558

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

No open projects
Status: Done

Development

Successfully merging this pull request may close these issues.

Handle multiple configurations natively

4 participants