You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* sync local env files with cloud on pull/push
* refactor(env): simplify env sync module
- Remove unused assetFileNames param from readProjectEnvFiles
- Consolidate config DTO builders via shared helpers
- Extract missing-env-file push warnings into envSync
* refactor(env): extract pull/push env orchestration
- Partition cloud config into asset vs non-asset env variables
- Add prepareEnvPushState and computeEnvPullChanges helpers
- Slim push and sync command env wiring
* refactor(env): trim tests and dedupe env sync
* fix(assets): archive removed assets on push
Also drop stale asset env keys from appConfig so pull doesn’t resurrect deleted asset vars
* feat(env): implement pruning of stale asset env entries on push
* fix(push): confirm cloud env/secrets wipe
Missing or empty .env.config/.env.secrets now warn and prompt
[y/N] before clearing cloud values; empty secrets push {}
* feat(env): alias-scoped env sync for push/pull
- resolve base vs .env.*.<alias> by default alias + file presence
- non-default pull creates scoped files; never stomps base
- missing env file skips push side; empty file wipes with confirm
- pull asset keys to resolved config path
- wire push/pull/release + docs/tests
* fix(release): honor --app on subcommands
- Commander ate --app when parent+child both declared it
- read --app from release parent opts in create/list/use
- align Firestore version id with GCS snapshot path
- alias-aware success/list hints for non-default apps
* fix(release): honor --app, sync version ids
This document proposes an environment-variable architecture for the Ensemble CLI that supports **multiple app environments** (or “targets”) cleanly and safely.
3
+
This document describes the environment-variable architecture used by the Ensemble CLI for **multiple app environments** (or “targets”).
| Alias is **default** and only base files exist |`.env.config` + `.env.secrets`|
77
+
| Alias is **not default**|`.env.config.<alias>` + `.env.secrets.<alias>` (created on pull if missing) |
78
+
| Alias has **both** scoped files (any alias) | scoped pair wins over base |
82
79
83
-
If only `.env.config` exists, behavior matches today (backwards compatible). Secrets files are additive and optional.
80
+
No mixing across tiers. Config and secrets always come from the same tier.
84
81
85
-
### Why this precedence?
86
-
87
-
- Shared values (common across envs) live in one place.
88
-
- Environment-specific values override without duplicating the whole file.
82
+
Pulling a non-default alias (e.g. `ensemble pull --app uat`) writes cloud env into `.env.config.uat` / `.env.secrets.uat` and leaves base files untouched.
89
83
90
84
---
91
85
92
-
## CLI behavior (proposed)
93
-
94
-
### Reading env config
86
+
## CLI behavior
95
87
96
-
Commands that need env config should use the **effective env config** for the selected `--app` alias.
88
+
### Reading env files
97
89
98
-
- If `--app` is omitted, treat it as `default` (existing behavior).
99
-
- If `.env.config.<alias>` is missing, fall back to `.env.config` only.
90
+
Commands use the resolved pair for the selected `--app` alias (see resolution rules above).
100
91
101
-
### Pushing env variables
92
+
`--app` is optional and defaults to `ensemble.config.json` → `default`.
102
93
103
-
If the CLI supports pushing env vars to the cloud, it should be **explicitly scoped**:
94
+
### Missing vs empty (push)
104
95
105
-
-`ensemble push --app prod` may only push the **prod effective env config**.
106
-
- It must never push dev values to prod unless the user explicitly made them prod values (via `.env.config.prod` or identical base defaults).
| File **missing**| Ignored — no env push for that side, no cloud wipe |
99
+
| File **present, empty**| Wipe — warn + `[y/N]` before deleting all cloud keys on that side |
107
100
108
-
Recommended sync semantics:
101
+
### Pushing env variables
109
102
110
-
- Default: **upsert/patch** (add/update keys present in local effective env config).
111
-
- Optional: `--delete-missing` (dangerous) to remove remote keys not present locally.
112
-
- Optional: `--dry-run` to show changes without applying.
103
+
-`ensemble push --app <alias>` pushes the **effective** env for that alias.
104
+
- Config and secrets are pushed independently (missing file → that side skipped).
113
105
114
106
### Pulling env variables
115
107
116
-
Similarly, pulling should be scoped:
108
+
-`ensemble pull --app <alias>` writes cloud env into the scoped target file when in scoped mode (`.env.config.<alias>` / `.env.secrets.<alias>`), leaving the base file untouched.
109
+
- In legacy mode, pull continues to write `.env.config` / `.env.secrets`.
117
110
118
-
-`ensemble pull --app prod` should update **only**`.env.config.prod` (or optionally print a diff).
119
-
- Avoid writing prod keys into `.env.config` unless explicitly requested.
111
+
### Release use
112
+
113
+
-`ensemble release use` restores snapshot config into the same write target as pull (scoped or base).
120
114
121
115
---
122
116
123
117
## Asset-generated keys and `.env.config`
124
118
125
-
Today, the CLI “upserts”`.env.config`to ensure asset-related keys exist after:
119
+
The CLI upserts `.env.config`for asset-related keys after:
126
120
127
121
-`ensemble add asset`
128
122
-`ensemble push` (asset upload)
129
-
-`ensemble pull` (asset sync)
130
-
131
-
This design proposes:
132
-
133
-
- Keep `.env.config` as a base defaults file for users.
134
-
- Write **asset-generated keys into the alias file** by default (because assets are associated with a specific app target).
135
123
136
-
Suggested split:
137
-
138
-
-`.env.config`: user-managed shared defaults (checked in or not—team choice)
- any cloud-provided asset usage env keys for that target
142
-
143
-
Backwards-compatibility note:
144
-
145
-
- If alias files are not in use yet, continue writing to `.env.config` as today.
146
-
- Once alias files exist (or a new setting/flag opts into alias-mode), write to alias files.
124
+
Pull writes asset env keys (`assets=`, per-asset keys) into the resolved config file for the active alias (base or scoped). `ensemble add asset` still upserts the base `.env.config`.
147
125
148
126
---
149
127
150
-
## Safety and production protections
151
-
152
-
To reduce “oops pushed dev to prod” failures:
128
+
## Safety
153
129
154
-
-**Require explicit target** for sensitive operations (recommended UX):
155
-
- For example, pushing env vars could require `--app` when multiple apps exist in `ensemble.config.json`.
156
-
-**Stronger confirmations** for production-like aliases (e.g. `prod`, `production`):
157
-
- Show a diff summary
158
-
- Require a typed confirmation or `--yes`
159
-
-**Never default to destructive deletes**:
160
-
-`--delete-missing` must be opt-in.
130
+
-**Never default to destructive deletes** except when a local env file exists but is empty (explicit wipe semantics above).
131
+
-**`--delete-missing`** is not implemented; local-only keys are not auto-deleted from cloud on push.
161
132
162
133
---
163
134
@@ -181,14 +152,6 @@ At minimum, consider adding these to `.gitignore`:
181
152
182
153
If you _do_ want to commit alias files for non-secret config, use a more selective ignore pattern or separate “public” vs “secret” configs.
183
154
184
-
### CLI handling expectations for secrets
185
-
186
-
If/when the CLI reads or syncs secrets:
187
-
188
-
- Never print secret values in logs (even in `--verbose`).
189
-
- Prefer diff output that only shows keys changed (and counts), not values.
190
-
- Consider stronger confirmations / restrictions for production aliases.
0 commit comments