@dotenvx/dotenvx-ops 0.17.0 → 0.18.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,19 @@
|
|
|
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-ops/compare/v0.
|
|
5
|
+
[Unreleased](https://github.com/dotenvx/dotenvx-ops/compare/v0.18.0...main)
|
|
6
|
+
|
|
7
|
+
## [0.18.0](https://github.com/dotenvx/dotenvx-ops/compare/v0.17.1...v0.18.0) (2025-10-06)
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
* Display conflict diff ([#2](https://github.com/dotenvx/dotenvx-ops/pull/2))
|
|
12
|
+
|
|
13
|
+
## [0.17.1](https://github.com/dotenvx/dotenvx-ops/compare/v0.17.0...v0.17.1) (2025-10-01)
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
* API sync output is `files` not `envFiles`
|
|
6
18
|
|
|
7
19
|
## [0.17.0](https://github.com/dotenvx/dotenvx-ops/compare/v0.16.1...v0.17.0) (2025-10-01)
|
|
8
20
|
|
package/package.json
CHANGED
package/src/cli/actions/sync.js
CHANGED
|
@@ -8,17 +8,25 @@ const smartMask = require('./../../lib/helpers/smartMask')
|
|
|
8
8
|
|
|
9
9
|
const Sync = require('./../../lib/services/sync')
|
|
10
10
|
|
|
11
|
+
const GetSynchronization = require('./../../lib/api/getSynchronization')
|
|
12
|
+
|
|
11
13
|
const spinner = createSpinner('syncing')
|
|
12
14
|
|
|
15
|
+
// move soon
|
|
16
|
+
const Session = require('./../../db/session')
|
|
17
|
+
const sesh = new Session()
|
|
18
|
+
const token = sesh.token()
|
|
19
|
+
|
|
13
20
|
function sha256File (filepath) {
|
|
14
21
|
const buf = fs.readFileSync(filepath)
|
|
15
22
|
return crypto.createHash('sha256').update(buf).digest('hex')
|
|
16
23
|
}
|
|
17
24
|
|
|
18
25
|
async function sync () {
|
|
26
|
+
// debug opts
|
|
27
|
+
const options = this.opts()
|
|
28
|
+
|
|
19
29
|
try {
|
|
20
|
-
// debug opts
|
|
21
|
-
const options = this.opts()
|
|
22
30
|
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
23
31
|
|
|
24
32
|
spinner.start()
|
|
@@ -26,12 +34,12 @@ async function sync () {
|
|
|
26
34
|
const {
|
|
27
35
|
dotenvxProjectId,
|
|
28
36
|
projectUsernameName,
|
|
29
|
-
|
|
37
|
+
files
|
|
30
38
|
} = await new Sync(options.hostname).run()
|
|
31
|
-
logger.debug(`
|
|
39
|
+
logger.debug(`files: ${JSON.stringify(files)}`)
|
|
32
40
|
|
|
33
|
-
// write
|
|
34
|
-
for (const file of
|
|
41
|
+
// write output files
|
|
42
|
+
for (const file of files) {
|
|
35
43
|
const { filepath, src, sha } = file
|
|
36
44
|
|
|
37
45
|
let needsWrite = true
|
|
@@ -64,6 +72,20 @@ async function sync () {
|
|
|
64
72
|
if (error.stack) {
|
|
65
73
|
logger.debug(error.stack)
|
|
66
74
|
}
|
|
75
|
+
|
|
76
|
+
// display conflict diff
|
|
77
|
+
if (error.code === 'DOTENVX_SYNC_CONFLICT') {
|
|
78
|
+
const synchronizationId = error.meta.synchronization_id
|
|
79
|
+
const data = await new GetSynchronization(options.hostname, token, synchronizationId).run()
|
|
80
|
+
const conflictedFile = data.files.find(f => f.status === 'conflicted')
|
|
81
|
+
if (conflictedFile) {
|
|
82
|
+
console.log(conflictedFile.filepath)
|
|
83
|
+
console.log(conflictedFile.diff_ansi)
|
|
84
|
+
} else {
|
|
85
|
+
console.log('No conflicted files found.')
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
67
89
|
process.exit(1)
|
|
68
90
|
}
|
|
69
91
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const { http } = require('../../lib/helpers/http')
|
|
2
|
+
const buildApiError = require('../../lib/helpers/buildApiError')
|
|
3
|
+
|
|
4
|
+
class GetSynchronization {
|
|
5
|
+
constructor (hostname, token, synchronizationId) {
|
|
6
|
+
this.hostname = hostname || 'https://ops.dotenvx.com'
|
|
7
|
+
this.token = token
|
|
8
|
+
this.synchronizationId = synchronizationId
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async run () {
|
|
12
|
+
const token = this.token
|
|
13
|
+
const synchronizationId = this.synchronizationId
|
|
14
|
+
const url = `${this.hostname}/api/synchronization/${synchronizationId}`
|
|
15
|
+
|
|
16
|
+
const resp = await http(url, {
|
|
17
|
+
method: 'GET',
|
|
18
|
+
headers: {
|
|
19
|
+
Authorization: `Bearer ${token}`,
|
|
20
|
+
'Content-Type': 'application/json'
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const json = await resp.body.json()
|
|
25
|
+
|
|
26
|
+
if (resp.statusCode >= 400) {
|
|
27
|
+
throw buildApiError(resp.statusCode, json)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return json
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
module.exports = GetSynchronization
|
|
@@ -2,10 +2,12 @@ function buildApiError (statusCode, json) {
|
|
|
2
2
|
const code = json.error.code || statusCode.toString()
|
|
3
3
|
const message = `[${code}] ${json.error.message}`
|
|
4
4
|
const help = `[${code}] ${json.error.help || JSON.stringify(json)}`
|
|
5
|
+
const meta = json.error.meta
|
|
5
6
|
|
|
6
7
|
const error = new Error(message)
|
|
7
8
|
error.code = code
|
|
8
9
|
error.help = help
|
|
10
|
+
error.meta = meta
|
|
9
11
|
|
|
10
12
|
return error
|
|
11
13
|
}
|