@dotenvx/dotenvx 0.15.3 → 0.16.0
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 +14 -12
- package/src/cli/actions/ls.js +24 -0
- package/src/cli/actions/precommit.js +6 -1
- package/src/cli/actions/run.js +4 -3
- package/src/cli/dotenvx.js +8 -0
- package/src/lib/helpers/arrayToTree.js +24 -0
- package/src/lib/helpers/installPrecommitHook.js +63 -0
- package/src/lib/main.js +22 -7
- package/src/lib/services/ls.js +41 -0
- package/src/lib/services/precommit.js +26 -0
- package/src/shared/logger.js +0 -2
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
2
|
+
"version": "0.16.0",
|
|
3
3
|
"name": "@dotenvx/dotenvx",
|
|
4
4
|
"description": "a better dotenv–from the creator of `dotenv`",
|
|
5
5
|
"author": "@motdotla",
|
|
@@ -21,7 +21,9 @@
|
|
|
21
21
|
"scripts": {
|
|
22
22
|
"standard": "standard",
|
|
23
23
|
"standard:fix": "standard --fix",
|
|
24
|
-
"test": "
|
|
24
|
+
"test": "tap 'tests/**/*.test.js' --100",
|
|
25
|
+
"prerelease": "npm test",
|
|
26
|
+
"release": "standard-version"
|
|
25
27
|
},
|
|
26
28
|
"funding": "Have you seen dotenvx.com? run anywhere, cross-platform, and encrypted envs.",
|
|
27
29
|
"dependencies": {
|
|
@@ -30,10 +32,12 @@
|
|
|
30
32
|
"clipboardy": "^2.3.0",
|
|
31
33
|
"commander": "^11.1.0",
|
|
32
34
|
"conf": "^10.2.0",
|
|
33
|
-
"dotenv": "^16.4.
|
|
34
|
-
"dotenv-expand": "^11.0.
|
|
35
|
+
"dotenv": "^16.4.4",
|
|
36
|
+
"dotenv-expand": "^11.0.6",
|
|
35
37
|
"execa": "^5.1.1",
|
|
38
|
+
"glob": "^10.3.10",
|
|
36
39
|
"ignore": "^5.3.0",
|
|
40
|
+
"object-treeify": "1.1.33",
|
|
37
41
|
"open": "^8.4.2",
|
|
38
42
|
"ora": "^5.4.1",
|
|
39
43
|
"undici": "^5.28.3",
|
|
@@ -42,15 +46,13 @@
|
|
|
42
46
|
"xxhashjs": "^0.2.2"
|
|
43
47
|
},
|
|
44
48
|
"devDependencies": {
|
|
45
|
-
"
|
|
46
|
-
"jest-mock-process": "^2.0.0",
|
|
49
|
+
"capture-console": "^1.0.2",
|
|
47
50
|
"pkg": "^5.8.1",
|
|
48
|
-
"
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
"
|
|
52
|
-
|
|
53
|
-
]
|
|
51
|
+
"proxyquire": "^2.1.3",
|
|
52
|
+
"sinon": "^14.0.1",
|
|
53
|
+
"standard": "^17.1.0",
|
|
54
|
+
"standard-version": "^9.5.0",
|
|
55
|
+
"tap": "^16.3.0"
|
|
54
56
|
},
|
|
55
57
|
"publishConfig": {
|
|
56
58
|
"access": "public"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const treeify = require('object-treeify')
|
|
2
|
+
|
|
3
|
+
const logger = require('./../../shared/logger')
|
|
4
|
+
|
|
5
|
+
const main = require('./../../lib/main')
|
|
6
|
+
const ArrayToTree = require('./../../lib/helpers/arrayToTree')
|
|
7
|
+
|
|
8
|
+
function ls (directory) {
|
|
9
|
+
// debug args
|
|
10
|
+
logger.debug(`directory: ${directory}`)
|
|
11
|
+
|
|
12
|
+
const options = this.opts()
|
|
13
|
+
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
14
|
+
|
|
15
|
+
const filepaths = main.ls(directory, options.envFile)
|
|
16
|
+
logger.debug(`filepaths: ${JSON.stringify(filepaths)}`)
|
|
17
|
+
|
|
18
|
+
const tree = new ArrayToTree(filepaths).run()
|
|
19
|
+
logger.debug(`tree: ${JSON.stringify(tree)}`)
|
|
20
|
+
|
|
21
|
+
logger.info(treeify(tree))
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
module.exports = ls
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
2
|
const path = require('path')
|
|
3
|
-
|
|
4
3
|
const ignore = require('ignore')
|
|
5
4
|
|
|
6
5
|
const logger = require('./../../shared/logger')
|
|
6
|
+
|
|
7
7
|
const helpers = require('./../helpers')
|
|
8
8
|
|
|
9
|
+
const Precommit = require('./../../lib/services/precommit')
|
|
10
|
+
|
|
9
11
|
function precommit () {
|
|
10
12
|
const options = this.opts()
|
|
11
13
|
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
12
14
|
|
|
15
|
+
const precommit = new Precommit(options)
|
|
16
|
+
precommit.run()
|
|
17
|
+
|
|
13
18
|
// 0. handle the --install flag
|
|
14
19
|
if (options.install) {
|
|
15
20
|
installPrecommitHook()
|
package/src/cli/actions/run.js
CHANGED
|
@@ -14,7 +14,8 @@ async function run () {
|
|
|
14
14
|
|
|
15
15
|
// load from .env.vault file
|
|
16
16
|
if (process.env.DOTENV_KEY && process.env.DOTENV_KEY.length > 0) {
|
|
17
|
-
const
|
|
17
|
+
const envVaultFilepath = options.envVaultFile // .env.vault
|
|
18
|
+
const filepath = helpers.resolvePath(envVaultFilepath)
|
|
18
19
|
|
|
19
20
|
if (!fs.existsSync(filepath)) {
|
|
20
21
|
logger.error(`you set DOTENV_KEY but your .env.vault file is missing: ${filepath}`)
|
|
@@ -56,7 +57,7 @@ async function run () {
|
|
|
56
57
|
const parsed = main.parseExpand(decrypted)
|
|
57
58
|
const result = main.inject(process.env, parsed, options.overload)
|
|
58
59
|
|
|
59
|
-
logger.successv(`injecting env (${result.injected.size}) from encrypted
|
|
60
|
+
logger.successv(`injecting env (${result.injected.size}) from encrypted ${envVaultFilepath}`)
|
|
60
61
|
} catch (e) {
|
|
61
62
|
logger.error(e)
|
|
62
63
|
}
|
|
@@ -78,7 +79,7 @@ async function run () {
|
|
|
78
79
|
|
|
79
80
|
try {
|
|
80
81
|
const src = fs.readFileSync(filepath, { encoding: ENCODING })
|
|
81
|
-
const parsed = main.parseExpand(src)
|
|
82
|
+
const parsed = main.parseExpand(src, options.overload)
|
|
82
83
|
const result = main.inject(process.env, parsed, options.overload)
|
|
83
84
|
|
|
84
85
|
readableFilepaths.add(envFilepath)
|
package/src/cli/dotenvx.js
CHANGED
|
@@ -56,6 +56,7 @@ program.command('run')
|
|
|
56
56
|
.description('inject env at runtime [dotenvx run -- yourcommand]')
|
|
57
57
|
.addHelpText('after', examples.run)
|
|
58
58
|
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)', '.env')
|
|
59
|
+
.option('-fv, --env-vault-file <path>', 'path to your .env.vault file', '.env.vault')
|
|
59
60
|
.option('-o, --overload', 'override existing env variables')
|
|
60
61
|
.action(require('./actions/run'))
|
|
61
62
|
|
|
@@ -96,6 +97,13 @@ program.command('genexample')
|
|
|
96
97
|
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)', '.env')
|
|
97
98
|
.action(require('./actions/genexample'))
|
|
98
99
|
|
|
100
|
+
// dotenvx ls
|
|
101
|
+
program.command('ls')
|
|
102
|
+
.description('print all .env files in a tree structure')
|
|
103
|
+
.argument('[directory]', 'directory to list .env files from', '.')
|
|
104
|
+
.option('-f, --env-file <filenames...>', 'path(s) to your env file(s)', '.env*')
|
|
105
|
+
.action(require('./actions/ls'))
|
|
106
|
+
|
|
99
107
|
// dotenvx hub
|
|
100
108
|
program.addCommand(require('./commands/hub'))
|
|
101
109
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
class ArrayToTree {
|
|
2
|
+
constructor (arr) {
|
|
3
|
+
this.arr = arr
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
run () {
|
|
7
|
+
const tree = {}
|
|
8
|
+
|
|
9
|
+
for (let i = 0; i < this.arr.length; i++) {
|
|
10
|
+
const parts = this.arr[i].split('/')
|
|
11
|
+
let current = tree
|
|
12
|
+
|
|
13
|
+
for (let j = 0; j < parts.length; j++) {
|
|
14
|
+
const part = parts[j]
|
|
15
|
+
current[part] = current[part] || {}
|
|
16
|
+
current = current[part]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return tree
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
module.exports = ArrayToTree
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
|
|
4
|
+
const logger = require('./../../shared/logger')
|
|
5
|
+
|
|
6
|
+
const HOOK_SCRIPT = `#!/bin/sh
|
|
7
|
+
|
|
8
|
+
if ! command -v dotenvx &> /dev/null
|
|
9
|
+
then
|
|
10
|
+
echo "[dotenvx][precommit] 'dotenvx' command not found"
|
|
11
|
+
echo "[dotenvx][precommit] ? install it with [brew install dotenvx/brew/dotenvx]"
|
|
12
|
+
echo "[dotenvx][precommit] ? other install options [https://dotenvx.com/docs/install]"
|
|
13
|
+
exit 1
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
dotenvx precommit`
|
|
17
|
+
|
|
18
|
+
class InstallPrecommitHook {
|
|
19
|
+
constructor () {
|
|
20
|
+
this.hookPath = path.join('.git', 'hooks', 'pre-commit')
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
run () {
|
|
24
|
+
try {
|
|
25
|
+
// Check if the pre-commit file already exists
|
|
26
|
+
if (this._exists()) {
|
|
27
|
+
// Check if 'dotenvx precommit' already exists in the file
|
|
28
|
+
if (!this._currentHook().includes('dotenvx precommit')) {
|
|
29
|
+
this._appendHook()
|
|
30
|
+
} else {
|
|
31
|
+
logger.warnvp(`dotenvx precommit exists [${this.hookPath}]`)
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
this._createHook()
|
|
35
|
+
}
|
|
36
|
+
} catch (err) {
|
|
37
|
+
logger.errorvp(`failed to modify pre-commit hook: ${err.message}`)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
_exists () {
|
|
42
|
+
return fs.existsSync(this.hookPath)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
_currentHook () {
|
|
46
|
+
return fs.readFileSync(this.hookPath, 'utf8')
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
_createHook () {
|
|
50
|
+
// If the pre-commit file doesn't exist, create a new one with the hookScript
|
|
51
|
+
fs.writeFileSync(this.hookPath, HOOK_SCRIPT)
|
|
52
|
+
fs.chmodSync(this.hookPath, '755') // Make the file executable
|
|
53
|
+
logger.successvp(`dotenvx precommit installed [${this.hookPath}]`)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
_appendHook () {
|
|
57
|
+
// Append 'dotenvx precommit' to the existing file
|
|
58
|
+
fs.appendFileSync(this.hookPath, '\n' + HOOK_SCRIPT)
|
|
59
|
+
logger.successvp(`dotenvx precommit appended [${this.hookPath}]`)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
module.exports = InstallPrecommitHook
|
package/src/lib/main.js
CHANGED
|
@@ -2,6 +2,9 @@ const logger = require('./../shared/logger')
|
|
|
2
2
|
const dotenv = require('dotenv')
|
|
3
3
|
const dotenvExpand = require('dotenv-expand')
|
|
4
4
|
|
|
5
|
+
// services
|
|
6
|
+
const Ls = require('./services/ls')
|
|
7
|
+
|
|
5
8
|
const config = function (options) {
|
|
6
9
|
return dotenv.config(options)
|
|
7
10
|
}
|
|
@@ -36,20 +39,27 @@ const parse = function (src) {
|
|
|
36
39
|
return result
|
|
37
40
|
}
|
|
38
41
|
|
|
39
|
-
const parseExpand = function (src) {
|
|
42
|
+
const parseExpand = function (src, overload) {
|
|
40
43
|
const parsed = dotenv.parse(src)
|
|
44
|
+
|
|
45
|
+
// consider moving this logic straight into dotenv-expand
|
|
46
|
+
let inputParsed = {}
|
|
47
|
+
if (overload) {
|
|
48
|
+
inputParsed = { ...process.env, ...parsed }
|
|
49
|
+
} else {
|
|
50
|
+
inputParsed = { ...parsed, ...process.env }
|
|
51
|
+
}
|
|
52
|
+
|
|
41
53
|
const expandPlease = {
|
|
42
|
-
processEnv: {},
|
|
43
|
-
parsed:
|
|
54
|
+
processEnv: {},
|
|
55
|
+
parsed: inputParsed
|
|
44
56
|
}
|
|
45
57
|
const expanded = dotenvExpand.expand(expandPlease).parsed
|
|
46
58
|
|
|
47
59
|
// but then for logging only log the original keys existing in parsed. this feels unnecessarily complex - like dotenv-expand should support the ability to inject additional `process.env` or objects as it sees fit to the object it wants to expand
|
|
48
60
|
const result = {}
|
|
49
61
|
for (const key in parsed) {
|
|
50
|
-
|
|
51
|
-
result[key] = expanded[key]
|
|
52
|
-
}
|
|
62
|
+
result[key] = expanded[key]
|
|
53
63
|
}
|
|
54
64
|
|
|
55
65
|
logger.debug(result)
|
|
@@ -95,11 +105,16 @@ const inject = function (processEnv = {}, parsed = {}, overload = false) {
|
|
|
95
105
|
}
|
|
96
106
|
}
|
|
97
107
|
|
|
108
|
+
const ls = function (directory, envFile) {
|
|
109
|
+
return new Ls(directory, envFile).run()
|
|
110
|
+
}
|
|
111
|
+
|
|
98
112
|
module.exports = {
|
|
99
113
|
config,
|
|
100
114
|
configDotenv,
|
|
101
115
|
decrypt,
|
|
102
116
|
parse,
|
|
103
117
|
parseExpand,
|
|
104
|
-
inject
|
|
118
|
+
inject,
|
|
119
|
+
ls
|
|
105
120
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const path = require('path')
|
|
2
|
+
const globSync = require('glob').globSync
|
|
3
|
+
|
|
4
|
+
class Ls {
|
|
5
|
+
constructor (directory = './', envFile = '.env*') {
|
|
6
|
+
this.ignore = ['node_modules/**', '.git/**']
|
|
7
|
+
|
|
8
|
+
this.cwd = path.resolve(directory)
|
|
9
|
+
this.envFile = envFile
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
run () {
|
|
13
|
+
return this._filepaths()
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
_filepaths () {
|
|
17
|
+
const options = {
|
|
18
|
+
ignore: this.ignore,
|
|
19
|
+
cwd: this.cwd // context dirctory for globSync
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const patterns = this._patterns()
|
|
23
|
+
return globSync(patterns, options)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
_patterns () {
|
|
27
|
+
if (!Array.isArray(this.envFile)) {
|
|
28
|
+
return `**/${this.envFile}`
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const out = []
|
|
32
|
+
|
|
33
|
+
for (let i = 0; i < this.envFile.length; i++) {
|
|
34
|
+
const part = this.envFile[i]
|
|
35
|
+
out.push(`**/${part}`)
|
|
36
|
+
}
|
|
37
|
+
return out
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
module.exports = Ls
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const logger = require('./../../shared/logger')
|
|
2
|
+
|
|
3
|
+
const InstallPrecommitHook = require('./../helpers/installPrecommitHook')
|
|
4
|
+
|
|
5
|
+
class Precommit {
|
|
6
|
+
constructor (options = {}) {
|
|
7
|
+
this.install = options.install
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
run () {
|
|
11
|
+
if (this.install) {
|
|
12
|
+
this._installPrecommitHook()
|
|
13
|
+
|
|
14
|
+
return true
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
logger.info('implement')
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/* istanbul ignore next */
|
|
21
|
+
_installPrecommitHook () {
|
|
22
|
+
new InstallPrecommitHook().run()
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
module.exports = Precommit
|
package/src/shared/logger.js
CHANGED