@dotenvx/dotenvx 1.4.0 → 1.5.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/CHANGELOG.md CHANGED
@@ -2,7 +2,21 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
- ## [Unreleased](https://github.com/dotenvx/dotenvx/compare/v1.4.0...main)
5
+ ## [Unreleased](https://github.com/dotenvx/dotenvx/compare/v1.5.0...main)
6
+
7
+ ## 1.5.0
8
+
9
+ ### Added
10
+
11
+ * add help text for dashed values on `set`. example: `dotenvx set KEY -- "- + * ÷"` ([#293](https://github.com/dotenvx/dotenvx/pull/293))
12
+
13
+ ### Changed
14
+
15
+ * replace `@inquirer/confirm` and `ora` ([#285](https://github.com/dotenvx/dotenvx/pull/285))
16
+
17
+ ### Removed
18
+
19
+ * remove `dotenvx ext hub`, replace with [dotenvx-ext-hub](https://github.com/dotenvx/dotenvx-ext-hub) (install there to continue using hub) ([#291](https://github.com/dotenvx/dotenvx/pull/291))
6
20
 
7
21
  ## 1.4.0
8
22
 
package/README.md CHANGED
@@ -1071,6 +1071,18 @@ More examples
1071
1071
  set HELLO with encryption (.env.ci)
1072
1072
  ```
1073
1073
 
1074
+ </details>
1075
+ * <details><summary>`set KEY -- "- + * ÷"`</summary><br>
1076
+
1077
+ If your value starts with a dash (`-`), then place two dashes instructing the cli that there are no more flag arguments.
1078
+
1079
+ ```sh
1080
+ $ touch .env.ci
1081
+
1082
+ $ dotenvx set HELLO -f .env.ci -- "- + * ÷"
1083
+ set HELLO with encryption (.env.ci)
1084
+ ```
1085
+
1074
1086
  </details>
1075
1087
  * <details><summary>`set KEY value --plain`</summary><br>
1076
1088
 
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.4.0",
2
+ "version": "1.5.0",
3
3
  "name": "@dotenvx/dotenvx",
4
4
  "description": "a better dotenv–from the creator of `dotenv`",
5
5
  "author": "@motdotla",
@@ -31,7 +31,7 @@
31
31
  },
32
32
  "funding": "https://dotenvx.com",
33
33
  "dependencies": {
34
- "@inquirer/confirm": "^2.0.17",
34
+ "@clack/core": "^0.3.4",
35
35
  "arch": "^2.1.1",
36
36
  "chalk": "^4.1.2",
37
37
  "commander": "^11.1.0",
@@ -45,7 +45,6 @@
45
45
  "is-wsl": "^2.1.1",
46
46
  "object-treeify": "1.1.33",
47
47
  "open": "^8.4.2",
48
- "ora": "^5.4.1",
49
48
  "picomatch": "^3.0.1",
50
49
  "undici": "^5.28.3",
51
50
  "which": "^4.0.0",
@@ -1,7 +1,7 @@
1
1
  const fs = require('fs')
2
2
  const main = require('./../../../lib/main')
3
3
  const { logger } = require('./../../../shared/logger')
4
- const createSpinner = require('./../../../shared/createSpinner')
4
+ const { createSpinner } = require('./../../../shared/createSpinner')
5
5
 
6
6
  const sleep = require('./../../../lib/helpers/sleep')
7
7
 
@@ -1,7 +1,7 @@
1
1
  const fs = require('fs')
2
2
 
3
3
  const { logger } = require('./../../../../shared/logger')
4
- const createSpinner = require('./../../../../shared/createSpinner')
4
+ const { createSpinner } = require('./../../../../shared/createSpinner')
5
5
  const sleep = require('./../../../../lib/helpers/sleep')
6
6
 
7
7
  const Decrypt = require('./../../../../lib/services/decrypt')
@@ -3,7 +3,7 @@ const path = require('path')
3
3
 
4
4
  const main = require('./../../../../lib/main')
5
5
  const { logger } = require('./../../../../shared/logger')
6
- const createSpinner = require('./../../../../shared/createSpinner')
6
+ const { createSpinner } = require('./../../../../shared/createSpinner')
7
7
  const sleep = require('./../../../../lib/helpers/sleep')
8
8
  const pluralize = require('./../../../../lib/helpers/pluralize')
9
9
 
@@ -1,4 +1,7 @@
1
+ const path = require('path')
2
+ const { spawnSync } = require('child_process')
1
3
  const { Command } = require('commander')
4
+ const { logger } = require('../../shared/logger')
2
5
 
3
6
  const examples = require('./../examples')
4
7
 
@@ -6,6 +9,45 @@ const ext = new Command('ext')
6
9
 
7
10
  ext
8
11
  .description('🔌 extensions')
12
+ .allowUnknownOption()
13
+
14
+ ext.addHelpText('after', ' hub 🚫 DEPRECATED: to be replaced by [dotenvx pro]')
15
+
16
+ ext
17
+ .argument('[command]', 'dynamic ext command')
18
+ .argument('[args...]', 'dynamic ext command arguments')
19
+ .action((command, args, cmdObj) => {
20
+ if (!command) {
21
+ ext.outputHelp()
22
+ process.exit(1)
23
+ }
24
+
25
+ // construct the full command line manually including flags
26
+ const rawArgs = process.argv.slice(3) // adjust the index based on where actual args start
27
+ const commandIndex = rawArgs.indexOf(command)
28
+ const forwardedArgs = rawArgs.slice(commandIndex + 1)
29
+
30
+ logger.debug(`command: ${command}`)
31
+ logger.debug(`args: ${JSON.stringify(forwardedArgs)}`)
32
+
33
+ const binPath = path.join(process.cwd(), 'node_modules', '.bin')
34
+ const newPath = `${binPath}:${process.env.PATH}`
35
+ const env = { ...process.env, PATH: newPath }
36
+
37
+ const result = spawnSync(`dotenvx-ext-${command}`, forwardedArgs, { stdio: 'inherit', env })
38
+ if (result.error) {
39
+ if (command === 'hub') {
40
+ logger.warn(`[INSTALLATION_NEEDED] install dotenvx-ext-${command} to use [dotenvx ext ${command}] commands`)
41
+ logger.help('? see installation instructions [https://github.com/dotenvx/dotenvx-ext-hub]')
42
+ } else {
43
+ logger.info(`error: unknown command '${command}'`)
44
+ }
45
+ }
46
+
47
+ if (result.status !== 0) {
48
+ process.exit(result.status)
49
+ }
50
+ })
9
51
 
10
52
  // dotenvx ext ls
11
53
  ext.command('ls')
@@ -53,6 +95,5 @@ ext.command('settings')
53
95
  .action(require('./../actions/ext/settings'))
54
96
 
55
97
  ext.addCommand(require('./../commands/ext/vault'))
56
- ext.addCommand(require('./../commands/ext/hub'))
57
98
 
58
99
  module.exports = ext
@@ -72,14 +72,17 @@ program.command('get')
72
72
  })
73
73
 
74
74
  // dotenvx set
75
+ const setAction = require('./actions/set')
75
76
  program.command('set')
76
77
  .description('set a single environment variable')
78
+ .addHelpText('after', examples.set)
79
+ .allowUnknownOption()
77
80
  .argument('KEY', 'KEY')
78
81
  .argument('value', 'value')
79
82
  .option('-f, --env-file <paths...>', 'path(s) to your env file(s)', '.env')
80
83
  .option('-c, --encrypt', 'encrypt value (default: true)', true)
81
84
  .option('-p, --plain', 'store value as plain text', false)
82
- .action(require('./actions/set'))
85
+ .action(setAction)
83
86
 
84
87
  // dotenvx encrypt
85
88
  const encryptAction = require('./actions/encrypt')
@@ -100,10 +100,26 @@ Try it:
100
100
  `
101
101
  }
102
102
 
103
+ const set = function () {
104
+ return `
105
+ Examples:
106
+
107
+ \`\`\`
108
+ $ dotenvx set KEY value
109
+ $ dotenvx set KEY "value with spaces"
110
+ $ dotenvx set KEY -- "---value with a dash---"
111
+ $ dotenvx set KEY -- "-----BEGIN OPENSSH PRIVATE KEY-----
112
+ b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
113
+ -----END OPENSSH PRIVATE KEY-----"
114
+ \`\`\`
115
+ `
116
+ }
117
+
103
118
  module.exports = {
104
119
  run,
105
120
  vaultEncrypt,
106
121
  precommit,
107
122
  prebuild,
108
- gitignore
123
+ gitignore,
124
+ set
109
125
  }
@@ -0,0 +1,12 @@
1
+ const { ConfirmPrompt } = require('@clack/core')
2
+
3
+ module.exports = (opts) => {
4
+ return new ConfirmPrompt({
5
+ active: 'Y',
6
+ inactive: 'N',
7
+ initialValue: true,
8
+ render () {
9
+ return `${opts.message} (${this.value ? 'Y/n' : 'y/N'})`
10
+ }
11
+ }).prompt()
12
+ }
@@ -1,8 +1,88 @@
1
- const ora = require('ora')
2
1
  const chalk = require('chalk')
3
2
 
4
- const createSpinner = function (initialMessage = '') {
5
- const spinner = ora(initialMessage)
3
+ const FRAMES = ['⠋', '⠙', '⠹', '', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
4
+ const HIDE_CURSOR = '\u001B[?25l'
5
+ const SHOW_CURSOR = '\u001B[?25h'
6
+ const CLEAR_LINE = '\r\x1b[K'
7
+ const SYMBOL_INFO = 'ℹ'
8
+ const SYMBOL_WARN = '⚠'
9
+ const SYMBOL_ERROR = '✖'
10
+ const SYMBOL_SUCCESS = '✔'
11
+
12
+ class Spinner {
13
+ text
14
+ interval
15
+ frameIndex = 0
16
+ symbol = chalk.blue(FRAMES[0])
17
+
18
+ constructor (text) {
19
+ this.text = text
20
+ }
21
+
22
+ start (text) {
23
+ if (text) {
24
+ this.text = text
25
+ }
26
+ this.render()
27
+ this.interval = setInterval(() => this.tick(), 50)
28
+ }
29
+
30
+ tick () {
31
+ this.symbol = chalk.blue(FRAMES[this.frameIndex++])
32
+ if (this.frameIndex === FRAMES.length - 1) this.frameIndex = 0
33
+ this.render()
34
+ }
35
+
36
+ render () {
37
+ process.stdout.write(CLEAR_LINE + HIDE_CURSOR + (this.symbol ? this.symbol + ' ' : '') + this.text)
38
+ }
39
+
40
+ succeed (text) {
41
+ if (text) {
42
+ this.text = text
43
+ }
44
+ this.symbol = chalk.green(SYMBOL_SUCCESS)
45
+ this.end()
46
+ }
47
+
48
+ info (text) {
49
+ if (text) {
50
+ this.text = text
51
+ }
52
+ this.symbol = chalk.blue(SYMBOL_INFO)
53
+ this.end()
54
+ }
55
+
56
+ warn (text) {
57
+ if (text) {
58
+ this.text = text
59
+ }
60
+ this.symbol = chalk.yellow(SYMBOL_WARN)
61
+ this.end()
62
+ }
63
+
64
+ fail (text) {
65
+ if (text) {
66
+ this.text = text
67
+ }
68
+ this.symbol = chalk.red(SYMBOL_ERROR)
69
+ this.end()
70
+ }
71
+
72
+ stop () {
73
+ this.symbol = ''
74
+ this.end()
75
+ }
76
+
77
+ end () {
78
+ this.render()
79
+ clearInterval(this.interval)
80
+ process.stdout.write(SHOW_CURSOR + '\n')
81
+ }
82
+ }
83
+
84
+ const createSpinner = (initialMessage = '') => {
85
+ const spinner = new Spinner(initialMessage)
6
86
 
7
87
  return {
8
88
  start: (message) => spinner.start(message),
@@ -14,4 +94,4 @@ const createSpinner = function (initialMessage = '') {
14
94
  }
15
95
  }
16
96
 
17
- module.exports = createSpinner
97
+ module.exports = { createSpinner, Spinner }
@@ -1,126 +0,0 @@
1
- const open = require('open')
2
- const { request } = require('undici')
3
- const clipboardy = require('./../../../../lib/helpers/clipboardy')
4
- const confirm = require('@inquirer/confirm').default
5
-
6
- const createSpinner = require('./../../../../shared/createSpinner')
7
- const store = require('./../../../../shared/store')
8
- const { logger } = require('./../../../../shared/logger')
9
-
10
- const OAUTH_CLIENT_ID = 'oac_dotenvxcli'
11
-
12
- const spinner = createSpinner('waiting on user authorization')
13
-
14
- const formatCode = function (str) {
15
- const parts = []
16
-
17
- for (let i = 0; i < str.length; i += 4) {
18
- parts.push(str.substring(i, i + 4))
19
- }
20
-
21
- return parts.join('-')
22
- }
23
-
24
- async function pollTokenUrl (tokenUrl, deviceCode, interval) {
25
- logger.http(`POST ${tokenUrl} with deviceCode ${deviceCode} at interval ${interval}`)
26
-
27
- try {
28
- const response = await request(tokenUrl, {
29
- method: 'POST',
30
- headers: {
31
- 'Content-Type': 'application/json'
32
- },
33
- body: JSON.stringify({
34
- client_id: OAUTH_CLIENT_ID,
35
- device_code: deviceCode,
36
- grant_type: 'urn:ietf:params:oauth:grant-type:device_code'
37
- })
38
- })
39
-
40
- const responseData = await response.body.json()
41
-
42
- logger.http(responseData)
43
-
44
- if (response.statusCode >= 400) {
45
- // continue polling if authorization_pending
46
- if (responseData.error === 'authorization_pending') {
47
- setTimeout(() => pollTokenUrl(tokenUrl, deviceCode, interval), interval * 1000)
48
- } else {
49
- spinner.start()
50
- spinner.fail(responseData.error_description)
51
- process.exit(1)
52
- }
53
- }
54
-
55
- if (responseData.access_token) {
56
- spinner.start()
57
- store.setToken(responseData.full_username, responseData.access_token)
58
- store.setHostname(responseData.hostname)
59
- spinner.succeed(`logged in as ${responseData.username}`)
60
- process.exit(0)
61
- } else {
62
- // continue polling if no access_token. shouldn't ever get here it server is implemented correctly
63
- setTimeout(() => pollTokenUrl(tokenUrl, deviceCode, interval), interval * 1000)
64
- }
65
- } catch (error) {
66
- spinner.start()
67
- spinner.fail(error.toString())
68
- process.exit(1)
69
- }
70
- }
71
-
72
- async function login () {
73
- const options = this.opts()
74
- logger.debug(`options: ${JSON.stringify(options)}`)
75
-
76
- const hostname = options.hostname
77
- const deviceCodeUrl = `${hostname}/oauth/device/code`
78
- const tokenUrl = `${hostname}/oauth/token`
79
-
80
- try {
81
- const response = await request(deviceCodeUrl, {
82
- method: 'POST',
83
- headers: {
84
- 'Content-Type': 'application/json'
85
- },
86
- body: JSON.stringify({ client_id: OAUTH_CLIENT_ID })
87
- })
88
-
89
- const responseData = await response.body.json()
90
-
91
- if (response.statusCode >= 400) {
92
- logger.http(responseData)
93
-
94
- spinner.start()
95
- spinner.fail(responseData.error_description)
96
- process.exit(1)
97
- }
98
-
99
- const deviceCode = responseData.device_code
100
- const userCode = responseData.user_code
101
- const verificationUri = responseData.verification_uri
102
- const interval = responseData.interval
103
-
104
- try { clipboardy.writeSync(userCode) } catch (_e) {}
105
-
106
- // qrcode.generate(verificationUri, { small: true }) // too verbose
107
-
108
- // begin polling
109
- pollTokenUrl(tokenUrl, deviceCode, interval)
110
-
111
- // optionally allow user to open browser
112
- const answer = await confirm({ message: `press Enter to open [${verificationUri}] and enter code [${formatCode(userCode)}]...` })
113
-
114
- if (answer) {
115
- await open(verificationUri)
116
-
117
- spinner.start()
118
- }
119
- } catch (error) {
120
- spinner.start()
121
- spinner.fail(error.toString())
122
- process.exit(1)
123
- }
124
- }
125
-
126
- module.exports = login
@@ -1,43 +0,0 @@
1
- const openBrowser = require('open')
2
- const confirm = require('@inquirer/confirm').default
3
-
4
- const createSpinner = require('./../../../../shared/createSpinner')
5
- const store = require('./../../../../shared/store')
6
- const { logger } = require('./../../../../shared/logger')
7
- const sleep = require('./../../../../lib/helpers/sleep')
8
-
9
- const username = store.getUsername()
10
- const usernamePart = username ? ` [${username}]` : ''
11
- const spinner = createSpinner(`logging off machine${usernamePart}`)
12
-
13
- async function logout () {
14
- spinner.start()
15
- await sleep(500) // better dx
16
-
17
- // debug opts
18
- const options = this.opts()
19
- logger.debug(`options: ${JSON.stringify(options)}`)
20
-
21
- logger.debug('deleting settings.DOTENVX_TOKEN')
22
- store.deleteToken()
23
-
24
- logger.debug('deleting settings.DOTENVX_HOSTNAME')
25
- store.deleteHostname()
26
-
27
- spinner.done(`logged off machine${usernamePart}`)
28
-
29
- const hostname = options.hostname
30
- const logoutUrl = `${hostname}/logout`
31
-
32
- // optionally allow user to open browser
33
- const answer = await confirm({ message: `press Enter to also log off browser [${logoutUrl}]...` })
34
-
35
- if (answer) {
36
- spinner.start()
37
- await sleep(500) // better dx
38
- await openBrowser(logoutUrl)
39
- spinner.done(`logged off browser${usernamePart}`)
40
- }
41
- }
42
-
43
- module.exports = logout
@@ -1,63 +0,0 @@
1
- const openBrowser = require('open')
2
- const confirm = require('@inquirer/confirm').default
3
-
4
- const createSpinner = require('./../../../../shared/createSpinner')
5
- const { logger } = require('./../../../../shared/logger')
6
-
7
- const isGitRepo = require('./../../../../lib/helpers/isGitRepo')
8
- const isGithub = require('./../../../../lib/helpers/isGithub')
9
- const gitUrl = require('./../../../../lib/helpers/gitUrl')
10
- const gitRoot = require('./../../../../lib/helpers/gitRoot')
11
- const extractUsernameName = require('./../../../../lib/helpers/extractUsernameName')
12
- const sleep = require('./../../../../lib/helpers/sleep')
13
-
14
- const spinner = createSpinner('opening')
15
-
16
- async function open () {
17
- // debug opts
18
- const options = this.opts()
19
- logger.debug(`options: ${JSON.stringify(options)}`)
20
-
21
- // must be a git repo
22
- if (!isGitRepo()) {
23
- spinner.fail('oops, must be a git repository')
24
- logger.help('? create one with [git init .]')
25
- process.exit(1)
26
- }
27
- // must be a git root
28
- const gitroot = gitRoot()
29
- if (!gitroot) {
30
- spinner.fail('oops, could not determine git repository\'s root')
31
- logger.help('? create one with [git init .]')
32
- process.exit(1)
33
- }
34
- // must have a remote origin url
35
- const giturl = gitUrl()
36
- if (!giturl) {
37
- spinner.fail('oops, must have a remote origin (git remote -v)')
38
- logger.help('? create it at [github.com/new] and then run [git remote add origin git@github.com:username/repository.git]')
39
- process.exit(1)
40
- }
41
- // must be a github remote
42
- if (!isGithub(giturl)) {
43
- spinner.fail('oops, must be a github.com remote origin (git remote -v)')
44
- logger.help('? create it at [github.com/new] and then run [git remote add origin git@github.com:username/repository.git]')
45
- logger.help2('ℹ need support for other origins? [please tell us](https://github.com/dotenvx/dotenvx/issues)')
46
- process.exit(1)
47
- }
48
-
49
- const usernameName = extractUsernameName(giturl)
50
- const openUrl = `${options.hostname}/gh/${usernameName}`
51
-
52
- // optionally allow user to open browser
53
- const answer = await confirm({ message: `press Enter to open [${openUrl}]...` })
54
-
55
- if (answer) {
56
- spinner.start()
57
- await sleep(500) // better dx
58
- await openBrowser(openUrl)
59
- spinner.succeed(`opened [${usernameName}]`)
60
- }
61
- }
62
-
63
- module.exports = open
@@ -1,105 +0,0 @@
1
- const fs = require('fs')
2
- const path = require('path')
3
- const { request } = require('undici')
4
-
5
- const store = require('./../../../../shared/store')
6
- const { logger } = require('./../../../../shared/logger')
7
- const createSpinner = require('./../../../../shared/createSpinner')
8
-
9
- const isGitRepo = require('./../../../../lib/helpers/isGitRepo')
10
- const isGithub = require('./../../../../lib/helpers/isGithub')
11
- const gitUrl = require('./../../../../lib/helpers/gitUrl')
12
- const gitRoot = require('./../../../../lib/helpers/gitRoot')
13
- const extractUsernameName = require('./../../../../lib/helpers/extractUsernameName')
14
- const sleep = require('./../../../../lib/helpers/sleep')
15
-
16
- const spinner = createSpinner('pulling')
17
-
18
- // constants
19
- const ENCODING = 'utf8'
20
-
21
- // Create a simple-git instance for the current directory
22
- async function pull (directory) {
23
- spinner.start()
24
- await sleep(500) // better dx
25
-
26
- // debug args
27
- logger.debug(`directory: ${directory}`)
28
-
29
- // debug opts
30
- const options = this.opts()
31
- logger.debug(`options: ${JSON.stringify(options)}`)
32
-
33
- // must be a git repo
34
- if (!isGitRepo()) {
35
- spinner.fail('oops, must be a git repository')
36
- logger.help('? create one with [git init .]')
37
- process.exit(1)
38
- }
39
- // must be a git root
40
- const gitroot = gitRoot()
41
- if (!gitroot) {
42
- spinner.fail('oops, could not determine git repository\'s root')
43
- logger.help('? create one with [git init .]')
44
- process.exit(1)
45
- }
46
- // must have a remote origin url
47
- const giturl = gitUrl()
48
- if (!giturl) {
49
- spinner.fail('oops, must have a remote origin (git remote -v)')
50
- logger.help('? create it at [github.com/new] and then run [git remote add origin git@github.com:username/repository.git]')
51
- process.exit(1)
52
- }
53
- // must be a github remote
54
- if (!isGithub(giturl)) {
55
- spinner.fail('oops, must be a github.com remote origin (git remote -v)')
56
- logger.help('? create it at [github.com/new] and then run [git remote add origin git@github.com:username/repository.git]')
57
- logger.help2('ℹ need support for other origins? [please tell us](https://github.com/dotenvx/dotenvx/issues)')
58
- process.exit(1)
59
- }
60
-
61
- const envKeysFilepath = path.join(directory, '.env.keys')
62
- const hostname = options.hostname
63
- const pullUrl = `${hostname}/v1/pull`
64
- const oauthToken = store.getToken()
65
- const usernameName = extractUsernameName(giturl)
66
- const relativeEnvKeysFilepath = path.relative(gitroot, path.join(process.cwd(), directory, '.env.keys')).replace(/\\/g, '/') // smartly determine path/to/.env.keys file from repository root - where user is cd-ed inside a folder or at repo root
67
-
68
- try {
69
- const response = await request(pullUrl, {
70
- method: 'POST',
71
- headers: {
72
- Authorization: `Bearer ${oauthToken}`,
73
- 'Content-Type': 'application/json'
74
- },
75
- body: JSON.stringify({
76
- username_name: usernameName,
77
- filepath: relativeEnvKeysFilepath
78
- })
79
- })
80
-
81
- const responseData = await response.body.json()
82
-
83
- if (response.statusCode >= 400) {
84
- logger.http(responseData)
85
- spinner.fail(responseData.error.message)
86
- if (response.statusCode === 404) {
87
- logger.help(`? try visiting [${hostname}/gh/${usernameName}] in your browser`)
88
- }
89
- process.exit(1)
90
- }
91
-
92
- if (fs.existsSync(envKeysFilepath) && fs.readFileSync(envKeysFilepath, ENCODING) === responseData.DOTENV_KEYS) {
93
- spinner.done(`no changes (${envKeysFilepath})`)
94
- } else {
95
- fs.writeFileSync(envKeysFilepath, responseData.DOTENV_KEYS)
96
- spinner.succeed(`pulled [${usernameName}]`)
97
- logger.help2(`ℹ run [cat ${envKeysFilepath}] to view locally`)
98
- }
99
- } catch (error) {
100
- spinner.fail(error.toString())
101
- process.exit(1)
102
- }
103
- }
104
-
105
- module.exports = pull
@@ -1,112 +0,0 @@
1
- const fs = require('fs')
2
- const path = require('path')
3
- const { request } = require('undici')
4
-
5
- const store = require('./../../../../shared/store')
6
- const { logger } = require('./../../../../shared/logger')
7
- const createSpinner = require('./../../../../shared/createSpinner')
8
-
9
- const isGitRepo = require('./../../../../lib/helpers/isGitRepo')
10
- const isGithub = require('./../../../../lib/helpers/isGithub')
11
- const gitUrl = require('./../../../../lib/helpers/gitUrl')
12
- const gitRoot = require('./../../../../lib/helpers/gitRoot')
13
- const extractUsernameName = require('./../../../../lib/helpers/extractUsernameName')
14
- const sleep = require('./../../../../lib/helpers/sleep')
15
- const forgivingDirectory = require('./../../../../lib/helpers/forgivingDirectory')
16
-
17
- const spinner = createSpinner('pushing')
18
-
19
- // constants
20
- const ENCODING = 'utf8'
21
-
22
- // Create a simple-git instance for the current directory
23
- async function push (directory) {
24
- spinner.start()
25
- await sleep(500) // better dx
26
-
27
- directory = forgivingDirectory(directory)
28
-
29
- // debug args
30
- logger.debug(`directory: ${directory}`)
31
-
32
- // debug opts
33
- const options = this.opts()
34
- logger.debug(`options: ${JSON.stringify(options)}`)
35
-
36
- // must be a git repo
37
- if (!isGitRepo()) {
38
- spinner.fail('oops, must be a git repository')
39
- logger.help('? create one with [git init .]')
40
- process.exit(1)
41
- }
42
- // must be a git root
43
- const gitroot = gitRoot()
44
- if (!gitroot) {
45
- spinner.fail('oops, could not determine git repository\'s root')
46
- logger.help('? create one with [git init .]')
47
- process.exit(1)
48
- }
49
- // must have a remote origin url
50
- const giturl = gitUrl()
51
- if (!giturl) {
52
- spinner.fail('oops, must have a remote origin (git remote -v)')
53
- logger.help('? create it at [github.com/new] and then run [git remote add origin git@github.com:username/repository.git]')
54
- process.exit(1)
55
- }
56
- // must be a github remote
57
- if (!isGithub(giturl)) {
58
- spinner.fail('oops, must be a github.com remote origin (git remote -v)')
59
- logger.help('? create it at [github.com/new] and then run [git remote add origin git@github.com:username/repository.git]')
60
- logger.help2('ℹ need support for other origins? [please tell us](https://github.com/dotenvx/dotenvx/issues)')
61
- process.exit(1)
62
- }
63
-
64
- const envKeysFilepath = path.join(directory, '.env.keys')
65
- if (!fs.existsSync(envKeysFilepath)) {
66
- spinner.fail('oops, missing .env.keys file')
67
- logger.help(`? generate one with [dotenvx encrypt${directory ? ` ${directory}` : ''}]`)
68
- logger.help2('ℹ a .env.keys file holds decryption keys for a .env.vault file')
69
- process.exit(1)
70
- }
71
-
72
- const hostname = options.hostname
73
- const pushUrl = `${hostname}/v1/push`
74
- const oauthToken = store.getToken()
75
- const dotenvKeysContent = fs.readFileSync(envKeysFilepath, ENCODING)
76
- const usernameName = extractUsernameName(giturl)
77
- const relativeEnvKeysFilepath = path.relative(gitroot, path.join(process.cwd(), directory, '.env.keys')).replace(/\\/g, '/') // smartly determine path/to/.env.keys file from repository root - where user is cd-ed inside a folder or at repo root
78
-
79
- try {
80
- const response = await request(pushUrl, {
81
- method: 'POST',
82
- headers: {
83
- Authorization: `Bearer ${oauthToken}`,
84
- 'Content-Type': 'application/json'
85
- },
86
- body: JSON.stringify({
87
- username_name: usernameName,
88
- DOTENV_KEYS: dotenvKeysContent,
89
- filepath: relativeEnvKeysFilepath
90
- })
91
- })
92
-
93
- const responseData = await response.body.json()
94
-
95
- if (response.statusCode >= 400) {
96
- logger.http(responseData)
97
- spinner.fail(responseData.error.message)
98
- if (response.statusCode === 404) {
99
- logger.help(`? try visiting [${hostname}/gh/${usernameName}] in your browser`)
100
- }
101
- process.exit(1)
102
- }
103
- } catch (error) {
104
- spinner.fail(error.toString())
105
- process.exit(1)
106
- }
107
-
108
- spinner.succeed(`pushed [${usernameName}]`)
109
- logger.help2('ℹ run [dotenvx ext hub open] to view on hub')
110
- }
111
-
112
- module.exports = push
@@ -1,8 +0,0 @@
1
- const store = require('./../../../../shared/store')
2
- const { logger } = require('./../../../../shared/logger')
3
-
4
- async function status () {
5
- logger.info(`logged in to ${store.getHostname()} as ${store.getUsername()}`)
6
- }
7
-
8
- module.exports = status
@@ -1,9 +0,0 @@
1
- const store = require('./../../../../shared/store')
2
- const { logger } = require('./../../../../shared/logger')
3
-
4
- async function token () {
5
- logger.debug(store.configPath())
6
- logger.blank(store.getToken())
7
- }
8
-
9
- module.exports = token
@@ -1,89 +0,0 @@
1
- const { Command } = require('commander')
2
-
3
- const store = require('./../../../shared/store')
4
- const { logger } = require('./../../../shared/logger')
5
-
6
- const hub = new Command('hub')
7
-
8
- hub
9
- .description('🚫 DEPRECATED: to be replaced by [dotenvx pro]')
10
-
11
- const loginAction = require('./../../actions/ext/hub/login')
12
- hub
13
- .command('login')
14
- .description('authenticate to dotenvx hub')
15
- .option('-h, --hostname <url>', 'set hostname', store.getHostname())
16
- .action(function (...args) {
17
- logger.warn('DEPRECATION NOTICE: to be replaced by [dotenvx pro]')
18
-
19
- loginAction.apply(this, args)
20
- })
21
-
22
- const pushAction = require('./../../actions/ext/hub/push')
23
- hub
24
- .command('push')
25
- .description('push .env.keys to dotenvx hub')
26
- .argument('[directory]', 'directory to push', '.')
27
- .option('-h, --hostname <url>', 'set hostname', store.getHostname())
28
- .action(function (...args) {
29
- logger.warn('DEPRECATION NOTICE: to be replaced by [dotenvx pro]')
30
-
31
- pushAction.apply(this, args)
32
- })
33
-
34
- const pullAction = require('./../../actions/ext/hub/pull')
35
- hub
36
- .command('pull')
37
- .description('pull .env.keys from dotenvx hub')
38
- .argument('[directory]', 'directory to pull', '.')
39
- .option('-h, --hostname <url>', 'set hostname', store.getHostname())
40
- .action(function (...args) {
41
- logger.warn('DEPRECATION NOTICE: to be replaced by [dotenvx pro]')
42
-
43
- pullAction.apply(this, args)
44
- })
45
-
46
- const openAction = require('./../../actions/ext/hub/open')
47
- hub
48
- .command('open')
49
- .description('view repository on dotenvx hub')
50
- .option('-h, --hostname <url>', 'set hostname', store.getHostname())
51
- .action(function (...args) {
52
- logger.warn('DEPRECATION NOTICE: to be replaced by [dotenvx pro]')
53
-
54
- openAction.apply(this, args)
55
- })
56
-
57
- const tokenAction = require('./../../actions/ext/hub/token')
58
- hub
59
- .command('token')
60
- .description('print the auth token dotenvx hub is configured to use')
61
- .option('-h, --hostname <url>', 'set hostname', 'https://hub.dotenvx.com')
62
- .action(function (...args) {
63
- logger.warn('DEPRECATION NOTICE: to be replaced by [dotenvx pro]')
64
-
65
- tokenAction.apply(this, args)
66
- })
67
-
68
- const statusAction = require('./../../actions/ext/hub/status')
69
- hub
70
- .command('status')
71
- .description('display logged in user')
72
- .action(function (...args) {
73
- logger.warn('DEPRECATION NOTICE: to be replaced by [dotenvx pro]')
74
-
75
- statusAction.apply(this, args)
76
- })
77
-
78
- const logoutAction = require('./../../actions/ext/hub/logout')
79
- hub
80
- .command('logout')
81
- .description('log out this machine from dotenvx hub')
82
- .option('-h, --hostname <url>', 'set hostname', store.getHostname())
83
- .action(function (...args) {
84
- logger.warn('DEPRECATION NOTICE: to be replaced by [dotenvx pro]')
85
-
86
- logoutAction.apply(this, args)
87
- })
88
-
89
- module.exports = hub