@@ -46,53 +46,62 @@ export function collectAssetEnvKeys(assetFileNames: string[] = []): Set<string>
4646 return new Set ( [ 'assets' , ...assetFileNames . map ( deriveAssetEnvKey ) ] ) ;
4747}
4848
49- export function stripAssetKeysFromConfigDto (
49+ function filterConfigEnvVariables (
5050 config : ConfigDTO | undefined ,
51- assetFileNames : string [ ] = [ ]
52- ) : ConfigDTO | undefined {
53- const assetKeys = collectAssetEnvKeys ( assetFileNames ) ;
54- const envVariables : Record < string , string > = { } ;
51+ includeKey : ( key : string ) => boolean
52+ ) : Record < string , string > {
5553 const vars = config ?. envVariables ;
56- if ( ! vars || typeof vars !== 'object' ) return undefined ;
54+ if ( ! vars || typeof vars !== 'object' ) return { } ;
55+ const envVariables : Record < string , string > = { } ;
5756 for ( const [ key , value ] of Object . entries ( vars ) ) {
58- if ( assetKeys . has ( key ) || value === undefined || value === null ) continue ;
57+ if ( ! includeKey ( key ) || value === undefined || value === null ) continue ;
5958 envVariables [ key ] = String ( value ) ;
6059 }
61- return Object . keys ( envVariables ) . length > 0 ? { envVariables } : undefined ;
60+ return envVariables ;
6261}
6362
64- export function buildConfigDtoFromEnvConfigFile (
63+ function buildConfigDtoFromEntries (
6564 entries : EnvEntry [ ] ,
66- assetFileNames : string [ ] = [ ]
65+ options ?: { excludeKeys ?: Set < string > }
6766) : ConfigDTO | undefined {
68- const assetKeys = collectAssetEnvKeys ( assetFileNames ) ;
6967 const envVariables : Record < string , string > = { } ;
7068 for ( const entry of entries ) {
71- if ( assetKeys . has ( entry . key ) ) continue ;
69+ if ( options ?. excludeKeys ? .has ( entry . key ) ) continue ;
7270 envVariables [ entry . key ] = entry . value ;
7371 }
7472 return Object . keys ( envVariables ) . length > 0 ? { envVariables } : undefined ;
7573}
7674
75+ export function stripAssetKeysFromConfigDto (
76+ config : ConfigDTO | undefined ,
77+ assetFileNames : string [ ] = [ ]
78+ ) : ConfigDTO | undefined {
79+ const assetKeys = collectAssetEnvKeys ( assetFileNames ) ;
80+ const envVariables = filterConfigEnvVariables ( config , ( key ) => ! assetKeys . has ( key ) ) ;
81+ return Object . keys ( envVariables ) . length > 0 ? { envVariables } : undefined ;
82+ }
83+
84+ export function buildConfigDtoFromEnvConfigFile (
85+ entries : EnvEntry [ ] ,
86+ assetFileNames : string [ ] = [ ]
87+ ) : ConfigDTO | undefined {
88+ return buildConfigDtoFromEntries ( entries , {
89+ excludeKeys : collectAssetEnvKeys ( assetFileNames ) ,
90+ } ) ;
91+ }
92+
7793export function mergeConfigDtoForPush (
7894 localNonAssetConfig : ConfigDTO | undefined ,
7995 cloudConfig : ConfigDTO | undefined ,
8096 assetFileNames : string [ ] = [ ]
8197) : ConfigDTO {
8298 const assetKeys = collectAssetEnvKeys ( assetFileNames ) ;
83- const merged : Record < string , string > = { } ;
84-
85- for ( const [ key , value ] of Object . entries ( cloudConfig ?. envVariables ?? { } ) ) {
86- if ( assetKeys . has ( key ) && value !== undefined && value !== null ) {
87- merged [ key ] = String ( value ) ;
88- }
89- }
90-
91- for ( const [ key , value ] of Object . entries ( localNonAssetConfig ?. envVariables ?? { } ) ) {
92- merged [ key ] = String ( value ) ;
93- }
94-
95- return { envVariables : merged } ;
99+ return {
100+ envVariables : {
101+ ...filterConfigEnvVariables ( cloudConfig , ( key ) => assetKeys . has ( key ) ) ,
102+ ...( localNonAssetConfig ?. envVariables ?? { } ) ,
103+ } ,
104+ } ;
96105}
97106
98107export function buildSecretsDtoFromEnvSecretsFile ( entries : EnvEntry [ ] ) : SecretDTO | undefined {
@@ -104,11 +113,25 @@ export function buildSecretsDtoFromEnvSecretsFile(entries: EnvEntry[]): SecretDT
104113 return { secrets } ;
105114}
106115
107- export async function readProjectEnvFiles (
108- projectRoot : string ,
109- assetFileNames : string [ ] = [ ]
110- ) : Promise < LocalEnvFiles > {
111- void assetFileNames ;
116+ export function warnIfMissingEnvFilesForPush (
117+ localEnv : LocalEnvFiles ,
118+ cloudEnv : CloudEnvState ,
119+ assetFileNames : string [ ] = [ ] ,
120+ warn : ( message : string ) => void
121+ ) : void {
122+ if ( ! localEnv . envConfigPresent && cloudHasNonAssetConfig ( cloudEnv . config , assetFileNames ) ) {
123+ warn (
124+ '.env.config is missing locally. Run `ensemble pull` to restore env vars from cloud. Config env push skipped.'
125+ ) ;
126+ }
127+ if ( ! localEnv . envSecretsPresent && cloudHasSecrets ( cloudEnv . secrets ) ) {
128+ warn (
129+ '.env.secrets is missing locally. Run `ensemble pull` to restore secrets from cloud. Secrets env push skipped.'
130+ ) ;
131+ }
132+ }
133+
134+ export async function readProjectEnvFiles ( projectRoot : string ) : Promise < LocalEnvFiles > {
112135 const [ envConfigPresent , envSecretsPresent ] = await Promise . all ( [
113136 envFileExists ( projectRoot , '.env.config' ) ,
114137 envFileExists ( projectRoot , '.env.secrets' ) ,
@@ -245,12 +268,7 @@ export function buildEnvPushDiff(
245268}
246269
247270export function buildConfigDtoForReleaseSnapshot ( entries : EnvEntry [ ] ) : ConfigDTO | undefined {
248- if ( entries . length === 0 ) return undefined ;
249- const envVariables : Record < string , string > = { } ;
250- for ( const entry of entries ) {
251- envVariables [ entry . key ] = entry . value ;
252- }
253- return { envVariables } ;
271+ return buildConfigDtoFromEntries ( entries ) ;
254272}
255273
256274/** restores `.env.config` from a release snapshot; secrets are never included in releases */
@@ -286,12 +304,8 @@ async function upsertCloudAssetConfigEntries(
286304 assetFileNames : string [ ] = [ ]
287305) : Promise < void > {
288306 const assetKeys = collectAssetEnvKeys ( assetFileNames ) ;
289- const vars = cloudConfig ?. envVariables ?? { } ;
290- const entries : EnvEntry [ ] = [ ] ;
291- for ( const [ key , value ] of Object . entries ( vars ) ) {
292- if ( ! assetKeys . has ( key ) || value === undefined || value === null ) continue ;
293- entries . push ( { key, value : String ( value ) } ) ;
294- }
307+ const envVariables = filterConfigEnvVariables ( cloudConfig , ( key ) => assetKeys . has ( key ) ) ;
308+ const entries = Object . entries ( envVariables ) . map ( ( [ key , value ] ) => ( { key, value } ) ) ;
295309 if ( entries . length > 0 ) {
296310 await upsertEnvFile ( projectRoot , '.env.config' , entries ) ;
297311 }
0 commit comments