adapt-migrations 1.2.0 → 1.4.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/.eslintignore +1 -1
- package/.eslintrc.json +14 -14
- package/.github/CONTRIBUTING.md +8 -0
- package/.github/ISSUE_TEMPLATE/config.yml +1 -0
- package/.github/ISSUE_TEMPLATE/issue_template.md +23 -0
- package/.github/ISSUE_TEMPLATE.md +17 -0
- package/.github/pull_request_template.md +25 -0
- package/.github/workflows/addtomainproject.yml +19 -0
- package/.github/workflows/releases.yml +25 -0
- package/README.md +106 -106
- package/api/commands.js +33 -33
- package/api/data.js +26 -26
- package/api/describe.js +12 -12
- package/api/errors.js +28 -28
- package/api/helpers.js +17 -17
- package/api/plugins.js +47 -47
- package/api/tests.js +56 -57
- package/api/where.js +46 -46
- package/examples/migrations.js +159 -159
- package/examples/script.js +78 -78
- package/index.js +70 -70
- package/lib/CacheManager.js +95 -95
- package/lib/Journal.js +303 -303
- package/lib/Logger.js +91 -91
- package/lib/Task.js +402 -381
- package/lib/TaskContext.js +27 -27
- package/lib/TaskTest.js +21 -19
- package/lib/lifecycle.js +50 -50
- package/package.json +55 -18
package/lib/Task.js
CHANGED
|
@@ -1,381 +1,402 @@
|
|
|
1
|
-
import globs from 'globs'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import fs from 'fs-extra'
|
|
4
|
-
import chalk from 'chalk'
|
|
5
|
-
import TaskContext from './TaskContext.js'
|
|
6
|
-
import Journal from '../lib/Journal.js'
|
|
7
|
-
import { exec } from 'child_process'
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
this.
|
|
84
|
-
this.
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
journal
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
this.context
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
journal
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
for (const
|
|
348
|
-
const {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
1
|
+
import globs from 'globs'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import fs from 'fs-extra'
|
|
4
|
+
import chalk from 'chalk'
|
|
5
|
+
import TaskContext from './TaskContext.js'
|
|
6
|
+
import Journal from '../lib/Journal.js'
|
|
7
|
+
import { exec } from 'child_process'
|
|
8
|
+
import pkgUp from 'pkg-up'
|
|
9
|
+
import semver from 'semver'
|
|
10
|
+
|
|
11
|
+
function makeTable(items, columnNames) {
|
|
12
|
+
// calculate the max column widths for the items
|
|
13
|
+
const colWidths = items.reduce((colWidths, item) => {
|
|
14
|
+
Object.entries(item).forEach(([colName, value]) => {
|
|
15
|
+
colWidths[colName] = Math.max(colWidths[colName] ?? 0, value !== undefined ? String(value).length : 0)
|
|
16
|
+
if (!colWidths[colName]) return
|
|
17
|
+
// Include column header if data has value
|
|
18
|
+
colWidths[colName] = Math.max(colWidths[colName], colName.length)
|
|
19
|
+
})
|
|
20
|
+
return colWidths
|
|
21
|
+
}, {})
|
|
22
|
+
// produce a well spaced column names header
|
|
23
|
+
const header = columnNames.map(colName => {
|
|
24
|
+
if (!colWidths[colName]) return ''
|
|
25
|
+
return chalk.cyan(String(colName).padEnd(colWidths[colName] + 1, ' '))
|
|
26
|
+
}).join('')
|
|
27
|
+
// produce a well spaced data table
|
|
28
|
+
const body = items.map(item => {
|
|
29
|
+
return columnNames.map(colName => {
|
|
30
|
+
if (!colWidths[colName]) return ''
|
|
31
|
+
return String(item[colName]).padEnd(colWidths[colName] + 1, ' ')
|
|
32
|
+
}).join('')
|
|
33
|
+
}).join('\n')
|
|
34
|
+
return `${header}\n${body}`
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function prettyPrintJournal(journal, logger) {
|
|
38
|
+
const lines = []
|
|
39
|
+
// collect all of the appropriate information about the change
|
|
40
|
+
for (const entry of journal.entries) {
|
|
41
|
+
const type = (entry.keys[0] === 'fromPlugins')
|
|
42
|
+
? 'plugin'
|
|
43
|
+
: entry._type
|
|
44
|
+
const name = entry._name
|
|
45
|
+
const id = entry._id
|
|
46
|
+
const action = entry.method
|
|
47
|
+
const property = entry.keys.slice(2).join('.')
|
|
48
|
+
const value = JSON.stringify(entry.value)
|
|
49
|
+
const prev = JSON.stringify(entry.previous)
|
|
50
|
+
lines.push({ type, name, id, '#': lines.length, action, property, value, prev })
|
|
51
|
+
}
|
|
52
|
+
let lineIndex = 0
|
|
53
|
+
const output = []
|
|
54
|
+
while (lineIndex < lines.length) {
|
|
55
|
+
// collect lines with identical subject name and id values
|
|
56
|
+
const fromLineIndex = lineIndex
|
|
57
|
+
let toLineIndex = lineIndex
|
|
58
|
+
const line = lines[lineIndex]
|
|
59
|
+
for (let i = lineIndex; i < lines.length; i++) {
|
|
60
|
+
const nextLine = lines[i]
|
|
61
|
+
if (nextLine.name !== line.name || nextLine.id !== line.id || nextLine.type !== line.type) break
|
|
62
|
+
toLineIndex = i
|
|
63
|
+
}
|
|
64
|
+
// print a grouped summary of the above lines with a single common subject line
|
|
65
|
+
const printLines = lines.slice(fromLineIndex, toLineIndex + 1)
|
|
66
|
+
const subjectTable = makeTable([printLines[0]], ['type', 'name', 'id'])
|
|
67
|
+
const propertyChangeTable = makeTable(printLines, ['#', 'action','property','value'])
|
|
68
|
+
output.push(`${subjectTable}\n${propertyChangeTable}\n`)
|
|
69
|
+
lineIndex = toLineIndex + 1
|
|
70
|
+
}
|
|
71
|
+
if (!output.length) return logger.info(`No changes where made`)
|
|
72
|
+
logger.info(`Summary of changes:\n\n${output.join('\n')}`)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export default class Task {
|
|
76
|
+
constructor ({
|
|
77
|
+
description = '',
|
|
78
|
+
tests = [],
|
|
79
|
+
steps = [],
|
|
80
|
+
filePath = Task.currentFile,
|
|
81
|
+
load = () => {}
|
|
82
|
+
} = {}) {
|
|
83
|
+
this.description = description
|
|
84
|
+
this.tests = tests
|
|
85
|
+
this.steps = steps
|
|
86
|
+
this.load = load
|
|
87
|
+
this.filePath = filePath
|
|
88
|
+
if (!load) return // Assumed cloned
|
|
89
|
+
Task.described.push(this)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
clone () {
|
|
93
|
+
return new Task({
|
|
94
|
+
description: this.description,
|
|
95
|
+
tests: this.tests,
|
|
96
|
+
steps: this.steps,
|
|
97
|
+
filePath: this.filePath,
|
|
98
|
+
load: null
|
|
99
|
+
})
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
getImmediateNextStepsOfType (stepIndex = 0, type) {
|
|
103
|
+
const nextFilters = []
|
|
104
|
+
const nextSteps = this.steps.slice(stepIndex)
|
|
105
|
+
for (const step of nextSteps) {
|
|
106
|
+
if (step.type === type) {
|
|
107
|
+
nextFilters.push(step)
|
|
108
|
+
continue
|
|
109
|
+
}
|
|
110
|
+
break
|
|
111
|
+
}
|
|
112
|
+
return nextFilters
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
getImmediateNextIndexOfType (stepIndex = 0, type) {
|
|
116
|
+
const nextSteps = this.steps.slice(stepIndex)
|
|
117
|
+
for (const nextStepIndex in nextSteps) {
|
|
118
|
+
const step = nextSteps[nextStepIndex]
|
|
119
|
+
if (step.type === type) {
|
|
120
|
+
return parseInt(nextStepIndex) + stepIndex
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return -1
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async run ({ journal, logger }) {
|
|
127
|
+
logger.debug(`Task -- Running ${this.description}`)
|
|
128
|
+
let shouldContinue = false
|
|
129
|
+
const lastJournalEntryIndex = journal.lastEntryIndex
|
|
130
|
+
this.context = new TaskContext({
|
|
131
|
+
fromPlugins: journal.subject.fromPlugins,
|
|
132
|
+
originalFromPlugins: journal.subject.originalFromPlugins,
|
|
133
|
+
toPlugins: journal.subject.toPlugins,
|
|
134
|
+
content: journal.subject.content,
|
|
135
|
+
journal
|
|
136
|
+
})
|
|
137
|
+
Task.isRunning = true
|
|
138
|
+
Task.stackUp(this)
|
|
139
|
+
const wheres = this.getImmediateNextStepsOfType(0, 'where')
|
|
140
|
+
let stepIndex = 0
|
|
141
|
+
const stepCount = this.steps.length
|
|
142
|
+
while (stepIndex < stepCount) {
|
|
143
|
+
if (stepIndex >= wheres.length) {
|
|
144
|
+
this.context.hasRun = true
|
|
145
|
+
}
|
|
146
|
+
const step = this.steps[stepIndex]
|
|
147
|
+
try {
|
|
148
|
+
shouldContinue = await step(this.context)
|
|
149
|
+
} catch (err) {
|
|
150
|
+
logger.error(`Task -- shouldContinue errored ${err}`)
|
|
151
|
+
this.context.errors.push(err)
|
|
152
|
+
this.context.hasErrored = true
|
|
153
|
+
// Undo changes from this errored migrations
|
|
154
|
+
journal.undoToIndex(lastJournalEntryIndex)
|
|
155
|
+
stepIndex = this.getImmediateNextIndexOfType(stepIndex, 'error')
|
|
156
|
+
shouldContinue = (stepIndex !== -1)
|
|
157
|
+
if (shouldContinue) continue
|
|
158
|
+
}
|
|
159
|
+
if (shouldContinue) {
|
|
160
|
+
stepIndex++
|
|
161
|
+
continue
|
|
162
|
+
}
|
|
163
|
+
this.context.hasStopped = true
|
|
164
|
+
break
|
|
165
|
+
}
|
|
166
|
+
this.isComplete = true
|
|
167
|
+
// TODO: update current plugin version
|
|
168
|
+
|
|
169
|
+
const result = this.context
|
|
170
|
+
this.context = null
|
|
171
|
+
Task.stackDown()
|
|
172
|
+
Task.isRunning = false
|
|
173
|
+
return result
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
async isApplicable ({ journal }) {
|
|
177
|
+
Task.isRunning = true
|
|
178
|
+
Task.stackUp(this)
|
|
179
|
+
this.context = new TaskContext({
|
|
180
|
+
fromPlugins: journal.subject.fromPlugins,
|
|
181
|
+
originalFromPlugins: journal.subject.originalFromPlugins,
|
|
182
|
+
toPlugins: journal.subject.toPlugins,
|
|
183
|
+
content: journal.subject.content,
|
|
184
|
+
journal
|
|
185
|
+
})
|
|
186
|
+
let shouldRun = true
|
|
187
|
+
const wheres = this.getImmediateNextStepsOfType(0, 'where')
|
|
188
|
+
|
|
189
|
+
for (const where of wheres) {
|
|
190
|
+
this.isRunning = true
|
|
191
|
+
const result = await where(this.context)
|
|
192
|
+
this.isRunning = false
|
|
193
|
+
if (result) continue
|
|
194
|
+
shouldRun = false
|
|
195
|
+
break
|
|
196
|
+
}
|
|
197
|
+
this.context = null
|
|
198
|
+
Task.isRunning = false
|
|
199
|
+
Task.stackDown()
|
|
200
|
+
return shouldRun
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
get isComplete () {
|
|
204
|
+
return this._isComplete ?? false
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
set isComplete (value) {
|
|
208
|
+
this._isComplete = value
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
static get isRunning () {
|
|
212
|
+
return this._isRunning ?? false
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
static set isRunning (value) {
|
|
216
|
+
this._isRunning = value
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
static get mapCacheToSource () {
|
|
220
|
+
return (this._mapCacheToSource = this._mapCacheToSource || {})
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** @returns {[Task]} */
|
|
224
|
+
static get described () {
|
|
225
|
+
return (this._described = this._described || [])
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/** @returns {[Task]} */
|
|
229
|
+
static get items () {
|
|
230
|
+
return (this._items = this._items || [])
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** @returns {[Task]} */
|
|
234
|
+
static get stack () {
|
|
235
|
+
return (this._stack = this._stack || [])
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** @returns {Task} */
|
|
239
|
+
static get current () {
|
|
240
|
+
return this.stack[this.stack.length - 1]
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
static get currentFile () {
|
|
244
|
+
return this._currentFile
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
static set currentFile (filePath) {
|
|
248
|
+
this._currentFile = filePath
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
static get clonedItems () {
|
|
252
|
+
return this.items.map(task => task.clone())
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* @param {Task} task
|
|
257
|
+
*/
|
|
258
|
+
static stackUp (task) {
|
|
259
|
+
this.stack.push(task)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
static stackDown () {
|
|
263
|
+
this.stack.pop()
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
static async load ({
|
|
267
|
+
cwd = process.cwd(),
|
|
268
|
+
scripts,
|
|
269
|
+
cachePath = path.join(cwd, 'migrations/cache'),
|
|
270
|
+
logger
|
|
271
|
+
}) {
|
|
272
|
+
logger.info(`Task -- using cache path ${cachePath}`)
|
|
273
|
+
if (!fs.existsSync(cachePath)) fs.mkdirSync(cachePath)
|
|
274
|
+
const toDelete = await new Promise(resolve => {
|
|
275
|
+
globs([
|
|
276
|
+
'*.js'
|
|
277
|
+
], { cwd: cachePath, absolute: true }, (err, files) => resolve(err ? null : files))
|
|
278
|
+
})
|
|
279
|
+
toDelete.forEach(filePath => fs.rmSync(filePath))
|
|
280
|
+
let i = 0
|
|
281
|
+
for (const filePath of scripts) {
|
|
282
|
+
let fileContents = fs.readFileSync(filePath, 'utf8')
|
|
283
|
+
const cachedPath = path.join(cachePath, `a${++i}.js`).replace(/\\/g, '/')
|
|
284
|
+
Task.mapCacheToSource[cachedPath] = filePath.replace(/\\/g, '/')
|
|
285
|
+
const replacements = ['@@CURRENT_VERSION', '@@RELEASE_VERSION']
|
|
286
|
+
const shouldReplaceVersions = replacements.some(item => fileContents.includes(item))
|
|
287
|
+
if (shouldReplaceVersions) {
|
|
288
|
+
const packageJsonPath = await pkgUp({ cwd: filePath })
|
|
289
|
+
if (!packageJsonPath) return logger.error(`Task -- Unable to find package.json for ${filePath}`)
|
|
290
|
+
const packageJson = await fs.readJson(packageJsonPath)
|
|
291
|
+
const currentVersion = packageJson.version
|
|
292
|
+
const releaseVersion = semver.inc(currentVersion, 'patch')
|
|
293
|
+
fileContents = fileContents
|
|
294
|
+
.replace(/@@CURRENT_VERSION/g, currentVersion)
|
|
295
|
+
.replace(/@@RELEASE_VERSION/g, releaseVersion)
|
|
296
|
+
logger.info(`Task -- ${filePath} @@CURRENT_VERSION/@@RELEASE_VERSION replaced with ${currentVersion}/${releaseVersion}`)
|
|
297
|
+
}
|
|
298
|
+
fs.writeFileSync(cachedPath, fileContents, 'utf8')
|
|
299
|
+
}
|
|
300
|
+
fs.writeJsonSync(path.join(cachePath, 'package.json'), {
|
|
301
|
+
name: 'migrations',
|
|
302
|
+
type: 'module'
|
|
303
|
+
})
|
|
304
|
+
await new Promise(resolve => exec('npm install', { cwd: cachePath }, resolve))
|
|
305
|
+
const modules = await new Promise(resolve => {
|
|
306
|
+
globs([
|
|
307
|
+
'*.js'
|
|
308
|
+
], { cwd: cachePath, absolute: true }, (err, files) => resolve(err ? null : files))
|
|
309
|
+
})
|
|
310
|
+
for (const filePath of modules) {
|
|
311
|
+
Task.currentFile = filePath
|
|
312
|
+
try {
|
|
313
|
+
await import('file://' + filePath.replace(/\\/g, '/'))
|
|
314
|
+
for (const task of Task.described) {
|
|
315
|
+
Task.items.push(task)
|
|
316
|
+
Task.stackUp(task)
|
|
317
|
+
await task.load()
|
|
318
|
+
Task.stackDown()
|
|
319
|
+
}
|
|
320
|
+
} catch (error) {
|
|
321
|
+
logger.error(`Task -- ${error}`)
|
|
322
|
+
error.stack = Object.entries(Task.mapCacheToSource).reduce((stack, [cache, source]) => {
|
|
323
|
+
return stack.replaceAll(cache, source)
|
|
324
|
+
}, error.stack)
|
|
325
|
+
throw error
|
|
326
|
+
}
|
|
327
|
+
Task.described.length = 0
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
static async runApplicable ({ cwd = process.cwd(), journal, logger }) {
|
|
332
|
+
// TODO: don't output task description for search
|
|
333
|
+
const clonedTasks = Task.clonedItems
|
|
334
|
+
while (true) {
|
|
335
|
+
const toRun = []
|
|
336
|
+
logger.debug('Task -- Checking for applicable tasks')
|
|
337
|
+
for (const task of clonedTasks.filter(item => !item.isComplete)) {
|
|
338
|
+
const isApplicable = await task.isApplicable({ cwd, journal, logger })
|
|
339
|
+
if (isApplicable) toRun.push(task)
|
|
340
|
+
}
|
|
341
|
+
logger.debug(`Task -- ${toRun.length} tasks applicable`)
|
|
342
|
+
const isExhausted = (!toRun.length)
|
|
343
|
+
if (isExhausted) break
|
|
344
|
+
logger.debug('Task -- Running applicable tasks')
|
|
345
|
+
// TODO: output task description only on run
|
|
346
|
+
const lastJournalEntryIndex = journal.lastEntryIndex
|
|
347
|
+
for (const task of toRun) {
|
|
348
|
+
const { hasErrored } = await task.run({ cwd, journal, logger })
|
|
349
|
+
if (hasErrored) {
|
|
350
|
+
journal.undoToIndex(lastJournalEntryIndex)
|
|
351
|
+
break
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
logger.debug('Task -- Applicable tasks finished')
|
|
355
|
+
const hasChanged = (lastJournalEntryIndex !== journal.lastEntryIndex)
|
|
356
|
+
if (!hasChanged) break
|
|
357
|
+
}
|
|
358
|
+
prettyPrintJournal(journal, logger)
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
static async runTests ({ cwd = process.cwd(), logger }) {
|
|
362
|
+
for (const task of Task.clonedItems) {
|
|
363
|
+
logger.info(`Testing -- ${task.description}`)
|
|
364
|
+
for (const test of task.tests) {
|
|
365
|
+
const {
|
|
366
|
+
// description,
|
|
367
|
+
shouldRun,
|
|
368
|
+
shouldStop,
|
|
369
|
+
shouldError,
|
|
370
|
+
fromPlugins = [],
|
|
371
|
+
originalFromPlugins = [],
|
|
372
|
+
toPlugins = [],
|
|
373
|
+
content = []
|
|
374
|
+
} = test()
|
|
375
|
+
const journal = new Journal({
|
|
376
|
+
logger,
|
|
377
|
+
data: {
|
|
378
|
+
content,
|
|
379
|
+
fromPlugins,
|
|
380
|
+
originalFromPlugins,
|
|
381
|
+
toPlugins
|
|
382
|
+
}
|
|
383
|
+
})
|
|
384
|
+
const {
|
|
385
|
+
hasErrored,
|
|
386
|
+
hasStopped,
|
|
387
|
+
hasRun
|
|
388
|
+
} = await task.run({ cwd, journal, logger })
|
|
389
|
+
const isPassed = (shouldError && hasErrored) ||
|
|
390
|
+
(shouldStop && hasStopped && !hasErrored) ||
|
|
391
|
+
(shouldRun && hasRun && !hasErrored && !hasStopped) ||
|
|
392
|
+
(shouldRun === false && hasRun === false)
|
|
393
|
+
if (!isPassed) {
|
|
394
|
+
logger.info(chalk.red('> Failed'))
|
|
395
|
+
} else {
|
|
396
|
+
logger.info(chalk.greenBright('> Passed'))
|
|
397
|
+
}
|
|
398
|
+
prettyPrintJournal(journal, logger)
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|