terraguardian-cli 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -1
- package/src/features/build/go-build.js +23 -0
- package/src/features/build/helpers.js +44 -0
- package/src/features/build/node-build.js +63 -0
- package/src/features/build/zip.js +100 -0
- package/src/index.js +15 -2
- package/.babelrc +0 -7
- package/.eslintrc.yaml +0 -12
- package/.gitlab-ci.yml +0 -5
- package/.prettierrc +0 -6
- package/jest.config.js +0 -21
- package/test/main.test.js +0 -3
package/package.json
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "terraguardian-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "CLI that helps with projects that are built with terraform and helps with deployments of lambda src code",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"tg-cli": "src/index.js"
|
|
8
8
|
},
|
|
9
|
+
"files": [
|
|
10
|
+
"src",
|
|
11
|
+
"bin"
|
|
12
|
+
|
|
13
|
+
],
|
|
9
14
|
"scripts": {
|
|
10
15
|
"test": "jest",
|
|
11
16
|
"lint": "eslint src",
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const util = require('util');
|
|
3
|
+
const exec = util.promisify(require('child_process').exec);
|
|
4
|
+
|
|
5
|
+
const GO_BINARY_NAME = 'bootstrap';
|
|
6
|
+
const GO_ARCHITECTURE = 'arm64';
|
|
7
|
+
|
|
8
|
+
const { GO_LAMBDA_SRC_DIR, LAMBDA_BUILD_DIR } = require('../../common/constants');
|
|
9
|
+
|
|
10
|
+
async function buildGoLambda(lambdaName) {
|
|
11
|
+
console.log('Building the go lambda...');
|
|
12
|
+
const goLambdaSrcPath = `${GO_LAMBDA_SRC_DIR}/${lambdaName.split('lambda_')[1]}`;
|
|
13
|
+
const buildOutputDir = `${LAMBDA_BUILD_DIR}/${lambdaName}`;
|
|
14
|
+
const buildCommand = `GOOS='linux' GOARCH='${GO_ARCHITECTURE}' GO111MODULE='on' go build -tags 'lambda.norpc' -o '${buildOutputDir}/${GO_BINARY_NAME}' '${goLambdaSrcPath}'`;
|
|
15
|
+
|
|
16
|
+
await exec(buildCommand);
|
|
17
|
+
console.log(chalk.green('Successfully built the lambda'));
|
|
18
|
+
return `${buildOutputDir}/${GO_BINARY_NAME}`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = {
|
|
22
|
+
buildGoLambda,
|
|
23
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const { execSync } = require('child_process');
|
|
2
|
+
const { NODE_RUNTIME_TF_VAR, GO_RUNTIME_TF_VAR } = require('../../common/constants');
|
|
3
|
+
|
|
4
|
+
const getEntryPointPaths = (config) => execSync(`${config.search} -name "${config.entryPoint}" -print`)
|
|
5
|
+
.toString()
|
|
6
|
+
.split('\n')
|
|
7
|
+
.filter(Boolean);
|
|
8
|
+
|
|
9
|
+
const getNormalizedLambdaNames = (lamdbdaPaths) => lamdbdaPaths.map((lambdaPath) => {
|
|
10
|
+
const regex = /lambda_(\w+)/g;
|
|
11
|
+
return regex.exec(lambdaPath)[0];
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
function findEntryPoints(runtime, lambdaName) {
|
|
15
|
+
const findConfig = {
|
|
16
|
+
[GO_RUNTIME_TF_VAR]: {
|
|
17
|
+
search: 'find "$(pwd)/build" -path "$(pwd)/build" -prune -o -name node_modules -prune -o -path "$(pwd)/dist" -prune -o',
|
|
18
|
+
entryPoint: 'main.go',
|
|
19
|
+
regexFilter: null,
|
|
20
|
+
},
|
|
21
|
+
[NODE_RUNTIME_TF_VAR]: {
|
|
22
|
+
search: 'find "$(pwd)/modules" -path "$(pwd)/dist" -prune -o -name node_modules -prune -o -path "$(pwd)/build" -prune -o',
|
|
23
|
+
entryPoint: 'index.js',
|
|
24
|
+
regexFilter: 'lambda_[^/]+/src/index.js',
|
|
25
|
+
},
|
|
26
|
+
}[runtime];
|
|
27
|
+
const entryPointPaths = getEntryPointPaths(findConfig);
|
|
28
|
+
|
|
29
|
+
if (lambdaName) {
|
|
30
|
+
return entryPointPaths.find((path) => path.includes(lambdaName));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const regex = new RegExp(findConfig.regexFilter);
|
|
34
|
+
if (regex) {
|
|
35
|
+
return entryPointPaths.filter((path) => regex.test(path));
|
|
36
|
+
}
|
|
37
|
+
return entryPointPaths;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports = {
|
|
41
|
+
findEntryPoints,
|
|
42
|
+
getEntryPointPaths,
|
|
43
|
+
getNormalizedLambdaNames,
|
|
44
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
LAMBDA_BUILD_DIR,
|
|
5
|
+
WEBPACK_FILE_PATH,
|
|
6
|
+
NODE_LIBARY_TYPE,
|
|
7
|
+
DEFAULT_WEBPACK_MODE,
|
|
8
|
+
NODE_BUILD_FILE_NAME,
|
|
9
|
+
NODE_RUNTIME_TF_VAR,
|
|
10
|
+
} = require('../../common/constants');
|
|
11
|
+
const { executeCommand } = require('../../common/helpers');
|
|
12
|
+
const FileHandler = require('../../fs-utils/FileHandler');
|
|
13
|
+
const { findEntryPoints, getNormalizedLambdaNames } = require('./helpers');
|
|
14
|
+
|
|
15
|
+
function getWebpackBuildCommand(lambdaName, lambdaPath, buildOutputDir) {
|
|
16
|
+
let buildCommand;
|
|
17
|
+
const webpackExists = FileHandler.doesFileExist('webpack.config.js');
|
|
18
|
+
|
|
19
|
+
if (webpackExists) {
|
|
20
|
+
console.log('Webpack exists');
|
|
21
|
+
buildCommand = (`npx webpack --config ${WEBPACK_FILE_PATH} --entry ${lambdaPath} --output-path "${buildOutputDir}" --output-filename ${NODE_BUILD_FILE_NAME}`);
|
|
22
|
+
} else {
|
|
23
|
+
console.log('Webpack does not exist');
|
|
24
|
+
buildCommand = (`npx webpack -entry ${lambdaPath} --output "${buildOutputDir}" --output-filename ${NODE_BUILD_FILE_NAME} -t ${NODE_LIBARY_TYPE} -target 'node' -mode ${DEFAULT_WEBPACK_MODE}`);
|
|
25
|
+
}
|
|
26
|
+
return buildCommand;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function buildNodeLambda(lambdaName, lambdaPath) {
|
|
30
|
+
console.log(chalk.blue(`Building the Node Lambda ${lambdaName}...`));
|
|
31
|
+
|
|
32
|
+
const buildOutputDir = `${LAMBDA_BUILD_DIR}/${lambdaName}`;
|
|
33
|
+
|
|
34
|
+
const buildCommand = await getWebpackBuildCommand(lambdaName, lambdaPath, buildOutputDir);
|
|
35
|
+
console.log(await executeCommand(buildCommand));
|
|
36
|
+
console.log(chalk.green('Successfully built the Lambda'));
|
|
37
|
+
return `${buildOutputDir}/${NODE_BUILD_FILE_NAME}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function buildNodeLambdas() {
|
|
41
|
+
const lambdaPaths = findEntryPoints(NODE_RUNTIME_TF_VAR);
|
|
42
|
+
const normalizedLambdaNames = getNormalizedLambdaNames(lambdaPaths);
|
|
43
|
+
if (lambdaPaths.length > 0) {
|
|
44
|
+
if (FileHandler.doesPathExist('./node_modules')) {
|
|
45
|
+
console.log('node_modules exists');
|
|
46
|
+
} else {
|
|
47
|
+
console.log('node_modules does not exist');
|
|
48
|
+
console.log('Installing node_modules');
|
|
49
|
+
const { stdout, stderr } = await executeCommand('npm install');
|
|
50
|
+
console.log(stdout);
|
|
51
|
+
console.log(stderr);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
lambdaPaths.forEach((lambdaPath, index) => {
|
|
56
|
+
buildNodeLambda(normalizedLambdaNames[index], lambdaPath);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module.exports = {
|
|
61
|
+
buildNodeLambda,
|
|
62
|
+
buildNodeLambdas,
|
|
63
|
+
};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const archiver = require('archiver');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const { promisify } = require('util');
|
|
5
|
+
|
|
6
|
+
const readdir = promisify(fs.readdir);
|
|
7
|
+
const stat = promisify(fs.stat);
|
|
8
|
+
const mkdir = promisify(fs.mkdir);
|
|
9
|
+
// const rename = promisify(fs.rename);
|
|
10
|
+
|
|
11
|
+
// TODO: Revist this later for hasing the build dir
|
|
12
|
+
// function getFileHash(filePath) {
|
|
13
|
+
// const data = fs.readFileSync(filePath);
|
|
14
|
+
// return crypto.createHash('md5').update(data).digest('hex');
|
|
15
|
+
// }
|
|
16
|
+
|
|
17
|
+
async function setTimestampToSameTimeRecursive(dirPath, timestamp) {
|
|
18
|
+
fs.readdirSync(dirPath).forEach((file) => {
|
|
19
|
+
const filePath = path.join(dirPath, file);
|
|
20
|
+
const statOutput = fs.statSync(filePath);
|
|
21
|
+
|
|
22
|
+
if (statOutput.isDirectory()) {
|
|
23
|
+
fs.utimesSync(filePath, timestamp, timestamp);
|
|
24
|
+
setTimestampToSameTimeRecursive(filePath, timestamp);
|
|
25
|
+
} else {
|
|
26
|
+
fs.utimesSync(filePath, timestamp, timestamp);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function zipFolder(sourceFolder, destinationZip) {
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
const output = fs.createWriteStream(destinationZip);
|
|
34
|
+
const archive = archiver('zip');
|
|
35
|
+
|
|
36
|
+
output.on('close', async () => {
|
|
37
|
+
// TODO: Return to this if needed for hashing
|
|
38
|
+
// console.log("zipFileName")
|
|
39
|
+
// console.log(zipFileName)
|
|
40
|
+
|
|
41
|
+
// const zipHash = getFileHash(path.join(zipFileName))
|
|
42
|
+
// const zipName = await getZipName(zipFileName, "zipHash")
|
|
43
|
+
// await fs.renameSync(zipFileName, path.join(destinationZip, zipName))
|
|
44
|
+
// console.log(`${zipFileName} zip file has been created`)
|
|
45
|
+
resolve();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
output.on('error', (err) => {
|
|
49
|
+
reject(err);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
archive.pipe(output);
|
|
53
|
+
archive.directory(sourceFolder, false);
|
|
54
|
+
archive.finalize();
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function zipAndMoveFolders(sourceFolder, destinationFolder) {
|
|
59
|
+
const zipFiles = {}; // Object to store zip file information
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
const ts = new Date(2020, 0, 1);
|
|
63
|
+
await setTimestampToSameTimeRecursive(sourceFolder, ts);
|
|
64
|
+
// Ensure the destination folder exists
|
|
65
|
+
await mkdir(destinationFolder, { recursive: true });
|
|
66
|
+
|
|
67
|
+
// Read all files and subdirectories in the source folder
|
|
68
|
+
const entries = await readdir(sourceFolder);
|
|
69
|
+
// eslint-disable-next-line
|
|
70
|
+
for (const entry of entries) {
|
|
71
|
+
const entryPath = path.join(sourceFolder, entry);
|
|
72
|
+
const stats = await stat(entryPath);
|
|
73
|
+
|
|
74
|
+
if (stats.isDirectory()) {
|
|
75
|
+
// If the entry is a directory, zip it and move the resulting zip file
|
|
76
|
+
const zipFileName = `${entry}.zip`;
|
|
77
|
+
const zipFilePath = path.join(destinationFolder, zipFileName);
|
|
78
|
+
await zipFolder(entryPath, zipFilePath, zipFileName);
|
|
79
|
+
|
|
80
|
+
// Add the zip file details to the object
|
|
81
|
+
zipFiles[entry] = {
|
|
82
|
+
name: zipFileName,
|
|
83
|
+
path: zipFilePath,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
console.log('All folders have been zipped and moved successfully.');
|
|
88
|
+
} catch (error) {
|
|
89
|
+
console.error('Failed to zip and move folders:', error);
|
|
90
|
+
}
|
|
91
|
+
return zipFiles; // Return the JSON object
|
|
92
|
+
}
|
|
93
|
+
// TODO: Revist later
|
|
94
|
+
// async function getZipName(builtLambda, zipHash) {
|
|
95
|
+
// return `${builtLambda}_-_${zipHash}.zip`
|
|
96
|
+
// }
|
|
97
|
+
|
|
98
|
+
module.exports = {
|
|
99
|
+
zipAndMoveFolders,
|
|
100
|
+
};
|
package/src/index.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const yargs = require('yargs');
|
|
4
4
|
const chalk = require('chalk');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const fs = require('fs');
|
|
5
7
|
const { zipAndMoveFolders } = require('./features/build/zip');
|
|
6
8
|
const { buildNodeLambdas } = require('./features/build/node-build');
|
|
7
9
|
const { deployLambda } = require('./features/deploy');
|
|
@@ -30,8 +32,19 @@ const argv = yargs
|
|
|
30
32
|
|
|
31
33
|
async function executeUserCommand(userCommands) {
|
|
32
34
|
if (userCommands.z || userCommands.zip) {
|
|
33
|
-
|
|
34
|
-
console.log('
|
|
35
|
+
// Write the result to a JSON file
|
|
36
|
+
console.log('Zipping folders...');
|
|
37
|
+
const zipDetails = await zipAndMoveFolders('build', 'dist');
|
|
38
|
+
|
|
39
|
+
// Write the result to a JSON file
|
|
40
|
+
const resultFilePath = path.join(process.cwd(), 'zip-details.json');
|
|
41
|
+
await fs.promises.writeFile(
|
|
42
|
+
resultFilePath,
|
|
43
|
+
JSON.stringify(zipDetails, null, 2),
|
|
44
|
+
'utf-8',
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
console.log(`Zipping complete. Details saved to ${resultFilePath}`);
|
|
35
48
|
} else if (userCommands.d || userCommands.deploy) {
|
|
36
49
|
console.log('deploying');
|
|
37
50
|
await deployLambda();
|
package/.babelrc
DELETED
package/.eslintrc.yaml
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
extends:
|
|
2
|
-
- airbnb-base
|
|
3
|
-
- plugin:import/errors
|
|
4
|
-
- plugin:import/warnings
|
|
5
|
-
rules:
|
|
6
|
-
prefer-destructuring: off
|
|
7
|
-
no-template-curly-in-string: warn
|
|
8
|
-
no-return-await: off
|
|
9
|
-
no-await-in-loop: warn
|
|
10
|
-
no-plusplus: off
|
|
11
|
-
import/extensions: off
|
|
12
|
-
import/no-unresolved: "off"
|
package/.gitlab-ci.yml
DELETED
package/.prettierrc
DELETED
package/jest.config.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
roots: ['<rootDir>'],
|
|
3
|
-
moduleFileExtensions: ['js', 'json'],
|
|
4
|
-
testEnvironment: 'node',
|
|
5
|
-
testRegex: '\\.test\\.js$',
|
|
6
|
-
transform: {
|
|
7
|
-
'^.+\\.js$': 'babel-jest',
|
|
8
|
-
},
|
|
9
|
-
collectCoverage: true,
|
|
10
|
-
coverageDirectory: 'test/coverage',
|
|
11
|
-
collectCoverageFrom: ['<rootDir>/src/**/*.js'],
|
|
12
|
-
coveragePathIgnorePatterns: ['/node_modules/', '/build/', '/dist/'], // Add paths to ignore here
|
|
13
|
-
coverageThreshold: {
|
|
14
|
-
global: {
|
|
15
|
-
branches: 0,
|
|
16
|
-
functions: 0,
|
|
17
|
-
lines: 0,
|
|
18
|
-
statements: 0,
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
};
|
package/test/main.test.js
DELETED