Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
DEV_LEMON_PAYMENT_GATEWAY_CARD_GBP=GBP gateway
STAGING_LEMON_PAYMENT_GATEWAY_CARD_GBP=GBP test gateway
DYNAMO_DB_ACCOUNTS_TABLE_ARN=ARNold Schwarzenegger
DYNAMO_DB_ENDPOINT=pointy end
6 changes: 3 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ typings/
# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@supachris28, why has this been removed?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

There is no runtime for this, it is a module, so no real env variables to be used. I've added a .env to be used for testing to ensure it works as expected.


# next.js build output
.next

# test output file
serverless.env.yml
247 changes: 171 additions & 76 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,90 +13,185 @@
// See the License for the specific language governing permissions and
// limitations under the License.

const log = require('debug')('packt:serverless-env-generator');

const commander = require('commander');
const Fs = require('fs');
const fse = require('fs-extra');
const YAML = require('yamljs');
const path = require('path');

// Commander config
commander
.version(require('./package.json').version)
.option('--stage [type]', 'Add deployment stage [stage]', 'dev')
.option(
'--serverless-env-file [filename]',
'Set the serverless env file',
'serverless.env.yml',
)
.option('--env-variables [filename|string]', 'Set the serverless env file')
.option('--local, -l', 'Use .env file')
.parse(process.argv);

// Use local ENV
if (commander.local) {
// eslint-disable-next-line global-require
require('dotenv').load();
}

// Name of the ENV storage file
const { serverlessEnvFile } = commander;

// Hard code the STAGE to dev for initial run through or if not set
const STAGE = commander.stage;

// The ENV variables
if (!commander.envVariables) {
// eslint-disable-next-line no-console
console.log(
'Please provide --env-variables either file containing an array of ENV variable names or a comma (,) separated list of ENV variable names',
);
process.exit(1);
}

const availableEnvs = Fs.existsSync(commander.envVariables)
// eslint-disable-next-line import/no-dynamic-require
? require(commander.envVariables)
: commander.envVariables.split(',');

// Prepopulate the ENV if a serverless.env.yml exists
const envVariables = Fs.existsSync(serverlessEnvFile)
? YAML.load(serverlessEnvFile)
: {};

// If the STAGE doesn't exist, create it
if (!envVariables[STAGE]) {
envVariables[STAGE] = {};
}

// Populate with blank variables for anything not already defined
for (let i = 0; i < availableEnvs.length; i += 1) {
if (!envVariables[STAGE][availableEnvs[i]]) {
envVariables[STAGE][availableEnvs[i]] = '';
}
}

// Populate from ENV variables
Object.keys(envVariables[STAGE]).map((key) => {
const stageKey = `${STAGE}_${key}`.toUpperCase();
if (process.env[key] || process.env[stageKey]) {
envVariables[STAGE][key] = process.env[stageKey]
? process.env[stageKey]
: process.env[key];

const loadDotEnv = async (filename) => {
const buffer = await fse.readFile(filename);
const asString = buffer.toString();
log('current: %S', asString);

const result = {};
asString
.split('\n')
.forEach((record) => {
const split = record.split('=');
// eslint-disable-next-line prefer-destructuring
if (split && split[0] && split[1]) result[split[0]] = split[1];
});

return result;
};

const buildEnvFile = (envVariables) => {
let file = '';
Object.keys(envVariables)
.forEach((key) => {
const value = envVariables[key];

file += `${key}=${value}\n`;
});

return file;
};

const loadFile = (filename) => {
if (!commander.D) return YAML.load(filename);

return loadDotEnv(filename);
};

(async () => {
// Commander config
commander
.version(require('./package.json').version)
.option('--stage [type]', 'Add deployment stage [stage]', 'dev')
.option(
'--serverless-env-file [filename]',
'Set the serverless env file',
'serverless.env.yml',
)
.option('--env-variables [filename|string]', 'Set the serverless env file')
.option('--local, -l', 'Use .env file')
.option('--dotenv, -d', 'Write .env file rather than yaml')
.parse(process.argv);

// Use local ENV
if (commander.local || commander.L) {
log('Getting from .env');
require('dotenv').config();
}

return true;
});
// log('commander: %O', commander);

// Name of the ENV storage file
const serverlessEnvFile = commander.D ? '.env' : commander.serverlessEnvFile;

const CWD = process.cwd();

// Convert the object into YAML
const ymlEnv = YAML.stringify(envVariables);
log('PWD: %O', CWD);

// Write the YAML to disk so it can be read by sls deploy --stage <STAGE>
Fs.writeFile(serverlessEnvFile, ymlEnv, (err) => {
if (err) {
// eslint-disable-next-line no-console
console.error(err);
log('Env File: %O', serverlessEnvFile);

// Hard code the STAGE to dev for initial run through or if not set
const STAGE = commander.stage;
log('Stage: %O', STAGE);

// The ENV variables
if (!commander.envVariables) {
console.log(
'Please provide --env-variables either file containing an array of ENV variable names or a comma (,) separated list of ENV variable names',
);
process.exit(1);
}

const envVariablesPath = path.join(CWD, commander.envVariables);

log('Env Variables: %O', envVariablesPath);

const availableEnvs = Fs.existsSync(envVariablesPath)
? require(envVariablesPath)
: commander.envVariables.split(',');

log('available envs: %O', availableEnvs);

// Prepopulate the ENV if a serverless.env.yml exists
const envVariables = Fs.existsSync(serverlessEnvFile)
? await loadFile(serverlessEnvFile)
: {};

log('previous env: %O', envVariables);

// If the STAGE doesn't exist, create it
if (!commander.D && !envVariables[STAGE]) {
envVariables[STAGE] = {};
}

// Populate with blank variables for anything not already defined
if (!commander.D) {
for (let i = 0; i < availableEnvs.length; i += 1) {
if (!envVariables[STAGE][availableEnvs[i]]) {
envVariables[STAGE][availableEnvs[i]] = '';
}
}
} else {
for (let i = 0; i < availableEnvs.length; i += 1) {
if (!envVariables[availableEnvs[i]]) {
envVariables[availableEnvs[i]] = '';
}
}
}

// Populate from ENV variables
if (!commander.D) {
Object.keys(envVariables[STAGE]).map((key) => {
const stageKey = `${STAGE}_${key}`.toUpperCase();
if (process.env[key] || process.env[stageKey]) {
envVariables[STAGE][key] = process.env[stageKey]
? process.env[stageKey]
: process.env[key];
}

return true;
});
} else {
Object.keys(envVariables).map((key) => {
const stageKey = `${STAGE}_${key}`.toUpperCase();
if (process.env[key] || process.env[stageKey]) {
envVariables[key] = process.env[stageKey]
? process.env[stageKey]
: process.env[key];
}

return true;
});
}

log('new env: %O', envVariables);

// Convert the object into YAML
if (!commander.D) {
const ymlEnv = YAML.stringify(envVariables);

// Write the YAML to disk so it can be read by sls deploy --stage <STAGE>
Fs.writeFile(serverlessEnvFile, ymlEnv, (err) => {
if (err) {
// eslint-disable-next-line no-console
console.error(err);
process.exit(1);
} else {
// eslint-disable-next-line no-console
console.log(`${serverlessEnvFile} has been created`);
process.exit(0);
}
});
} else {
// eslint-disable-next-line no-console
console.log(`${serverlessEnvFile} has been created`);
process.exit(0);
const envFile = buildEnvFile(envVariables);
fse.writeFile(serverlessEnvFile, envFile)
.then(() => {
console.log(`${serverlessEnvFile} has been created`);
process.exit(0);
})
.catch((error) => {
log('error: %O', error);
console.error(error);
process.exit(1);
});
}
});
})();
Loading