Skip to content

Commit 7425739

Browse files
committed
✨ env file synchronization with config file
1 parent 026e0ef commit 7425739

File tree

6 files changed

+124
-40
lines changed

6 files changed

+124
-40
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "workspaces",
3-
"version": "0.6.8",
3+
"version": "0.6.9",
44
"description": "GraphQL -> anything. Use GraphQL as your source of truth. GraphQL Editor Official CLI.",
55
"author": "Artur Czemiel",
66
"license": "MIT",

packages/cli/src/commands/common/dev.ts

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { DEPLOY_FILE, STUCCO_FILE } from '@/gshared/constants/index.js';
55
import path from 'path';
66
import fs from 'fs';
77
import process from 'node:process';
8-
import * as dotenv from 'dotenv';
8+
import { getEnvFile } from '@/common/envs.js';
99

1010
let killing = false;
1111
let changingFile = false;
@@ -20,7 +20,7 @@ export const CommandDev = async () => {
2020
onCreate: async () => {
2121
const envFile = getEnvFile();
2222
await onCreateStucco({
23-
envs: envFile,
23+
envs: envFile?.content,
2424
});
2525
},
2626
});
@@ -30,7 +30,7 @@ export const CommandDev = async () => {
3030
const envFile = getEnvFile();
3131
changingFile = true;
3232
onCreateStucco({
33-
envs: envFile,
33+
envs: envFile?.content,
3434
}).then((e) => {
3535
changingFile = false;
3636
});
@@ -55,13 +55,3 @@ export const CommandDev = async () => {
5555
});
5656
return;
5757
};
58-
59-
const getEnvFile = () => {
60-
const dir = fs.readdirSync(process.cwd());
61-
const envFile = dir.find((e) => e.startsWith('.env'));
62-
if (envFile) {
63-
const filePath = path.join(process.cwd(), envFile);
64-
const fileContent = fs.readFileSync(filePath, 'utf-8');
65-
return dotenv.parse(fileContent);
66-
}
67-
};
Lines changed: 48 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
import { CommandAzureGitlab } from '@/commands/externalCi/azure.js';
2+
import {
3+
CommandEnvs,
4+
CommandGenerateEnvs,
5+
} from '@/commands/externalCi/envs.js';
6+
import { Configuration } from '@/Configuration/index.js';
27
import { AzureGitlabCIConf } from '@/Configuration/index.js';
38
import { CommandModule, Options } from 'yargs';
49

@@ -7,31 +12,48 @@ export default {
712
describe:
813
'External continous integration generation commands. Azure Functions for now.',
914
builder: (yargs) => {
10-
return yargs.command(
11-
'azure-gitlab',
12-
'Generate .gitlab-ci.yml file to deploy backend to Azure functions',
13-
async (yargs) => {
14-
yargs.options({
15-
azureEnv: {
16-
type: 'string',
17-
describe: 'Comma separated environment variables names',
18-
},
19-
azureFnName: {
20-
type: 'string',
21-
describe: 'Globally unique name of azure service',
22-
},
23-
azureCors: {
24-
type: 'string',
25-
describe:
26-
'Space separated CORS addresses for production and staging',
27-
},
28-
} as {
29-
[P in keyof AzureGitlabCIConf]: Options;
30-
});
31-
},
32-
async (argv) => {
33-
await CommandAzureGitlab(argv as any);
34-
},
35-
);
15+
return yargs
16+
.command(
17+
'azure-gitlab',
18+
'Generate .gitlab-ci.yml file to deploy backend to Azure functions',
19+
async (yargs) => {
20+
yargs.options({
21+
azureEnv: {
22+
type: 'string',
23+
describe: 'Comma separated environment variables names',
24+
},
25+
azureFnName: {
26+
type: 'string',
27+
describe: 'Globally unique name of azure service',
28+
},
29+
azureCors: {
30+
type: 'string',
31+
describe:
32+
'Space separated CORS addresses for production and staging',
33+
},
34+
} as {
35+
[P in keyof AzureGitlabCIConf]: Options;
36+
});
37+
},
38+
async (argv) => {
39+
await CommandAzureGitlab(argv as any);
40+
},
41+
)
42+
.command(
43+
'env',
44+
`Inject envs from .env file to ${Configuration.CONFIG_NAME}`,
45+
async (yargs) => {},
46+
async (argv) => {
47+
await CommandEnvs();
48+
},
49+
)
50+
.command(
51+
'env-generate',
52+
`Generate .env file from ${Configuration.CONFIG_NAME}. Works idempotent. When you already have an .env file it adds missing keys `,
53+
async (yargs) => {},
54+
async (argv) => {
55+
await CommandGenerateEnvs();
56+
},
57+
);
3658
},
3759
} as CommandModule;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { Config, Configuration } from '@/Configuration/index.js';
2+
import { getEnvFile } from '@/common/envs.js';
3+
import { logger } from '@/common/log/index.js';
4+
import fs from 'fs';
5+
import path from 'path';
6+
export const CommandEnvs = () => {
7+
const envFile = getEnvFile();
8+
if (!envFile) {
9+
logger(
10+
'No .env file in current path. Please create .env file first',
11+
'error',
12+
);
13+
return;
14+
}
15+
const commaSeparatedEnvKeys = Object.keys(envFile.content).join(',');
16+
Config.set({
17+
azureEnv: commaSeparatedEnvKeys,
18+
});
19+
logger(
20+
`Successfully wrote .env keys to ${Configuration.CONFIG_NAME} file.`,
21+
'success',
22+
);
23+
return;
24+
};
25+
26+
export const CommandGenerateEnvs = () => {
27+
const envFile = getEnvFile();
28+
const envKeysInConfig = Config.get('azureEnv')?.split(',');
29+
const envKeysInFile = envFile ? Object.keys(envFile.content) : [];
30+
const keysInConfigButNotInFile = envKeysInConfig.filter(
31+
(k) => !envKeysInFile.includes(k),
32+
);
33+
const mappedKeysAddon = keysInConfigButNotInFile
34+
.map((k) => `${k}=`)
35+
.join('\n');
36+
37+
fs.appendFileSync(
38+
envFile?.path || path.join(process.cwd(), '.env'),
39+
envFile?.path ? '\n' + mappedKeysAddon : mappedKeysAddon,
40+
);
41+
42+
logger(
43+
`Successfully synchronized ${Configuration.CONFIG_NAME} envs to .env file.`,
44+
'success',
45+
);
46+
return;
47+
};

packages/cli/src/common/envs.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import fs from 'fs';
2+
import * as dotenv from 'dotenv';
3+
import path from 'path';
4+
5+
export const getEnvFile = () => {
6+
const dir = fs.readdirSync(process.cwd());
7+
const baseEnvFile = dir.find((e) => e === '.env');
8+
const envFile = baseEnvFile || dir.find((e) => e.startsWith('.env'));
9+
if (envFile) {
10+
const filePath = path.join(process.cwd(), envFile);
11+
const fileContent = fs.readFileSync(filePath, 'utf-8');
12+
return {
13+
content: dotenv.parse(fileContent),
14+
path: path.join(process.cwd(), envFile),
15+
};
16+
}
17+
};

packages/cli/src/integrations/api.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ export const getResolverData = <T>(
2121
return resolver as ResolverConfig<T>;
2222
};
2323

24+
export const getSchema = ({
25+
schemaPath = path.join(process.cwd(), 'schema.graphql'),
26+
}: {
27+
schemaPath?: string;
28+
}) => {
29+
return fs.readFileSync(schemaPath, 'utf-8');
30+
};
31+
2432
export const getReturnTypeName = (ref: TypeRef): string | undefined => {
2533
if (!ref) return;
2634
if ('nonNull' in ref || 'list' in ref) {

0 commit comments

Comments
 (0)